access variable in scope from ng-repeat ng-style - angularjs

I got some problem on AngularJS.
my controller, mainCtrl, has this variables :
this.colors = {Sam:blue,Jane:red,Tom:pink};
this.arr = [{person:'Sam',story:'some story'},{name:'Tom',story:'some story2'}]
And I got this code :
<div ng-controller="mainCtrl as vm">
<ul ng-repeat="obj in arr">
<li ng-style={color:vm.color[obj.person]}>{{obj.story}}</li>
</ul>
</div>
I want that the li will be colored such as the color of the person at colors dictionary . how can I handle that? I got undefined every time, but when I do it explictly its work , for Example :
<li ng-style={color:vm.color['Sam']}>{{obj.story}}</li>

You are using the controllerAs-Syntax, so you must use vm.arr in your ng-repeat. And furthermore you should use the ng-repeat on the list item:
<ul>
<li ng-repeat="obj in vm.arr" ng-style="{color:vm.color[obj.person]}">{{obj.story}}</li>
</ul>

It should look like this.
<div ng-controller="mainCtrl as vm">
<ul>
<li ng-repeat="obj in vm.arr track by $index"
ng-style="{'color':vm.colors[obj.person]}"
ng-bind="obj.story">
</li>
</ul>
</div>
Remember to use your alias vm (controllerAs)
Usetrack by with ng-repeat for better performance.
I think that ng-repeat should have been placed in li
Her's a working jsfiddle http://jsfiddle.net/irhabi/nh4ddemr/

Related

AngularJS - Change scope with one of the iterations of a ng-repeat

I have a project with Angular where I don't want to use a select element with ng-options, so I made up a list with different options in order to select one of them.
<div class="countrylist">
<ul>
<li ng-repeat="c in shippingCountry"><p>{{c.name}}</p></li>
</ul>
</div>
So the option selected would modify another element where the chosen option would be displayed.
<div>
<ul>
<li>{{selectedCountry}}</li>
</ul>
</div>
In order to do that, I would need to pass the data from the chosen option of the first element into the 2nd one. I have tried doing something like this
<li ng-repeat="c in shippingCountry" ng-click="selectedCountry = {{c}}"><p>{{c.name}}</p></li>
with no success.
You can check the plunker here Thanks in advance
I suggest you to use a function over there like this in the DEMO
<li ng-repeat="c in shippingCountry" ng-click="Click(c)"><p>{{c.name}}</p></li>
Having this method in your controller
$scope.Click=function (c)
{
$scope.select=c;
}
It creates child scope for each iteration, so explicitly refer parent scope:
Change like this,
<ul>
<li ng-repeat="c in shippingCountry" ng-click="$parent.selectedCountry = c"><p>{{c.name}}</p></li>
</ul>
DEMO
I've fixed your plunker here. It would be better to use methods in scope for this operations because they work in current scope, not in child
<li ng-repeat="c in shippingCountry" ng-click="selectCountry(c)">
<p>{{c.name}}</p>
</li>
// .html
<div>
<ul>
<li>{{selectedCountry.item}}</li>
</ul>
</div>
<div class="countrylist">
<ul>
<li ng-repeat="c in shippingCountry" ng-click="selectedCountry.item = c"><p>{{c.name}}</p></li>
</ul>
</div>
// controller
$scope.selectedCountry = {
item: $scope.shippingCountry[0]
};
Example

Avoid multiple use of a Filter in AngularJs

I am trying to avoid using the same filter on the same collection multiple times in AngularJS application.
What is the correct way to do it:
<div ng-app="myApp" ng-controller="PeopleCtrl">
<ul ng-init="(person in people|filter:{show:true}) as myPeople" ng-if="myPeople.length>0">
<h4>My People</h4>
<li ng-repeat="person in myPeople">{{person.name}}; display: {{person.show}};
</ul>
</div>
CODE PEN
When I use (person in people|filter:{show:true}) as myPeople I try to use an alias in order to not repeat the same filter{show:true} everywhere...
You should do it something like this:
<div ng-init="myPeople = (people | filter:{show:true})">
<div ng-if="myPeople.length>0">
<h4> My People</h4>
<ul>
<li ng-repeat="person in myPeople">
{{person.name}}; age: {{person.age}}; show: {{person.show}};
</li>
</ul>
</div>
</div>

In what scope is ng-repeat "as alias" available

I'm using angular 1.4.8. I want to save filtered result from ng-repeat and use it to determine whether to enable a "load more" button at the bottom of the list. I have looked at this question:
AngularJS - how to get an ngRepeat filtered result reference
And many others, they suggest to use "as alias" from ng-repeat, here's what my code looks like:
<ul class="media-list tab-pane fade in active">
<li class="media">
<div ng-repeat-start="item in items | limitTo: totalDisplayed as filteredResult">
{{item}}
</div>
<div class="panel panel-default" ng-repeat-end>
</div>
<div>
{{filteredResult.length}}
</div>
</li>
</ul>
<button ng-click="loadMore()" ng-show="totalDisplayed <= filteredResult.length">
more
</button>
However, I found filteredResult.length is displayed fine right after ng-repeat, but the button is never shown. If I try to display filteredResult.length in where the button is, it will show null.
So is there a rule for "as alias" scope? I've seen plenty of examples work but mine doesn't, what am I missing here?
EDIT:
The accepted answer uses controllerAs which indeed will resolve the problem. However, charlietfl's comment using ng-init to save filteredResult to parent scope is also very neat and that's the solution I use in my code eventually.
Probably some of classes in your <ul class="media-list tab-pane fade in active"> or <li class="media"> is selector for a directive that would have its own scope. So you store filteredResult in e.g. tab-pane's scope and then try to have access out of it's scope in outside of ul tag.
Try to use Controller as instead of scope:
angular
.module('plunker', [])
.controller('MainCtrl', function() {
vm = this;
// make an array from 1 to 10
var arr = [];
while (arr.length < 10) {
arr.push(arr.length + 1)
};
vm.items = arr;
vm.totalDisplayed = 5;
vm.filteredResult = [];
});
<body ng-controller="MainCtrl as main">
{{main.items}}
<ul class="media-list tab-pane fade in active">
<li class="media">
<div ng-repeat-start="item in main.items | limitTo: main.totalDisplayed as filteredResult">
{{item}}
</div>
<div class="panel panel-default" ng-repeat-end>
</div>
<div>
filteredResult = {{main.filteredResult = filteredResult}}
</div>
</li>
</ul>
<button ng-click="loadMore()" ng-show="main.totalDisplayed <= main.filteredResult.length">
more
</button>
</body>
http://plnkr.co/edit/drA1gQ1qj0U9VCN4IIPP?p=preview

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>

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