How to pass an ng-repeat iterator to ng-click - angularjs

I have created this snippet in AngularJS that displays a pagination bar on my web page. The object $scope.PagesOnBar contains an array of numbers like 1, 2, 3 which are appearing on the pagination bar. The problem is in my ng-click attribute; the value {{x}} gets passed as a literal - the x is not replaced with 1, 2, 3. How can I re-write this so that the numeric value is passed to the BarClick function? I tried putting ng-repeat before ng-click and that didn't work either. I also tried removing the curly braces - same result.
<ul class="PaginationBar">
<li class="FloatLeft" ng-click="BarClick('<<');"><<</li>
<li class="FloatLeft" ng-click="BarClick('<');"><</li>
<li class="FloatLeft" ng-click="BarClick('{{x}}');" ng-repeat="x in PagesOnBar">{{x}}</li>
<li class="FloatLeft" ng-click="BarClick('>');">></li>
<li class="FloatLeft" ng-click="BarClick('>>');">>></li>
</ul>

<ul class="PaginationBar">
<li class="FloatLeft" ng-click="BarClick('<<');"><<</li>
<li class="FloatLeft" ng-click="BarClick('<');"><</li>
<li class="FloatLeft" ng-repeat="x in PagesOnBar" ng-click="BarClick(x)">{{x}}</li>
<li class="FloatLeft" ng-click="BarClick('>');">></li>
<li class="FloatLeft" ng-click="BarClick('>>');">>></li>
</ul>
Most ng directives don't need curly braces ({{ }}) to understand that you're referring to some sort of expression or variable.
Also, this may be just my preference, but I tend to declare the ng-repeat loop before I ever try to reference the iterated variable. It may be that Angular will still understand it, but at least for reading, it makes more sense to declare it first.

If you don't want a literal, don't enclose x in '... Just write x

Related

ng-repeat and ng-click not playing well

<li ng-repeat="item in data" ng-click="myFunc('{{ item.name }}')">
I can't seem to get ng-click to pass the varible value of item.name. It actually sends:
{{ item.name }}
An example in Plunker:
http://plnkr.co/edit/dq5KA3?p=preview
In the console it looks ok, but doesn't actually work:
ng-click is actually an angularjsexpression, so you should be able to set it as ng-click='myFunc(item.name)'. This will pass the actual value of item.name rather than trying to pass the string value of the raw text as your current implementation is doing.
Use:
<li ng-repeat="item in data" ng-click="myFunc(item.name)">{{item.name}}
</li>
Because item is an object.
Explanation about the results in the console, in your scenario:
Always: {{item.name}} It will print the value, this is why you see in the console:
<li ng-repeat="item in data" ng-click="myFunc('Apple')" class="ng-binding ng-scope">Apple
</li>
Because you have in your page:
<li ng-repeat="item in data" ng-click="myFunc('{{ item.name }}')">{{item.name}}
</li>
ng-click is actually an angular directive not an expression, you need to give brackets when you are passing value to the expression but you do not need to use brackets when you pass values to directive.

How to iterate through an array of arrays in JSON using ng-repeat?

I am trying to iterate over a JSON object userTypes.
For the below code:
In the 1st ng-repeat:
{{user.type}} outputs 'Parent'(as expected),
{{user.options}} outputs '[{"option1":"11QWERT","option2":"22QWERT"}]'(as expected).
But in the 2nd ng-repeat, I am not able to iterate through the user.options and output each of the {{options}}
What should be changed to get the option1 and option2 as the outputs in 2nd ng-repeat ?
JS snippet
var userTypes = [{
"type": 'Parent',
"options": [{
"option1": "11QWERT",
"option2": "22QWERT"
}]
}]
HTML snippet
<li ng-repeat="user in userTypes">
<p>{{user.type}}</p>
<p>{{user.options}}</p>
<li ng-repeat="option in user.options">
<p>
{{option}}
</p>
</li>
</li>
Replace your child <li> with <ul> and then you can iterate user.options like so:
<li ng-repeat="user in userTypes">
<p>{{user.type}}</p>
<ul ng-repeat="(key, value) in user.options[0]">
<p>{{key}}: {{value}}</p>
</ul>
</li>
Or if your options may include more then one object:
<li ng-repeat="user in userTypes">
<p>{{user.type}}</p>
<ul ng-repeat="option in user.options">
<li ng-repeat="(key, value) in option">{{key}}: {{value}}</li>
</ul>
</li>
If you don't need object keys:
<ul ng-repeat="option in user.options">
<li ng-repeat="item in option">{{item}}</li>
</ul>
Fiddle
Extended explanation:
In your example you have <li> tag inside another <li>:
<li ng-repeat="user in userTypes">
<li ng-repeat="option in user.options">
</li>
</li>
Since it is not a valid HTML browser will interprets this markup to following:
<li ng-repeat="user in userTypes">
</li>
<li ng-repeat="option in user.options">
</li>
Since ng-repeat creates new scope for each iteration you can't access user variable in second ng-repeat and iterator wouldn't run.
For this exact JSON input it should be like this:
<li ng-repeat="option in user.options">
<p>
{{option.option1}}
{{option.option2}}
</p>
</li>
However as you said you want non fixed number of options, update your JSON to be like this:
"options":["11QWERT","22QWERT"]
And then your code should work as you wanted it.
You can add each new element to list with simple coma before it.
Since user.options is an array you should loop it again. By doing that you will get an object, with that object you can access your options1 and option2 easily.
please refer working plunker:
http://embed.plnkr.co/5c3i5fY50jLP0fFgxkUX/preview
see through the code if you have any doubt.
Hope this helps
A little aside, but just found out you can render a valid list HTML using ng-repeat-start/end in combination with ng-if="false" for the given array of arrays to flatten them:
<ul>
<script ng-repeat-start="user in userTypes" ng-if="false"></script>
<li ng-repeat="item in user.options">{{item}}</li>
<script ng-repeat-end="" ng-if="false"></script>
</ul>
Just access the propertie of the option object in the second ng-repeat. Like option.option1
You should probably make your user.options an object and not an array containing a single object.
Note the difference between these:
[{"option1":"11QWERT","option2":"22QWERT"}]
{"option1":"11QWERT","option2":"22QWERT"}
You can then iterate the options with an ng-repeat like discussed here:
<li ng-repeat="(key, value) in user.options">
<p>{{ key }}: {{ value }}</p>
</li>

Uncertainty about the use of ngInclude

I render recursive template with ngInclude. Here is my code:
<!--
definitionsRenderer.html
-->
<ul data-ng-if="currentLoc.definitions && templateIsloaded">
<li ng-repeat="definition in currentLoc.definitions">
{{definition.text}}
</li>
</ul>
<ul data-ng-if="templateIsloaded">
<li ng-repeat="loc in currentLoc.loc" ng-include="'./partials/definitionsRenderer.html'"></li>
</ul>
I need code to be executed asynchronous. So for scope of every included template
I want to have a variable - templateIsloaded with value false by default. When template is loaded and rendered it value to be true. How do that?
Best regards.
To have separate $scope for each of recursive called includes you can simply add ng-controller.
<li ng-repeat="loc in currentLoc.loc" ng-controller="definitionsRendererCtrl" ng-include="'./partials/definitionsRenderer.html'"></li>

Do bindings nested inside of a lazy one-time ng-repeat binding bind just once?

My understand is that in the following code, both bindings will lazily bind only once:
<li ng-repeat="item in ::items">{{::item.name}}</li>
However, in the following case will {{item.name}} be updated every digest?
<li ng-repeat="item in ::items">{{item.name}}</li>
And how does one-time binding effect nested ng-repeats ?
<li ng-repeat="item in ::items">
<span ng-repeat="thing in item.things">{{thing.name}}</span>
</li>
Scenario 1:
<li ng-repeat="item in ::items">{{::item.name}}</li>
Both expressions will be one-time bound. Adding an item or changing an existing item's name will not be reflected.
Demo: http://plnkr.co/edit/53r8FCmcNK4MmM6Uzxp2?p=preview
Scenario 2:
<li ng-repeat="item in ::items">{{item.name}}</li>
First expression will be one-time bound. Adding an item will not be reflected. Changing an existing item's name will be reflected.
Demo: http://plnkr.co/edit/52wTEb8ze2FKRDDcS9Ow?p=preview
Scenario 3:
<li ng-repeat="item in ::items">
<span ng-repeat="thing in item.things">{{thing.name}}</span>
</li>
First expression will be one-time bound. Adding new item will not be reflected. Adding a new thing and changing existing thing's name will be reflected.
Demo: http://plnkr.co/edit/HkObhkJtUnFEHBAzFUmN?p=preview

AngularJS: $index lost with filter?

I'm new to AngularJS so please be kind to me.. :-P
So I'm looping twice with ng-repeat as in this example:
<ul>
<li ng-repeat="b in aMSG">
<p>{{b.name}}</p>
<ul>
<li ng-repeat="c in b.x"><a ng-click="getM($parent.$index,$index)" href="#">{{c.name}}</a></i>
</ul>
</li>
</ul>
See the fiddle: http://jsfiddle.net/trK98/
But when I apply a filter to search for text within the children:
<ul>
<li ng-repeat="b in aMSG">
<p>{{b.name}}</p>
<input type="text" ng-model="search" placeholder="Search for?">
<ul>
<li ng-repeat="c in b.x|filter:search"><a ng-click="getM($parent.$index,$index)" href="#">{{c.name}}</a></i>
</ul>
</li>
</ul>
The $index is lost as you can see here: http://jsfiddle.net/zb2kc/
(search for instance for juice then click on it you'll see $index = 0)
What am I doing wrong?
Thank you!
P.S: Sorry for my poor english.
Never use $index for any kind of logic. It can be used for managing CSS classes only. It's a highly volatile variable and will be changed after any change in source array (deletion, re-ordering), so $index is not bind to element of array, but only to position of some element in current view rendering.

Resources