ng-repeat execute many times - javascript

I have a little demo on jsfiddle :
HTML:
<input type="checkbox" id="chkUsr{{usr.Id}}" ng-model="usr.Checked">
{{usr.Name}} : {{usr.Checked}}
<input type="text" ng-model="research"/>
<div ng-repeat="entity in entities | filter:research | log">
Hello {{entity.id}}!
JavaScript:
app.filter('log', function() {
return function(items) {
console.log('yo');
return items;
};
});
The log filter is called when input change (even the checkbox).
How to change that and trigger log filter only when text input change ?

That's because angular runs $digest and updates all the scope properties even if one variable in the scope changes. It is called "dirty checking".
Learn more about how angular works: http://www.sitepoint.com/understanding-angulars-apply-digest/

Related

angular js - function firing multiple times with ng-checked inside ng-repeat

I have the following html which has an ng-repeat that generates checkboxes:
<span ng-repeat="name in $ctrl.widgetSelectorNames" class="widget-selectors">
<label class="checkbox" for="{{name}}">
<input type="checkbox" value="{{name}}" ng-model="name" ng-change="$ctrl.toggleVisibility(name)" ng-checked="$ctrl.checkIfHidden(name)"/>
{{name}}
</label>
</span>
what I'm trying to do is have ng-checked=true, if the relevant item has property of hidden as true. I think my logic is correct, but the ng-checked function runs wayy too many times:
let numTimesCalled = 0;
$ctrl.checkIfHidden = function (name){
numTimesCalled++;
console.log(numTimesCalled);
$ctrl.widgets.forEach(widget => {
if (name == widget.name && widget.hidden) {
return true;
}
})
return false;
}
there are six items in $ctrl.widgetSelectorNames yet the function is called 48 times as per the numTimesCalled variable! what's happening? if this isn't the right way to do it, what's a better way?
It's an old question but for those who want to understand what is going on behind the scene can read.
The ng-checked expression needs to be evaluated on every $digest.
See here:
https://docs.angularjs.org/guide/scope#integration-with-the-browser-event-loop

trying to achieve two way binding between ng-repeate and a form

Values of selected row in ng-repeate get populated in a form below it. to accomplish this i am doing a simple thing
<p ng-repeat="item in array" ng-click="SetCurrVariable(item)">
{{item.ThresholdSet}}
</p>
in the controller i have a function
$scope.array = [
{ ThresholdSet: false },
{ ThresholdSet: false },
{ ThresholdSet: false }
];
$scope.SetCurrVariable = function (variable) {
$scope.CurrVariable = variable;
};
form have a check-box that i bind to a property of CurrVariable
<input id="chkThr" type="checkbox" ng-model="CurrVariable.ThresholdSet">
i am trying to achieve this behavior that if i click the check-Box in the form. The change gets visible in ng-repeate like a two way binding.
Plunkr setup
Updated with $scope
$scope.SetCurrVariable = function (variable) {
$scope.CurrVariable = variable;
};
Use this code in your controller, then the two-way binding should work

How to pass a value from Jquery to angular Js?

I have working to pass a value from Jquery to angular js. But I have found undefined in angular js.
My code :
HTML :
<button onclick="change('5')"></button>
<input type="hidden" ng-model="data" id="one" />
<button ng-click="test(data)">Test</button>
JQuery:
function change(data)
{
$("#one").val(data).change();
}
Angular Js :
$scope.test= function(data)
{
console.log(data)
}
But I got undefined. How can I do this ?
You can do it for sure*, however you should probably not, as this blend of jQuery and Angular will soon become hard to maintain. This is not really well-design.
Instead, use angular directives and methods, in your case it's straightforward:
<button ng-click="change('5')"></button>
<input type="hidden" ng-model="data" id="one" />
<button ng-click="test(data)">Test</button>
and in Angular controller:
$scope.change = function(x) {
$scope.data = x;
};
* If you really want it: you need to let Angular know that you have changed the model from outside of digest cycle with manual $("#one").val(data).change(); angular.element($("#one")).scope().$apply();.

How to initialize ng-model of input checkboxes in an ng-repeat loop

I've run into an issue when creating multiple input[checkbox]es for a list of items in angular with ng-repeat and attaching an ng-model:
<li ng-repeat="item in items">
<a ng-href="#/{{item.id}}" > {{ item.id }} </a>
<input type="checkbox" ng-model="selectedMessages[item.id]"/>
</li>
The issue here is that selectedMessages[item.id] is only initialized and set when the checkbox is clicked once.
The reason this is necessary is that I would like to toggle all checkboxes with a single comand like so:
$scope.toggleCheckboxes = (state) ->
for key, val of $scope.selectedMessages
$scope.selectedMessages[key] = state # true or false
Let's say I have 3 checkboxes, and click 1 once, 2 twice, and 3 never, then said object will look like this:
$scope.selectedMessages = {
"1" : true,
"2" : false
}
So obviously, $scope.toggleCheckboxes(true) will only work for those checkboxes.
Is there a good way to initialize this ng-model for multiple checkboxes?
You can use ng-init to populate the array. I used $index rather than making up a bunch of data with id properties...adjust your code accordingly
<input type="checkbox"
ng-model="selectedMessages[$index]"
ng-init="selectedMessages[$index]=selectedMessages[$index]||false" />
JS
$scope.selectedMessages=[];
$scope.checkAll=function(){
var msgs = $scope.selectedMessages
msgs.forEach(function(elem, idx){
msgs[idx] =true
})
}
DEMO

Angular ng-class performance issue when too many elements in DOM

I have been working on a complex angular page which has been causing performance issue. To highlight the problem I have created a fiddle http://jsfiddle.net/4ex2xgL1/3/ here.
Essentially the performance issue is being caused by ng-class statement which has a function in it.
<span class="done-{{todo.done}}" ng-class="myfunction()">{{todo.text}}</span>
The span is in an ng-repeat. On running the fiddle one can see that ng-class gets executed several times when the page loads and on each key up it gets called as many time as number of items in the TODO list.
This is a lot simpler case, in my case I have 780 items on my page and the function ends up being evaluated aroung 3000 times!
One of the solution we saw is to break up the scope but it will cause almost a rewrite of my app.
We also tried https://github.com/Pasvaz/bindonce but it doesn't seem to be working with highly dynamic content.
Any thoughts?
I built a tree with https://github.com/JimLiu/angular-ui-tree with almost 500 items to render, with quite a lot of listeners. It takes 5 seconds to render. Bindonce won't work there.
The only solution out there is make ng-repeat do less. Keep the list small with a pagination, search or anything. Its the best shot as far as I know.
Well here are my recommendations
use ng-change on the checkbox to manipulate dom or anything rather using ng-class, it will improve your performance drastically.
<li ng-repeat="todo in todos track by todo.id">
<input type="checkbox" ng-model="todo.done" ng-change="myfunction()">
<span class="done-{{todo.done}}">{{todo.text}}</span>
</li>
http://jsfiddle.net/4ex2xgL1/3/
use track by in ng-repeat if you have ids, more here http://www.codelord.net/2014/04/15/improving-ng-repeat-performance-with-track-by/
dont show 780 items in a list. Use a searchbox to show some 100 or 50 or you know better
quick-ng-repeat not used yet, try testing it https://github.com/allaud/quick-ng-repeat
finally a few good http://tech.small-improvements.com/2013/09/10/angularjs-performance-with-large-lists/
Finally I found the solution and it will helps lot to improve performance in angular js.
If your model changes dynamically and if you have lots of data and then also it improve AngularJS pages rendering up to 1000% and more - no kidding !.
Fore more information you can visit : http://orangevolt.blogspot.in/2013/08/superspeed-your-angularjs-apps.html
Follow the steps:
download the library from the link:library
2.example without library:(check your console)
function MyController( $scope) {
var entries = [
{ label : 'one', value : 'first entry'},
{ label : 'two', value : 'second entry'},
{ label : 'three', value : 'third entry'}
];
$scope.label ="";
$scope.value ="";
$scope.order = 'label';
$scope.add = function() {
entries.push({
label : $scope.label,
value : $scope.value
});
};
$scope.getEntries = function() {
console && console.log( "getEntries() called");
return entries;
};
}
<script src="https://raw.githubusercontent.com/lodash/lodash/2.4.1/dist/lodash.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<form name="myform" ng-app ng-controller="MyController">
Label/Value :
<input type="text" required ng-model="label">
<input type="text" required ng-model="value">
<button
ng-disabled="!myform.$valid"
ng-click="add()"
>Add</button>
<fieldset>
<legend>
Entries sorted by
<select
ng-model="order"
ng-options="property for property in [ 'label', 'value']">
</select>
</legend>
<div ng-repeat="entry in getEntries() | orderBy:order">
{{entry.label}} = "{{entry.value}}"
</div>
</fieldset>
</form>
3.example with library:(check your console)
function MyController( $scope) {
var entries = [
{ label : 'one', value : 'first entry'},
{ label : 'two', value : 'second entry'},
{ label : 'three', value : 'third entry'}
];
$scope.label ="";
$scope.value ="";
$scope.order = 'label';
$scope.add = function() {
entries.push({
label : $scope.label,
value : $scope.value
});
// clear cache
$scope.getEntries.cache = {};
};
$scope.getEntries = _.memoize(
function() {
console && console.log( "getEntries() sorted by '" + $scope.order + " 'called");
// return entries sorted by value of $scope.order
return _.sortBy( entries, $scope.order);
},
function() {
// return the cache key for the current result to store
return $scope.order;
}
);
}
<script src="https://raw.githubusercontent.com/lodash/lodash/2.4.1/dist/lodash.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.20/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<form name="myform" ng-app ng-controller="MyController">
Label/Value :
<input type="text" required ng-model="label">
<input type="text" required ng-model="value">
<button
ng-disabled="!myform.$valid"
ng-click="add()"
>Add</button>
<fieldset>
<legend>
Entries sorted by
<select
ng-model="order"
ng-options="property for property in [ 'label', 'value']">
</select>
</legend>
<div ng-repeat="entry in getEntries()">
{{entry.label}} = "{{entry.value}}"
</div>
</fieldset>
</form>

Categories

Resources