I have simple object:
"socials": {
"f": "#/facebook/",
"B": "#/behance/",
"d": "#/dribble/",
"L": "#/linkedin/",
"P": "#/pinterest/"
}
When I try to use ng-repeat="(key, value) in data.socials" it sorts like this: B L P d f.
$index catches wrong index, just as it is ordered by already. How can I order it correctly as it is in jSON file? Or maybe how can I get correct index to use orderBy: correctIndex? I found a fiddle that shows an issue exactly like this: http://jsfiddle.net/zMjVp/
ngRepeat iterates over object keys in alphabetical order to manage tracking items by $index (see the code for ngRepeat on Github).
To control the order of iteration in ngRepeat you should convert your object structure into an Array which has guaranteed iteration ordering:
JavaScript:
var jsonData = {
"socials": {
"f": "#/facebook/",
"B": "#/behance/",
"d": "#/dribble/",
"L": "#/linkedin/",
"P": "#/pinterest/"
}
};
var socialsList = [];
angular.forEach(jsonData.socials, function(value, key){
socialsList.push({
key: key,
value: value
});
});
$scope.socialsList = socialsList;
HTML:
Then update your HTML to iterate over the list instead of the object.
<div ng-repeat="item in socialsList">
<p> {{item.key}} : {{item.value}} </p>
</div>
NOTE:
Unless you're using the delete operator you can generally rely on the order of the for...in loop. It's not guaranteed, but it's generally reliable. See the MDN documentation on for...in loops
Related
I wnt to use ng-repeat to display a list filtered by an object value. Here is a plukr of my attempt https://plnkr.co/edit/vD4UfzM4Qg7c0WGTeY18?p=preview
The following returns all of my JSON names as expected.
<li ng-repeat="item in collection_data">{{navitem.name}}</li>
now i want to filter and only show the names of the items that have "foreign_lang": "es", like in this json snippet
{
"id": "ddb06ba2-6348-4d45-9e63-a6fa3632e5c2",
"created_at": "2015-10-12T18:34:15.668Z",
"updated_at": "2016-04-14T15:55:37.433Z",
"custom_attributes": {
"Display Name": "Activos en Español",
"foreign_lang": "es",
"display_boxes": "false"
},
},
so i made this filter function
$scope.filterByDisplay = function() {
$filter('filter')($scope.collection_data, ['foreign_lang', 'es']);
}
and called it like this.
<li ng-repeat="item in collection_data" | filter: filterByDisplay>{{navitem.name}}</li>
I did not get any console errors but i got nothing returned.
How do I properly filter through this collection to only return items with 'foreign_lang', 'es' as a value in the json? See the plunkr to see a working example https://plnkr.co/edit/vD4UfzM4Qg7c0WGTeY18?p=preview
Third attempt (since the question was revised). Use the filter function to check each object individually, and returning only those that pass the truth test.
$scope.filterByDisplay = function(value) {
return (value.content)
&& (value.content.custom_attributes)
&& (value.content.custom_attributes.foreign_lang === "es");
}
Updated Plunk - Using Filter Function
I have created a Angular Select box for countries. My array looks like this:
AD: "Andorra"
AE: "United Arab Emirates"
AF: "Afghanistan"
AG: "Antigua and Barbuda"
AI: "Anguilla"
And my NgRepeater looks like this
<li nya-bs-option="(k, v) in fields.country.available" data-value="v" data-label="{{v}}">
As you can see, The 'Key' is automatically getting alphabetically arrange in order. However I wish for the 'Value' to be arranged in alphabetical order. I have tried:
<li nya-bs-option="(k, v) in fields.country.available | orderBy:'v'" data-value="v" data-label="{{v}}">
But this didn't work. Can anyone help?
Your array seems more like an object as far as I can see from <key>:<value> structure. In this case you would need to write an own filter for orderBy because angular cannot sort object keys with this filter.
See also: Order by Object key in ng-repeat
Despite of the solution in the thread above, I would suggest to use another structure for the countries if possible:
[{id: 'AD', name: 'Andorra'}, ...]
Then you can do this in ng-repeat:
country in fields.country.available | orderBy: 'id'
I have solved it. And by doing this way, the countries are automatically put into alphabetical order :)
HTML:
<ol class="nya-bs-select" ng-model="data.ship.country" name="ship_{{fields.country.slug}}">
<li nya-bs-option="v in sortable" data-value="v[0]">
<a>{{v[1]}}</a>
</li>
</ol>
Controller:
var countries = fields.country.available,
sortable = [];
for (var country in countries){
sortable.push([country, countries[country]]);
}
sortable.sort(function(a, b) {
return a[1] - b[1]
});
$scope.sortable = sortable;
I know in my current version of Angular, ng-repeat auto sorts. My problem is that its sorting doesn't appear to be correct.
Taking an object with numbered keys:
{
"1": "value",
"2": "value",
"10": "value"
}
ng-repeat sorts it 1, 10, 2. I'm familiar with this sort of sorting and throwing a 0 on the front of number should fix it. However adding that 0 requires additional code and would need to be stripped out for display.
Likewise, converting to an array caused ng-repeat to loop through all of the empty values (3-9) and creates excess elements, as well as generating a duplicate error.
How can I make ng-repeat sort an object by keys as if they were integers?
I was not able to find a solution that didn't change your data structure, but here is an example of how it can be done by using keys to sort the object into an array. Here is the html:
<ul ng-controller="ExampleController">
<li ng-repeat="item in filtered">{{ item.value }}</li>
</ul>
And here is the code:
controller('ExampleController', ['$scope', function($scope) {
$scope.list = {
"1": "1 Value",
"10": "10 Value",
"5": "5 Value",
"2": "2 Value"
};
$scope.$watch('list', function (newVal) {
$scope.filtered = Object.keys(newVal).map(function (key) {
return { key: key, value: newVal[key] };
});
});
}]);
The output of this code looks like this:
1 Value
2 Value
5 Value
10 Value
Note that this creates an array of key/value pair objects which is easier to work with. Here is a plunker example of it working: http://plnkr.co/edit/Q0BYLeMzTZmd1k8VzTlQ?p=preview
This is my first time playing with AngularJS, and actually, I'm following the getting-started tutorial. It came to my mind that I would tweak the tutorial scripts to my understandings, by just adding a little that was not in the tutorial.
Basically, the phone object used in the tutorial was:
{
"age": 1,
"id": "motorola-xoom",
"imageUrl": "img/phones/motorola-xoom.0.jpg",
"name": "MOTOROLA XOOM™",
"snippet": "The Next, Next Generation..."
}
What I was trying to do was to add an auto populated select box for order the list:
<select ng-model="orderProp">
<option ng-repeat="(key, value) in phones[0]" value="{{key}}">
{{labels[key]}}
</option>
</select>
and added a model labels to the controller:
$scope.labels = {
"name": "Phone name",
"snippet": "Description",
"age": "Newest",
};
It was working as expected, except that I only wanted to filter the 3 properties above, so I think it would be easy to add a custom predicated function for filtering like this:
$scope.isPhonePropFilterable = function (propName) {
console.log('it DOES NOT get here!!!');
return propName == 'name' || propName != 'snippet' || propName != 'age';
};
and added this to the ng-repeat
<option ng-repeat="(key, value) in phones[0] | filter:isPhonePropFilterable" value="{{key}}">
To my suprise, it was not as easy as I thought, my filter function was not called.
See it here: plunker
Did I do anything wrong?
edited: ng-repeat filter supports filtering array only, not object. The filter function returnes if array param is not an array...
Well, it was my fault. Ng-repeat filter supports array only, it did only mention array in the docs. And checking the filter function, it returned if array param is not an array....
I've got a problem with ng-class in AngularJS - it doesn't update properly.
View:
<div class="cal-day" ng-repeat="day in schedule">
...
<div class="entry" ng-click="entryDetails(entry)" ng-repeat="entry in day.blockGrid"
ng-class="{'selected': isSelected(entry), 'bg-{{entry.color}}': entry, 'bg-empty': !entry}">
{{isSelected(entry)}}
...
</div>
</div>
JS:
$scope.entryDetails = function(entry) {
$scope.entryForDetails = entry;
};
$scope.isSelected = function(entry) {
return $scope.entryForDetails === entry;
};
CSS class selected is implemented fine - when I replace isSelected(entry) with true in ng-class, the class gets applied properly.
Same thing with isSelected() function - it correctly prints true or false depending on whether the item is selected.
Even though both elements work, they somehow refuse to work together, and the div class doesn't get updated to selected when isSelected(entry) returns true.
Edit:
Model stored in day
{
"date": "6.6.2013",
"blockGrid": [
null,
null,
null,
null,
null,
null,
{
"group": "ABCD",
"subjectName": "AB CD",
"subjectShorthand": "PW",
"type": "c",
"number": 4,
"profName": "ABAB",
"date": "2013-06-05T22:00:00.000Z",
"venue": "329 S",
"timetableBlock": 7,
"color": 16,
"_id": "51c3a442eb2e46a7220000e2"
}
]
}
As you can see, it's an array of 7 elements which are either null or contain an entry object.
I forgot to mention that posted section of my view is inside another ng-repeat. View code snippet above is now expanded to reflect that.
Ng-class, as you have set it up, is wanting to evaluate a boolean expression, which your first expression in the object has done. However, the next two expressions are trying to evaluate the entry object, and not the result of isSelected(entry), which returns true/false.
So to correct:
ng-class="{'selected': isSelected(entry), 'bg':isSelected(entry), 'bg-empty':!isSelected(entry)}"
That is, unless you are trying something else. Also notice that I removed bg-{{entry.color}}. I have no clue how to evaluate a scope property within an ng-class, or if it is even possible.
Here is the working plunker demo. This may not be what you are after, but it can at least help you troubleshoot.