Application made with RactiveJS, Redux and Gridstack.
When new widgets are added, all is fine and widgets are movable/resizable as well. But when I delete all widgets and add, for example, two new, then:
- widgets can't be moved and can't be resized. As in picture:
- when try to delete widget it disappear, but other widgets change their position.
jsFiddle is provided as follows
You can see that right widget is moved to the right side, but handle stays where it is. So why is such behavior and how to deal with that?
RactiveJS application have three components
DashboardComponent
WidgetGridComponent
WidgetComponent
Code provided as follows:
var Widget = Ractive.extend({
isolated: false, // To pass events to WidgetGrid component (makeWidget, removeWidget, etc.)
template: '#widgetTemplate',
components: {},
oninit: function() {
// Load data to widget
},
oncomplete: function() {
this.drawChart();
},
drawChart: function() {
var self = this;
function exampleData() {
return [{
"label": "One",
"value": 29.765957771107
},
{
"label": "Two",
"value": 0
},
{
"label": "Three",
"value": 32.807804682612
},
{
"label": "Four",
"value": 196.45946739256
},
{
"label": "Five",
"value": 0.19434030906893
},
{
"label": "Six",
"value": 98.079782601442
},
{
"label": "Seven",
"value": 13.925743130903
},
{
"label": "Eight",
"value": 5.1387322875705
}
];
}
nv.addGraph(function() {
var chart = nv.models.pieChart()
.x(function(d) {
return d.label
})
.y(function(d) {
return d.value
})
.showLabels(true);
d3.select("#widget" + self.get("id") + " svg")
.datum(exampleData())
.transition().duration(350)
.call(chart);
return chart;
});
},
data: function() {
return {
id: null,
x: null,
y: null,
width: null,
height: null,
}
}
});
var WidgetGrid = Ractive.extend({
// isolated:false,
// twoway:false,
template: '#widgetGridTemplate',
components: {
Widget: Widget,
},
onrender: function() {
// Init gridstack instance
this.bindGridstack();
},
deleteWidget: function(id) {
Action.deleteWidget(id);
},
removeWidget: function(id) {
$(".grid-stack").data("gridstack").removeWidget("#widget" + id);
},
createWidget: function(id) {
$(".grid-stack").data("gridstack").makeWidget("#widget" + id);
},
updateWidgetSize: function(id, width, height) {
Action.updateWidgetSize(id, width, height);
},
updateWidgetPosition: function(id, x, y) {
Action.updateWidgetPosition(id, x, y);
},
bindGridstack: function() {
var self = this;
var options = {
animate: true,
auto: false, // if false gridstack will not initialize existing items (default: true)
float: true, // enable floating widgets (default: false)
disableOneColumnMode: true,
width: 10, // amount of columns (default: 12)
height: 10, // maximum rows amount. Default is 0 which means no maximum rows
// height: 10,
// cellHeight: 80,
disableResize: false,
disableDrag: false,
verticalMargin: 0,
resizable: {
handles: 'se'
}
};
var grid = $(".grid-stack").gridstack(options);
// On user ends resizing
grid.on('gsresizestop', function(event, elem) {
var $el = $(elem);
var node = $el.data('_gridstack_node');
var id = node.el.attr("id").replace("widget", "");
self.updateWidgetSize(id, node.width, node.height, node.el.css("width"), node.el.css("height"));
});
// On user ends dragging
grid.on('dragstop', function(event, ui) {
var $el = $(event.target);
var node = $el.data('_gridstack_node');
var id = $el.attr("id").replace("ar-widget", "");
self.updateWidgetPosition(id, node.x, node.y);
});
},
data: function() {
return {
widgets: [],
}
}
});
var Dashboard = Ractive.extend({
el: '#dashboard', //document.body,
template: '#dashboardTemplate',
isolated: true,
append: false,
oninit: function() {
this.on("add", function() {
Action.addWidget()
});
},
components: {
WidgetGrid: WidgetGrid,
},
data: function() {
return {
store: {}
}
}
});
There's several problems in there:
detach
is not called when unrendering a component. It's only called whenractive.detach()
is called. Your grid was not aware of the widget's removal. After Ractive unrendered the widget elements, this caused the grid to act weird.On the flip side,
grid.removeWidget()
removes the widget from the DOM. After a state change, Ractive will still try to unrender. But since the element is no longer there and because Ractive wasn't aware of the widget's removal, it will cause a double removal.After a state change, the data for the widget is no longer present.
id
is alreadyundefined
. You can no longer useid
when you handleteardown
,unrender
nordestruct
events. You'll have to disconnect a widget from the grid earlier, preferably before the state change.Ideally, you should just let Ractive do the rendering/unrendering of elements and only inform gridstack about making/disconnecting widgets from the grid. You're already doing this on render by using
makeWidget
instead ofaddWidget
. For removal, you simply need to do the same thing.removeWidget
accepts a second argument which, iffalse
, will disassociate a widget from the grid but not remove the element from the DOM. This leaves unrendering to Ractive after the state change.Here's an example: https://jsfiddle.net/fm133mk6/