Reputation: 1806
What I am trying to achieve: trigger an angular js directive on a jquery ui event which in turn calls a method in the controller, which adds a value in an array which should appear in the view because of the two way data binding.
What does not work: the value is properly added in the array but the view is not updated
HTML
<li id="collection_{{$index+1}}" class="collection" ng-repeat="collection in column | filter:avoidUndefined" ng-controller="collectionController" ng-model="collection">
<h1 class="collection-title"> {{ collection.title }}</h1>
<ul class="bookmarks sortable droppable" droppable=".draggable" sortable=".bookmarks.sortable">
<li class="bookmark" ng-repeat="bookmark in collection.bookmarks">
<a class="bookmark-link bookmark-{{bookmark.id}}" href="{{bookmark.url}}">{{bookmark.title}}</a>
</li>
</ul>
</li>
DIRECTIVE
directives.directive('droppable',function(){
return {
link:function(scope,el,attrs){
el.droppable({
accept: attrs.droppable,
drop: function( event, ui ) {
var url = $(ui.helper).text();
scope.addBookmark(null, url, url);
$(this).removeClass('ui-state-highlight');
},
...
CONTROLLER
$scope.addBookmark = function (id, title, url){
if (id == null) {
...
}
var bookmark = {
'id': id,
'title': title,
'url': url,
'type': 'bookmark'
};
$scope.collection.bookmarks.push(bookmark);
};
$scope.collection.bookmarks
is updated properly but the view stays the same. If I call the same addBookmark
function directly with a normal button it works.
Upvotes: 0
Views: 1709
Reputation: 20014
My recommendation is to use $emit
instead of calling a method of the controller directly in your directive.
Directives should be always independent components, if inside the directive there is a call to a method from a controller(outside the directive) this will create a dependency between my directive and the controller and of course this will force one not being able to exist without the other.
If I would have to apply a design principle to a directive it will be the S in SOLID, Single responsibility principle. Directives should be able to encapsulate and work independently.
I would probably try this on my directive: scope.$emit("UrlChanged", url);
Something like this:
directives.directive('droppable',function(){
return {
link:function(scope,el,attrs){
el.droppable({
accept: attrs.droppable,
drop: function( event, ui ) {
var url = $(ui.helper).text();
scope.$emit("UrlChanged", url);
$(this).removeClass('ui-state-highlight');
},
On my controller:
$scope.$on("UrlChanged", function(event, url){
... //your has changed.
});
Upvotes: 0
Reputation: 1000
You forgot to wrap your drop-callback in $apply
:
directives.directive('droppable',function(){
return {
link:function(scope,el,attrs){
el.droppable({
accept: attrs.droppable,
drop: function( event, ui ) {
scope.$apply(function(scope){
var url = $(ui.helper).text();
scope.addBookmark(null, url, url);
$(this).removeClass('ui-state-highlight');
});
},
...
Upvotes: 1