4
votes

I have a directive that builds a set of nested <ul> elements representing a folder structure. I used the link function to create the new DOM elements and append them to the directive instance element:

function link(scope, iElement, iAttr) {
  var rootElement = buildChildElement(scope.tree);
  iElement.append(rootElement);
}

Elements within the <ul> tree are wired with jQueryUI's drag/drop interactions that call a function on the Controller housing the directive to update the scope parameter based on the drag & drop events.

I would like the <ul> tree to automatically update when there is a change to the scope parameter. I have tried a watch function within my link function:

scope.$watch('tree', function(newTree, oldTree) {
  var newRoot = buildChildElement(newTree);
  iElement.contents().remove();
  iElement.append(newRoot);
}

This works to a certain extent, but the call to remove() fires off the $watch() method a second time which ends up reverting my Controller changes. If I comment out the remove(), I can see that a new <ul> tree is written that properly reflects the changes to the parameter made in the Controller.

The double firing $watch() makes me think I'm going about this wrong. Without it, my parameter is properly updating but my <ul> doesn't update (the dropped element stays where it was dropped).

What's the correct way to make sure your directive is refreshed on a change in one of the scope parameters?

Should I be using the compile function and building the <ul> tree based on the attributes array instead of using the link function?

2

2 Answers

0
votes

Your approach is very jQuery-style. I think you'll find that you're working against Angular in this case. sh0ber is right with his/her question; you should post a demo or something, or at least some sample code so you can have an effective answer.

I think you want to make a recursive tree directive. Check out this SO answer for some interesting approaches to this. The main idea is that watch is unnecessary. Simply change the object and Angular will take care of the rest. The most efficient thing is to change the specific node objects directly rather than replacing the whole object, but that will work too.

0
votes
scope.$watch('tree', function(newTree, oldTree) {
  var newRoot = buildChildElement(newTree);
  iElement.contents().remove();
  iElement.append(newRoot);
},**true**)

I think you can have a try and reference the watch API for more information Here is another artical http://www.bennadel.com/blog/2566-scope-watch-vs-watchcollection-in-angularjs.htm