Angular 2. Loop of array inside object using ngFor - javascript

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>

Related

How to loop over object properties with ngFor in Angular app

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).

Unable to create ref dynamically in Vue.js

I am rendering a list and then a sublist within that. I want to have a ref to my inner list which will be named something like list-{id}. However, I am not able to achieve this.
Here is the code snippet:
<ul class="scrollable-list" ref="getScrollableRef(company.id)">
<li v-for="operation in getOperations(company.id)">
{{company.name}}
</li>
</ul>
When I inspect the $refs object:
$vm0.$refs
Object {getScrollableRef(company.id): Array(13)}
I think for some reason the value is not being evaluated. Has anyone faced this?
Edit: I am trying to solve this problem https://github.com/egoist/vue-mugen-scroll/issues/14
In your example, you are specifying that the ref should literally be named "getSchoolableRef(componany.id)". That's why the $refs object contains an getScrollableRef(company.id) property with an array of 13 elements as its value.
If you want to use the result of the getSchoolableRef method as the name of the ref, you can use v-bind or the shorthand colon:
<ul class="scrollable-list" :ref="getScrollableRef(company.id)">
As you mentioned, $refs is not reactive and changing the bound value once the component has initialized will not update the property name in $refs. But, you can dynamically set the name of the ref when the component initializes.

Accessing specific array element in an Angular2 Template

I have an array that I can loop through using ng-for syntax. However, ultimately I want to access just a single element of that array. I cannot figure out how to do that.
In my component script I have
export class TableComponent {
elements: IElement[];
}
In my template, I am able to loop through the elements via
<ul>
<li *ngFor='let element of elements'>{{element.name}}</li>
</ul>
However, trying to access an item in the element array by secifically referencing an item utilizing
x {{elements[0].name}}x
does not seem to work.
The formatting in the template is pretty explicit, so I want to be able to access each element of the array explicitly in the template.
I am not understanding something basic....
2020 Edit :
{{elements?.[0].name}}
is the new way for the null check
Original answer :
{{elements[0].name}}
should just work. If you load elements async (from a server or similar) then Angular fails when it tries to update the binding before the response from the server arrived (which is usually the case). You should get an error message in the browser console though.
Try instead
{{elements && elements[0].name}}
Work around, use ngIf check the length. elements? means if elements is null, don't read the length property.
<div *ngIf="elements?.length">
{{elements[0].name}}
</div>

How to output array of objects in angularjs?

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().

Pass parent scope value into ng-repeat loop in Angular

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.

Categories