I have an object that looks like this:
$scope.locations [
{Kanaanbadet: {"name":"Kanaanbadet","image":"http://www.stockholm.se/Web/Core/Pages/Special/StreamServiceGuideImage.aspx?path=%2fWeb%2fCore%2fPages%2fSpecial%2fServiceGuideFile.aspx%3ffileid%3d14b313cb2b2f45e380eb88156c95b539","_cached_page_id":"4b71e342c82be9de1c74de3c2f57ea1c4dde8150","long":"17.85448","lat":"59.34966","url":"http://www.stockholm.se/-/Serviceenhetsdetaljer/?enhet=cf0a856830e4422cb55dcd60e8e6b40b"}},
{Johannelundsbadet:{"name":"Johannelundsbadet","image":"http://www.stockholm.se/Web/Core/Pages/Special/StreamServiceGuideImage.aspx?path=%2fWeb%2fCore%2fPages%2fSpecial%2fServiceGuideFile.aspx%3ffileid%3d3e4c2056b5534cfc9b0799e2377b8ce4","_cached_page_id":"18cf34222d74612979afd945a925abc0bf16e44d","long":"17.98914","lat":"59.34098","url":"http://www.stockholm.se/-/Serviceenhetsdetaljer/?enhet=ebf8d49780224e908064551c35dbcca4"}},
...more items
]
I would lie to put out the name in a template within a foreach, and I would like to be able to reference the key.
<a ng-href="#/{{location}}" class="location" ng-repeat="location in locations">{{location}}</a>
I can change the array around to look some other way, but I would like to keep it as an array so I can sort it and select items from the objects keys somehow. How should structure my array?
I think you want to wrap this in two repeats:
<div ng-controller="DemoCtrl">
<div ng-repeat="location in locations">
<a ng-href="#/{{item.url}}" class="location" ng-repeat="item in location">{{item.name}}</a>
</div>
</div>
Maybe check this Plunker
I have to be honest, I really dislike the way you have structured your object. The object should be anonymous, and name should be a property within it. That way, you could use location.name.
All that being said, you can use Object.keys() to get an array of the keys within the object.
<a ng-href="getKey(location)"
class="location"
ng-repeat="location in locations"> {{ getKey(location) }}
</a>
getKey would have to be a function on your scope:
$scope.getKey = function(location){
return Object.keys(location)[0];
}
Example plunk
Note: depending on desired browser support you might be better to iterate over the properties using a for (key in location) loop as some older browsers won't support Object.keys().
Related
I can write data by keyValuePipe or {{data | JSON}} but I think that is not good solution for me. How I can write data differently? How I use for this example Object.entries, Object.keys or Object.value?
Code with JSON in Stackblitz: https://stackblitz.com/edit/angular-ivy-jn8snh?file=src/app/app.component.ts
Your object is considered as a dictionary in javascript.
You can loop over properties of your object as follow:
<div *ngFor="let property of data">
<p>{{ property }} - {{ data[property] }}</p>
</div>
You can't to do that out of the box. NgForOf allows iterating over a collection, and by default object does not implement required methods and properties. In theory you could get the keys of the object by writing something like this:
<p *ngFor="let property of Object.keys(object)">
{{property}} {{object[property]}}
</p>
But the way the contents of ngFor are evaluated, the global variable Object is not present in the scope. So you're best off writing a custom pipe that would do the work for you by transforming your object into iterable of your choice that is suitable for your requirements (not idea what that would be since the only information is that "keyValuePipe or {{data | JSON}} is not good solution for me" without any reasoning).
I have an object
Object {1: "CMAR0002", 2: "CMAR0003", 4: "CMAR0001"}
I am using this object in ng-repeat directive but i want to sort it by values. But the problem is that angular orderBy filter requires array of objects. But i have only pretty simple object here ;)
Thanks in advance
By Angular ng-repeat documentation:
It is possible to get ngRepeat to iterate over the properties...
However, there are a limitations compared to array iteration, like "The built-in filters orderBy and filter do not work with objects, and will throw if used with one"
If you are hitting any of these limitations, the recommended workaround is to convert your object into an array that is sorted into the order that you prefer before providing it to ngRepeat. You could do this with a filter such as toArrayFilter or implement a $watch on the object yourself.
Anyway, you can try to implement you own filter for this, but it will be pretty ugly and it will require much effort (probably for nothing).
Hope, it will help you!
Do this:
<li ng-repeat="(key, value) in Object | orderBy: key">
{{ key }} - {{ value }}
</li>
Fiddle: http://jsfiddle.net/oo4cb9xf/1/
I have next structure of a component data:
I want to print a list of assignedCards within component's view using *ngFor. I do this possible:
<div *ngFor="#item of mission.assignedCards" class="b-progress-bar__item m-progress-bar__item_completed">
<div class="b-progress-bar__inner">{{item}}</div>
</div>
But it falls with an exception:
If i test mission value, it says me, that mission is an object.
So, i'd like to access assignedCards array inside mission object and make a loop of it.
I guess that the mission object is loaded asynchronously. So it's undefined at a first time and is set later...
So you could use the Elvis operator (mission?.assignedCards):
<div *ngFor="#item of mission?.assignedCards"
class="b-progress-bar__item m-progress-bar__item_completed">
<div class="b-progress-bar__inner">{{item}}</div>
</div>
I receive an object which is on server-side a map, i.e. a key-value array. I would like to bind it in an Angular form and be able to modify the value (easy) and the key. Challenge is that when the key is modified, the associated value has to stay linked.
I tried :
<div ng-repeat="(type, value) in estate.extraServices track by $index">
<input ng-model="type"> <input ng-model="estate.extraServices[type]">
</div>
But when the first input change, a new line is added to the map and the new one is not linked to the new one.
My goal is to avoid using a scope function to resolve this problem, so I ask without many hope, but who knows !
If a binding on a key isn't possible, I would probably change the object structure to an array of Pair object (2 property : key and value)
<div ng-repeat="pair in array">
<input ng-model="pair.key"> <input ng-model="pair.value">
</div>
You can't bind an input to the actual property name. Object property names can't be changed dynamically
Your first example however works fine to update values
<div ng-repeat="(type, value) in estate.extraServices track by $index">
{{type}} <input ng-model="estate.extraServices[type]">
</div>
As for adding keys you would need to use a different input not bound to that object to add a new key to the object. Then with an event handler use a function that updates the object
Same for removing keys , use an event handler function that would do delete object[key]
Changing to an array of objects with same key name structure would likely be simplest depending on how this object is used
DEMO
This should be an extremely simple question, but all of the workarounds I've found are complex. I'm looping through an array of objects in using ng-repeat in a template as follows:
<div class="row-fluid" ng-repeat="message in messages.current|filter:'draft'">
{{ message.subject }} ... {{ campaign.name }} ...
</div>
Since the ng-repeat creates a new scope, the 'campaign' object from the controller doesn't seem to be accessable. Is there any way (aside from adding the campaign object to every item in my array) of getting that value?
Thanks in advance.
You can access the parent scope by using $parent
<div class="row-fluid" ng-repeat="message in messages.current|filter:'draft'">
{{ message.subject }} ... {{ $parent.campaign.name }} ...
</div>
This is a way that works that doesn't use $parent. It searches upwards through the nested scopes to find the object you're using, however many scopes it has to go through.
In the scope that contains the list, you can define an object with the list as a property, like this:
$scope.obj = {};
$scope.obj.items = ['item1','item2','item3'];
Then have the ng-repeat look like this:
<div ng-repeat="item in obj.items | filter:'item3' track by $index">
{{obj.items[ obj.items.indexOf(item) ]}}
</div>
(you need to use obj.items[ obj.items.indexOf(item) ] rather than obj.items[ $index ] because $index is the index of the filtered array, not the original)
The reason this works is because while obj doesn't exist in the current scope, as you attempt to access its property, Angular will look above the current scope rather than give you an error (if you just tried {{obj}} it would be undefined, and Angular would be happy with giving you nothing instead of looking through higher scopes). This is a helpful link about nested scopes: http://www.angularjshub.com/examples/basics/nestedcontrollers/
In my case I needed the track by $index, because I had an input with ng-model bound to an item in the array, and whenever the model updated, the input would blur because I think the HTML was being re-rendered. A consequence of using track by $index is that items in the array with identical values will be repeated. If you modify one of those other than the 1st one, weird things will happen. Maybe you can filter for uniqueness to avoid that.
I'm relatively new to AngularJS, so please comment if there is anything big I'm missing. But this works, so I'm using it at least.
Another method might be to pass parent scope as a scope variable to the directive i.e.
<my-directive
md-parent-scope="this"
ng-repeat="item in items"></my-directive>
It's a bit messy, but you have more control over what the parent actually is and can pass anything in.