I create super simple angular app like the following
<html ng-app>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.1/angular.min.js"></script>
<body>{{"hello"}}</body>
</html>
I found that the $rootScope has one $watcher for the expression {{"hello"}}, it would be nice that angularjs will be smart enough to find that the expression is a constant, so there is no need to watch it again. This feature (if supported) can be useful sometime such as {{ "" | toRemdomNumber }}, {{ "key" | getResourceByKey }}. This save some memory consumption and computation when scope is in digest.
Is this possible?
I know creating a directive such as bindonce is super simple as well, what I want is that angularjs core / $interpolate service should be smart enough the parse the expression, so that unncessary $watcher will not be created.
I'm new to Angular my self, but I found this directive called bindonce on github. https://github.com/Pasvaz/bindonce It will show you how you can bind constants once. (It gets rid of their watchers after it first binds.) It even has support for filters, and it eliminates unnecessary watches.
Here is an example of bindonce used with a filter.
<div bindonce="Person">
<span bo-bind="Person.bill | currency:'USD$'"></span>
</div>
Here's an article on how to unbind the watcher yourself if you want to try that. I just skimmed over it so far. Like I said I'm kind of new so I don't understand all of it. http://www.bennadel.com/blog/2480-Unbinding-watch-Listeners-In-AngularJS.htm
Related
I am trying to understand how angular 1 digest cycles work and how they impact the existing scope. I have 2 controllers one of them is using angular material with a repeater. The second controller is a simple button click event. Both events print to the console to see what is happening.
What i am seeing is that every time i click the button on the second controller the repeater re-runs its entire calculation?
Is this how angular is intended to work? Please see attached the following codepen - when the button is clicked the repeater re-runs on the first controller every single time. I assume this is going to happen every single time any operations occurs on any controller - which just seems like madness.
the repeater code is as follows:
<div flex="50" ng-repeat="item in items">
<md-checkbox ng-checked="exists(item, selected)" ng-click="toggle(item, selected)">
{{ item }} <span ng-if="exists(item, selected)">selected</span>
</md-checkbox>
</div>
At first i thought there was something wrong in my angular but it seems like this happens anywhere full codepen bellow.
Codepen Example
If you don't want ng-repeat to rerun on change then use "track by $index" in ng-repeat
yes this is exactly how it is supposed to work. That is the nature of two-way binding, you constantly check whether one of both values changed.
If you want to turn off that feature and use a one-time binding you can use the :: syntax.
see in the documentation: https://docs.angularjs.org/guide/expression (you need to scroll down to One-time binding. Sadly there are no anchors :D)
I'm having trouble using one way binding in directives with an isolate scope.
If I use an equal sign for two-way binding, and use the data like so: {{d.name}}, it works.
If I use an # sign, it doesn't work. If I use an equal sign and use the data like so: {{::d.name}}, it fails also.
You can see my full example at this plunker: http://plnkr.co/edit/8bUl8pZSV8Ryru6GDq2M?p=preview
Can someone please help me understand what's happening here? Thanks.
The one-way binding syntax you are trying to use, has been introduced since Angular 1.3.
In your demo you are using version 1.2.25.
You must change the script link:
<script data-require="angular.js#1.3.x" src="https://code.angularjs.org/1.3.0/angular.js" data-semver="1.2.25"></script>
The problem with the second directive, instead, is that the # is not a one-way binding, it simply takes the attribute as text.
To use it like you would, so you need to interpolate the text before passing it to the directive, like this
<h3>Directive 2</h3>
<p ng-repeat="d in data">
<dir2 d="{{d.name}}"></dir2>
</p>
DEMO
I'm using twitter bootstrap with a popover and got a AngularJS scoped variable to appear correctly. The below works.
(data-content="{{notifications[0].user}} shared {{notifications[0].user_two}}'s records")
When I add the following
(data-content="<b>{{notifications[0].user}} shared {{notifications[0].user_two}}'s records</b>")
No errors show up, but all of the {{}} no longer render.
So I tried this as a test of sorts
(data-content="<div ng-repeat='item in notifications'>test {{item}} <br/><hr/></div>")
Much like the last example, I see the "test" but not the {{item}}. And the "test" only show s up once, even though the notifications had three elements. When I look at the DOM there's this
<div class="popover-content">
<div ng-repeat="item in notifications">you <br><hr></div>
</div>
I've also tried just creating a directive to iterate through the array and make the output I want, but my attempt to set data-content equal to a directive have been failures. The examples I've found elsewhere I'm confident would work, but I just wanted to confirm before I begin implementing something like this (http://tech.pro/tutorial/1360/bootstrap-popover-using-angularjs-compile-service) or (Html file as content in Bootstrap popover in AngularJS directive) that I'm not missing a straightforward fix to the problem I outlined above that would not require me creating a directive.
Edit:
Plunkr Url http://plnkr.co/edit/VZwax4X6WUxSpUTYUqIA?p=preview
html might be breaking it, try marking it as trusted html using $sce
How do you use $sce.trustAsHtml(string) to replicate ng-bind-html-unsafe in Angular 1.2+
$scope.html = '<ul><li>render me please</li></ul>';
$scope.trustedHtml = $sce.trustAsHtml($scope.html);
<button ... data-content="trustedHtml" ...> </button>
I was faced the performance issue of ng-repeat directive, I rendered the PDF formFields using ng-repeat directive, somehow it halts my browser. But when I use track by $index and limitTo:1 together in same ng-repeat, it works fine and it enhances the rendering speed. I can't understand the logic behind this but it works extraordinary fast :)
This works faster and fine for me, also limitTo:1 not work, some how it is binding the limit with $index and halting of browser issue fixed.
<div ng-repeat="friend in friends track by $index | limitTo:1">
{{ friend.id }} — {{ friend.name }}
</div>
if we use limitTo before track by $index than it behaves normally the limit behavior of angular js which is understandable
<div ng-repeat="friend in friends | limitTo:1 track by $index">
{{ friend.id }} — {{ friend.name }}
</div>
OR
<div ng-repeat="friend in friends | limitTo:1">
{{ friend.id }} — {{ friend.name }}
</div>
Although i achieve my performance goal, but i want to know the logic behind this.
Here is the link of jsfiddle
http://jsfiddle.net/neglingeyes/G6q84/
You can not measure multiple ng-repeat directives at once with post-repeat.
This is because the way it tries to figure out when the rendering is complete is to set a timeout function for the next event loop tick, and that really means all the directives on the page have finished rendering, not just this specific ng-repeat.
In your demo fiddle, I guess each next post-repeat timeout gets processed in a separate event loop tick or something like that, and this is why their "measured" performance seems to get worse and worse. If you changed their order, again the first will seem to be the fastest. But only by a couple of ms - a trivial difference.
Have you tried to benchmark each case separately? Also, on what platform and with what data? On desktop browsers and with such short data it is too fast to make a difference either way.
As to what the first code segment does - it is parsed as friend in friends track by ($index | limitTo:1) ("What brackets?" ;-) )
The limitTo filter can only be applied to arrays, not to scalar variables like the number $index. But the angular filters normally return their input unchanged if they can not make sense of it, so I guess that is what happens here too.
Here is an explanation:
by default ng-repeat creates a dom node for each item and destroys that dom node when the item is removed; As it watches the ng-repeat object, it expects the object to change & implement the change & hence keep adding or deleting nodes. But using $index it reuses DOM nodes.
Here is the link where I picked up this information- http://www.reddit.com/r/angularjs/comments/2cvo16/speeding_up_angularjs_with_simple_optimizations/
So here is my question:
I have the following:
<li bindonce ng-repeat="value in Types" ng-include="'views/repeaters/types.html'"></li>
and I was wondering if this is the correct way to use the bindonce so that ng-repeat will not have a $watch? Should I also put it before the ng-include as well as so:
<li bindonce ng-repeat="value in Types" bindonce ng-include="'views/repeaters/types.html'"></li>
This way, the ng-include will not have a $watch created for it.
How about using bindonce for ng-class, ng-click - is it possible to do bo-click, and bo-class ? Thanks!
Regarding bo-click, I don't think it's possible, yet. But you can use bo-class if you need it. You can have a look at the full list of available directives within bindonce here.
Also, bindonce is the main directive. That means you just have to use it once and inside the wrapper/root element, you use the bo-* directives according to your needs.
Finally, there is no way currently to remove the watcher on ng-repeat. And if bindonce was in fact able to it, you would have to use something called bo-repeat or so. It's actually the same for all the directive brought by bindonce. You generally have to replace you ng-* directives with bo-* equivalent directives.