Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular directive not being re-called with ng-repeat

I have a directive ct-steps-tooltip on an element along with ng-repeat like so:

<div id='courseSteps' 
     class='relative ease {{step.action.toLowerCase()}}' 

     ng-repeat='step in currentItem.userData.steps | filter:{action: filterSteps} track by $index' 
     ng-class='{"completed": step.endDate, "pointer": step.action==="Submit" && !step.endDate}' 
     ng-click='getRelated(step, $index)'

     ct-steps-tooltip 
     ct-step-name="step.stepName" 
     ct-step-description="step.description" 
     ct-action="step.action" 
     ct-value-text="step.valueText" 
     ct-quantity='steps.length' 
     ct-completed='currentItem.steps.completedSteps' 
     ct-start-date='step.startDate' 
     ct-end-date='step.endDate'>

    <div ng-show='step.endDate' class="stepCompleteCheck absolute"></div>
    <div> {{ step.stepName }} </div>
</div>

My goal was to get the directive to re-bind/get called again whenever currentItem.userData.steps changed (I am actually completely clearing currentItem and then reassigning it). This actually works great in this simplified fiddle I made. In the fiddle you can clearly see "I got called!" in the console every time the data is changed. For some reason, the ct-steps-tooltip directive in the real code only gets called the first time, and doesn't get called again when the data changes (I have a similar "I got called" message in the real directive's link function). What am I doing in the real code that has broken this functionality?

EDIT: Noticing that OCCASIONALLY the directive IS called again on data change. Its happening like 10% of the time. My question is now seeming similar to this one.

like image 431
Rob Allsopp Avatar asked Jul 02 '14 20:07

Rob Allsopp


1 Answers

The data is not refreshing because in your ngRepeat expression, you specify track by $index.

When currentItem is updated, the indices of objects in your steps array remain the same even if the actual objects are different.

Therefore angular does not update the repeater because the $index has not changed and we are tracking the step objects by this $index variable. Remove the track by part of the repeater expression and your problem will be solved.

track by is really only useful when you are adding and removing objects to/from an array in the repeater, not when you are changing the entire array. For example, if you have a list of 100 books and you add one to this array (without track by), the entire array of 101 books would be re-rendered. You could use track by book.id to tell angular that the original 100 books in the repeater have not changed and to only render dom for the single book we are adding.

like image 166
Evan Drewry Avatar answered Oct 21 '22 18:10

Evan Drewry