I'm trying to integrate Gridster with AngularJS, but without too much success yet.
Reading the documentation on Angular UI's ui-jq
directive, I get the impression that this (check fiddle) should work. But when I look a bit further with Chrome's debugger, it turns out that on this line, it doesn't find any children at all.
I suspect that somewhere in the ng-repeat directive, AngularJS decides to rip out the part that will be repeated, and I see why, but that doesn't solve my problem. I'd welcome any clue that would help me to get a little further.
Update 1
I started turning it into a directive, hoping that would improve things. However, the nested ng-repeat
is also getting in the way in case of a homegrown directive. I tried postponing hooking up the jQuery plugin as long as I could ($evalAsync
) and alike, and eventually ended up using a $timeout
. That's the only way in which I could get it working.
Update 2
I think the original approach would have never given me what I needed. So implemented a custom directive. See my answer below.
I eventually ended up writing my own directives for it. I needed to be sure that every change to the underlying data would be seen by gridster, but at the same time, I didn't want to write my own monitoring on the data model and replace everything you normally do within gridster with a directive that hides all of that. (It would involve implementing most of ng-repeat within the directive itself.)
This is what I have (and assume "foo" to be the name of my module):
foo.directive "gridster", () -> { restrict: "E" template: '<div class="gridster"><div ng-transclude/></div>' transclude: true replace: true controller: () -> gr = null return { init: (elem) -> ul = elem.find("ul") gr = ul.gridster().data('gridster') return addItem: (elm) -> gr.add_widget elm return removeItem: (elm) -> gr.remove_widget elm return } link: (scope, elem, attrs, controller) -> controller.init elem } foo.directive "gridsterItem", () -> { restrict: "A" require: "^gridster" link: (scope, elm, attrs, controller) -> controller.addItem elm elm.bind "$destroy", () -> controller.removeItem elm return }
With this, I can have a gridster generated view, by adding this:
<gridster> <ul> <li ... ng-repeat="item in ..." gridster-item> <!-- Have something here for displaying that item. --> <!-- In my case, I'm switching here based on some item properties. --> </li> </ul> </gridster>
Whenever items are added to or removed from the collection observed by the ng-repeat directive, they will be automatically added and removed from gridster controlled view.
EDIT
Here is a plunk demonstrating a slightly modified version of this directive:
angular.module('ngGridster', []); angular.module('ngGridster').directive('gridster', [ function () { return { restrict: 'E', template: '<div class="gridster"><div ng-transclude/></div>', transclude: true, replace: true, controller: function () { gr = null; return { init: function (elem, options) { ul = $(elem); gr = ul.gridster(angular.extend({ widget_selector: 'gridster-item' }, options)).data('gridster'); }, addItem: function (elm) { gr.add_widget(elm); }, removeItem: function (elm) { gr.remove_widget(elm); } }; }, link: function (scope, elem, attrs, controller) { var options = scope.$eval(attrs.options); controller.init(elem, options); } }; } ]); angular.module('ngGridster').directive('gridsterItem', [ function () { return { restrict: 'EA', require: '^gridster', link: function (scope, elm, attrs, controller) { controller.addItem(elm); elm.bind('$destroy', function () { controller.removeItem(elm); }); } }; } ]);
If you want you can try and roll your own wrapper for gridster. I spent most of the night last night and it was a little glitchy. The way gridster handles serialization isn't straightforward, etc. Anyway I stumbled on this project and it works really well.
https://github.com/ManifestWebDesign/angular-gridster
I couldn't find an online demo so I made a plunk of it:
http://plnkr.co/edit/r5cSY1USjtr2bSs7rvlC?p=preview
This will be fixed in the next release of
https://github.com/angular-ui/angular-ui/pull/347
The new deferred attribute will take care of the problem as soon as I can figure out why the stupid unit tests won't pass.
There's also Angular Gridster.
Came across it and this question while researching Gridster implementation in Angular.