Is there an easy way to remove the contents of a div in Angular,
I have <div class="row"> inside of which I have an ng-repeat that generates several widgets. Now if an action takes place from the parent scope I need to empty that div and call the function that does the ng-repeat again.
Without code it's kind of hard to answer this, but if the ng-repeat is only thing in your div, if you update the array/object bound to the ng-repeat it will automatically update the contents of the div because the ng-repeat will re-evaluate. You don't have to clear it out. Now, if you have other content in the div, this solution won't work.
Angular watches the variables on its own and adds / deletes / updates the ng-repeat on it's own when the array it lists gets updated.
So there is no need to delete it all first, you can just update the object / widget you'd like OR replace the contents of the array it lists with a new array.
May be you are updating data outside of AngularJS.
You can try scope.$apply or an easier way is to wrap the function in an $timeout without delay:
$timeout(function(){ // Update your data });
Related
I'm trying to reuse a template directive in a ng-repeat loop. I'm passing down to the directive an id which is then used in the template as following:
<g id="scaling{{id}}">\
...
</g>
This works perfectly, it gets rendered properly in the final html page. Now the thing is that I'm trying to select the element above with the dynamically set unique id in the link function of the directive as following in order to set some style attributes:
d3.select('#scaling' + scope.id}.
However this always returns null. From what I've understood by searching around, this happens because the element is not in the DOM yet when I make this query. How can I work around this? Thank you very much in advance!
So I found the solution myself. You can add the DOM selection query in a $timeout function, which will only get called after the DOM is rendered.
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?
What I want to do is push an object to an array which have angularjs binding to html, then do a click function on the new created element.
the code is like this
$scope.fruits = {"orange", "plum", "cherry"};
$scope.add = function() {
$scope.fruits.push("apple");
//this would add an element to the html, then I want to click on the element
$('#fruits').children.eq(-1).click();//click the last element (which has just been created)
}
the html is like:
<div id="fruits">
<div ng-repeat="fruit in fruits"></div>
</div>
The problem is, when an object is pushed to the model, angular would do something like $scope.$apply() to dynamically update the html.
If I click the last element with .children().eq(-1).click(), it won't wait after the new element been created, what it actually clicks is the "cherry" div.
I tried to call $scope.$apply() before click(), it works, but I got this error message:
$apply already in progress
which I believe is not a good practise, and $apply() should not be called in this way.
When you add to the $scope you are inside a digest loop and the DOM won't be compiled and refreshed until those loops complete - basically in your $scope push you are changing the array but at that moment the rendered DOM still has the previous items. Once it exits the loop, the watchers from the repeater will fire and render the new DOM element, but you've already left your controller.
The solution is really simple. You just need to queue your update for the moment the current digest loop ends. You can do that using setTimeout with no delay. this will put your function on the queue and call it when the current processing is done:
setTimeout(function() {
$('#fruits').children().eq(-1).click();
}, 0);
Here is a working fiddle: http://jsfiddle.net/jeremylikness/bWeQL/
(I strongly encourage you to consider writing a directive for this to avoid manipulating the DOM directly from within your controller).
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.
(Note that you don't need to know about datatables for this one..)
I'm creating a directive to handle DataTables. What I'd like to do is have an actions column with two icons - edit and delete. Those icons should response to an ng-click.
Datatables allow you do this by providing a callback for a given column defintion (mRender). This callback returns an html string for that cell value, which is inserted into the DOM instead of the actual cell value.
Checkout this plunker. The two important functions are highlighted:
renderActionIcon - my implementation of the callback mentioned above. It generates the HTML string that I'd like in the cell.
registerNewHtmlWithAngular - function where I ostensibly let angular know about the ng-clicks that I need to register for that column.
What should go in registerNewHtmlWithAngular?
If $compile the html, angular adds the appropriate click event listeners and gives me back an element, but since the Datatables function expects HTML, those registered elements will not be added to the DOM.
Any ideas? Thanks folks!
After a day of keyboard banging:
There does not seem to be a way to $compile into html and have it be usable in the DOM. It has to be an element that's inserted into the DOM, so that event listeners are not lost.
The way I solved the problem in this particular scenario is to just insert the HTML, and run $compile on the new HTML later.
Datatables makes this easy with the fnCreatedRow callback, which, after a row is rendered, passes back a row's Element and lets you do whatever you want with it. In this case I ran $compile over the row and returned it back to Datatables. See the rowCompiler function in the updated plunker.
Because datatables uses innerHTML = mRender(...) to insert an html (so it anyway will convert anything to string and you will lose the results of $compile function. I guess there is no way to do it with mRender without hacks - for instance it is possible to slightly change datatables so it will use $.append instead of innerHTML. But this is not a good practice so in our project we use usual jquery bindings instead of ng-click.