AngularJS Nested ng-repeat Not Working in Version 1.2.1 - javascript

I am working on a system where I would like to nest two ng-repeat statements so that I can work my way through a 2D array. I was able to complete the task successfully using version 1.1.1 as you can see here:
http://jsfiddle.net/skArT/1/
However, when I take the exact same code set and change the version of Angular to 1.2.1 the code no longer works and throws an error:
http://jsfiddle.net/skArT/2/
Error:
Error: [ngRepeat:dupes] Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: x in value, Duplicate key: number:0
So my question is, how can I accomplish the task shown in version 1.1.1 with newer versions of Angular?

All you need to do is read the error message and listen to it. Change:
<div ng-repeat="x in value">{{x}}</div>
To:
<div ng-repeat="x in value track by $index">{{x}}</div>

Adding a track by clause solves this. It seems rather trivial to me for it to be required in your case.
<body ng-app="myApp" ng-controller="myCtrl">
<span ng-repeat="(index, value) in field">
<div ng-repeat="(key,x) in value track by key">{{x}}</div>
<br/>
</span>
</body>
http://jsfiddle.net/92bSt/

Related

How to show the name of the variable in an AngularJS website?

I'm trying to show the name of the variable in my website written with AngularJS.
for example:
Backend code:
$scope.Bundles = {
Bundle1:["Sensor1","Sensor2"],
Bundle2:["Sensor1","Sensor2","Sensor3"],
Bundle3:["Sensor1","Sensor2","Sensor3","Sensor4"]
}
Frontend code:
<label ng-repeat="name in Bundles">
<div> *Want to show "Bundle#" (name), instead of it's value (the sensors)* </div>
</label>
Some notes:
From google searches, I always find people asking how to show the value of the variable, {{name}}, I know that, haven't found anything like the question im asking here
I need it because later in the code I will need to do a ng-repeat with "sensor in name" to show the sensors separately, so I really need a concrete solution and not a dirty one with another array holding the names.
Thank you.
You can access both the key and value using:
<label ng-repeat="(key, value) in Bundles">
<div> *Want to show {{ key }}, instead of it's value {{ value }} (the sensors)* </div>
</label>
You can use the tuple returned by the ng-repeat as stated in the docs https://docs.angularjs.org/api/ng/directive/ngRepeat
<label ng-repeat="(key,value) in Bundles">
You can use javascipt Object.keys(arr) to get all the keys and then iterate to the keys using ng-repeat.
$scope.BundleNumbers = Object.keys($scope.Bundles)
$scope.BundleNumbers will have ["Bundle1", "Bundle2", "Bundle3"]
<label ng-repeat="name in BundleNumbers">
{{name}}
</label>
The other and efficient/angular way to do is :
<label ng-repeat="(key,value) in Bundles">{{key}} </label>
Reference links:
Angular JS ng Repeat
JavaScript Object keys

AngularJS: bo-bind of bindonce and the translate filter

I'm using angular 1.2.25, angular-translate 2.0.1, angular-translate-loader-static-files 2.0.0 and angular-bindonce 0.3.1.
What I want to do is translating a static translation key with bindonce. So I got this code snippet:
<div bindonce>
<div bo-bind="'TEST' | translate"></div>
</div>
As result of this snippet the translation key is displayed instead of the translation. If I'm using now ng-bind instead of bo-bind everything works just fine:
<div>
<div ng-bind="'TEST' | translate"></div>
</div>
I have stepped through with the debugger and it seems like the translate filter doesn't exist when bo-bind is executed.
Is there any way I can use this one time binding in combination with angular-translate?
Here is a plunker replicating my issue
Try:
<div bindonce="languages"> <div bo-bind="'TEST' | translate"></div></div>
in controller just set scope "language" = true when angular-translate build complete. I think you should use rootscope for saving "language"

AngularJS: Using 'track by' disables filter in ng-repeat

Since I implemented track by into ng-repeat, it prevents my filter from executing. For example, track by $index works like a charm but when I try to add an input field to search my object, nothing happens and the console does not show any error.
Here is my html:
<input type="text" ng-model="searchText">
<div ng-repeat="message in messages.collection track by $index | filter : searchText">
<p>{{message.text}}</p>
</div>
I also created a Plunkr in order to show both cases (with and without track by).
I would like to know if it is a syntax problem or something else in order to fix it.
You need to add track by at the end of the expression. See this working plunkr.
Code:
<div ng-repeat="message in messages.collection | filter : searchText track by $index">
<p>{{message.text}}</p>
</div>
Please rather try to track by on the filter
message in messages.collection | filter : searchText track by $index
As suggested on https://docs.angularjs.org/api/ng/directive/ngRepeat
Best

How to show a message when filter returns nothing in ng-repeat - AngularJS

I would like to show one div(message) when no items returned on filter(ng-repeat).
Filter is happening based on select box (ng-model). And there are no results for some select options, at that time user should be able to read a message at same place.
Can I use ng-show/hide here? How?
Thanks,
You can also save your filtered array in a variable and then use that variable inside the ng-show expression:
<select ng-model="shade" ng-options="shade for shade in shades"></select><br>
<ul>
<li ng-repeat="c in filteredColors = (colors | filter:shade)">{{c.name}}</li>
</ul>
<div ng-show="!filteredColors.length">No colors available</div>
You can see it in action in this plunker.
You can get the size of array returned by filter using something like
{{(data|filter:query).length}}
You can use this expression for ng-show expression. I am not sure how performant would it be.
There's a simpler solution using just the standard syntax of ngRepeat.
As stated in the official documentation, the ngRepeat accepts an alias for the collection even if filter are applied to it:
<div ng-repeat="model in collection | filter:search | orderBy: 'id' as filtered_result track by model.id">
{{model.name}}
</div>
Note: I added ad additional filter to the example copied from the documentation to have a more complete example.
In this example you can simply use:
<div class="alert alert-info"
ng-show="filtered_result.length == 0">
No items in the collection!
</div>
I tested it with AngularJS 1.5.0, I can't tell when this feature was introduced.

Angular NgModelController behaviour inside ng-repeat

Once I realized how ng-model directive works and was absolutely confident about it's behaviour this example just blowed my mind
<html ng-app>
<head>
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/css/bootstrap-combined.min.css" rel="stylesheet">
</head>
<body ng-init="names = ['Sam', 'Harry', 'Sally']">
<h1>Fun with Fields and ngModel</h1>
<p>names: {{names}}</p>
<h3>Binding to each element directly:</h3>
<div ng-repeat="name in names">
Value: {{name}}
<input ng-model="name">
</div>
<p class="muted">The binding does not appear to be working: the value in the model is not changed.</p>
<h3>Indexing into the array:</h3>
<div ng-repeat="name in names">
Value: {{names[$index]}}
<input ng-model="names[$index]">
</div>
<p class="muted">Type one character, and the input field loses focus. However, the binding appears to be working correctly.</p>
</body>
ng-repeat fiddle. Main problem is angular's behaviour for three different versions. I understand that ng-repeat creates a new scope for each array item, I suppose (not sure) it tracks only array reference and it's size (so, array items shouldn't cause $digest loop on change), but, what we've got here (watch just first example without $index using): for version 1.0.3 < we have expected behaviour: changing 'name' property with input will only change ngModelController's value (scope inheritance) and this is fair, 1.1.1 - well, what's going on there: we don't even get new values inside of input and! we don't rerender our items cause we don't lose the focus (and i really don't understand why $digest loop fires value replacement for this input as Artem has said), third version - 1.2.1: changing input values also changes 'name' value in the outer scope (as I understand ngModelController should inherit a scope created by ng-repeat directive). So, what really happens (and why) in all three examples?
Using Angular latest version (1.2.1) and track by $index. This issue is fixed
http://jsfiddle.net/rnw3u/55/
<div ng-repeat="name in names track by $index">
Value: {{names[$index]}}
<input ng-model="names[$index]">
</div>

Categories