I'm working with Framework7 (http://framework7.io/) and with Angular.
In my case, I have a sortable list (from F7) filled with an ng-repeat directive.
My problem is when I update my list (LI elements), the $scope array does not change its order.
What I expect is that when I make changes on the list, the $scope array which filled the list, also changes the order of its elements.
How I can obtain the expected behaviour?
I think that with JS/jQuery I can find a workaround, but I want to know which could be a correct solution with Angular.
Many thanks!
Related
I am an Angularjs rookie. Recently I am reading guide in Angularjs website and get some confusion.
In angularjs API Document about ngRepeat, it says:
If you are working with objects that have an identifier property, you should track by the identifier instead of the whole object. Should you reload your data later, ngRepeat will not have to rebuild the DOM elements for items it has already rendered, even if the JavaScript objects in the collection have been substituted for new ones. For large collections, this significantly improves rendering performance. If you don't have a unique identifier, track by $index can also provide a performance boost.
I don't understand this content:
Should you reload your data later, ngRepeat will not have to rebuild the DOM elements for items it has already rendered, even if the JavaScript objects in the collection have been substituted for new ones.
What this sentence mean? Can you give me an example?
Thank you very much!
Say you have ng-repeat build two elements like this:
<div></div>
<div></div>
Then you add three more elements to the object to get this:
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
The point is, the first two divs won't be removed from the DOM and then recreated and reinserted, but only the three new ones will be added.
The same goes when if the first two elements of your objects were changed, but the element they're being tracked by remains the same (thus they recommend $index) - the two DOM elements (the divs) would still be intact, just their contents replaced.
Of course, no content in the mini-example I gave you, but you get the point. Think of a track by variable as a "glue" that keeps DOM in place.
ngRepeat behavior changes with and without track by.
When the collection changes:
Without track by:
Angular rebuild the DOM (destroy and create again each DOM element).
With track by:
Angular retrieve the DOM element of each item and update the values.
As the doc said:
For large collections, this significantly improves rendering performance.
That behavior is really well explained in this article.
So I'm trying to build a drag & drop list with ctrl/shift selection in Angular. For some reason, when I attempt to load my template / directive, angular uses the last array loaded at any given point. What I mean by this is, if I load two arrays, each in separate <ul> elements, it will use the second one for both of them. Overall, it's pretty confusing why it happens.
See my fiddle here.
You're initializing the same scope attribute twice:
ng-init="itemList=itemsInTrash"
...
ng-init="itemList=itemsThatAreReal"
So, once the template has been initialized, this itemList variable references the itemsThatAreReal array, and the two included templates thus display this array.
I've created a directive for Angular to know when a ng-repeat is finished. I've found the most common solution is something like is used here - Calling a function when ng-repeat has finished
But, Why the directive is just triggered when an element is added but not when is removed?
Here - ng-repeat list in Angular is not updated when a model element is spliced from the model array I've seen some suggestion about making a $scope.$apply, but is still not working because it says '$apply already in progress'
I've created here - a Plunker where you can reproduce it.
Thanks a lot!!!
The reason why the directive works when adding an item to the collection is that the link function is called when each repeated element is added to the dom. This works great when the collection is rendered for the first time and when an item is added to the end of the collection. It does not work when an item is added elsewhere in the collection e.g. at the beginning, as the link function is called for the new element but $last will be false.
When an item is removed from the collection no directive is created and hence no link function is called.
To get what you want you can create a watch on the collection and perform whatever you want to do in a $timeout so that it's done after the render:
$scope.$watchCollection('ta', function(){
$timeout( function(){
// the collection has rendered so do all my whizzy stuff
});
});
Most likely it is because ng-repeat doesn't iterate over the whole array when an item is spliced. It just removes that item from the array and removes the associated DOM node.
I don't know what exactly you are trying to achieve, but if you need to react to changes in the ng-repeat list, why don't you just $watch the array instead?
I'm building a complex, variable layout with infinite scroll UI in AngularJS.
Think something like Flipboard with a load of repeating data items, each item containing the same thing (title, description, image etc). Each item is pre-loaded into JSON, sorted and then organised into a series of pages, selected from a series of variable layouts. Each page has a variable number columns and each column a variable number of rows.
In order to achieve this, I'm using multiple Directives for each page layout, compiled at run time. Inside each layout Directive, I'm then building a variable number of columns, each of which contains an ng-repeat for the variable number of rows. Each row can be a different Directive, depending on how it needs to be styled. Again, all of this is happening at runtime.
I'm 99% of the way there.
The Directives are being compiled correctly and calling up the correct column Directives, which in turn are compiling the correct number of rows. Once we get to the row/item level, I'm using a Service which brings back the correct Directive for each item. The reason I choose the Service approach is that I want the items to be reused inside other modules.
The problem I'm having, is that once the page layout is compiled, it sets up the columns and then the rows but does not execute the ng-repeat. I need to get the ng-repeat to loop and also call the specific Directives I use for each item.
I think is a problem to do with $compile and what Angular knows about the DOM. Maybe I need to do a $compile or $apply at some stage to get the ng-repeat to kick in and bind the final Directives to the data items.
**
Side note: if I don't use a Service, but simply use define each layout Directive with a templateUri it works perfectly!
I can go with this approach, but ideally, I'd like to get away from downloading a bunch of templates at runtime. Also, by passing parameters into a Service, I can design more layouts, much quicker and easier than having to build individual template files.
I've set up a JS fiddle with quick example of how I'm approaching all of this:
http://jsfiddle.net/joecarney/vE3Ls/6/
Some SO required code just to post this comment:
<div ng-app="app" ng-controller="appPageController">
<div>
<div my-page></div>
</div>
</div>
If you use scope: {} in a directive it creates a new scope so your directives will not have access to controller scope unless you allow it, which you started out doing but appears you then copied and pasted the same thing for all :)
The directive compiling items in ng-repeat had no access to items. I removed scope from directives and used the attrs value to access the attributes
http://jsfiddle.net/vE3Ls/7/
I'm having some AngularJS trouble with firing off a directive when ng-repeat has completed an update. I have three named arrays, switched to via three links, allowing the selected array to be displayed by the ng-repeat. I'd like to fire some code off when it's finished as I'm planning to set some element attributes for D3 to use.
I've tried checking scope.$last in my directive, but this isn't called at the end of every ng-repeat process. If some of the data remains the same, it may not set scope.$last to true.
http://plnkr.co/edit/hwmOlI6YrgS4H1C1h7k2?p=preview
So, what's the best way to trigger code in a directive when ng-repeat has finished?
Here is a solution for you. Note that the last triggers each time now.
http://plnkr.co/edit/xV1quqzorzxliS2shrP4?p=preview
You just need to $watch the $last variable and it will work fine. This helps in situations where the scope is not created but just updated with new values. Your directive gets created once and if one of the repeated variable just changes values ng-repeat optimizes and just updates values ( as opposed to removing all the values and re-creating the new ones. ). In this scenario, the $scope.$last will be an updated variable and not something that gets "created". So, you will need to $watch it.