I searched for an considerable amount of time now but i still can't find a solution to my problem. I don't know anything about packery but i found this code which works perfectly and does what i wanted to do.
directive('workspace', ['$rootScope', function($rootScope) {
return {
constrain: 'A',
link: function(scope, element, attrs) {
element.ready(function() {
var packery = new Packery(element[0], {
rowHeight: '.module-sizer',
itemSelector: '.module',
columnWidth: '.module-sizer'
});
angular.forEach(packery.getItemElements(), function(item) {
var draggable = new Draggabilly(item);
packery.bindDraggabillyEvents(draggable);
});
packery.layout();
});
} }; }]).
So it was working perfectly when i had an array of widgets where i was not adding or removing an element but simply using ng-show to hide/show them. Now I no longer want to use ng-show, instead i am adding and deleting my widgets from an initial empty array
.controller('WidgetCtrl', ['$scope', function ($scope) {
$scope.counter = 0;
$scope.current = 0;
$scope.widgets = [];
$scope.addWidget = function(name){
var widgets = {
widget1: {name: 'widget1', id: ''},
widget2: {name: 'widget2', data: {dataVariable: 'some data'}, id:''}
};
var widget = widgets[name];
if (widget) {
$scope.widgets.push(widget);
$scope.widgets[$scope.current].id = $scope.widgets.length-1;
console.log('index of the last widget added: ' + $scope.widgets[$scope.current].id);
$scope.current++;}
So the only widgets that can be dragged are those who are initially in the array. Any widgets i add after the page has loaded will not work. I am new in angular and i was reading on $scope.apply and recompile a directive but i am not sure if its related to my problem
<div class="module-container" workspace>
<div class="module-sizer"></div>
<div class="gutter-sizer"></div>
<div class="module" ng-repeat='widget in widgets'>
<div dynamic-widget='widget.name' data='widget.data'> </div>
</div>
</div>
The issue here is to do with the fact packery binds events to grid items in order to perform layout and to make them 'draggable', here's the snippet responsible for that:
angular.forEach(packery.getItemElements(), function(item) {
var draggable = new Draggabilly(item);
packery.bindDraggabillyEvents(draggable);
});
So what's happening presently with the way your directive is set up is that when the template containing the directive initially loads, it's picking up any matching items .module
and initialising packery & draggabilly with the above code and pckry.layout();
, from that point onwards there's no way of your app knowing that the number of widgets has increased at all.
What you can do to make sure they're initialised when added is to pass the scope into the directive, as follows:
constrain: 'A',
scope: true,
link: // ...
And then you'll want to add a $scope.$watchCollection
to the array widgets
like so:
$scope.$watchCollection('widgets', function() {
// Call packery and draggabilly on elems here
});
I guess you'll want to move the logic for initialising packery into a separate function for better code separation, though be aware that the $watchCollection
will fire the first time the directive runs anyway so all the logic could just be inside there.
One final thing to note is that you may need to call pckry.destroy();
beforehand to ensure the desired result. Unfortunately I don't have enough time to make an example so this really is just a thought experiment, but I hope it helps!