How to use .slice().reverse() in *ngFor with | keyvalue? - html

I often use .slice().reverse() in *ngFor to display elements in reverse order. But now I have a problem, because I also use | keyvalue. How to use .slice().reverse() with | keyvalue?
<div *ngFor="let order of orderData.order.slice().reverse() | keyvalue ">
Sum: {{order.value.sum}}
</div>
This solution works but I am getting an error:

I don't think that you issue is with the keyvalue pipe. Probably the orderData is still not loaded whenever you are trying to use it and order is undefined.
You can do optional chaining/safe navigation operator in templates and adding a ? checks to see if the item on the left side has this property and and if it does it just returns it, if it doesn't it returns undefined and in this case if order is undefined inside the pipe transform method as value you will get undefined and if it exists you will get your array.
<div *ngFor="let order of orderData.order?.slice()?.reverse() | keyvalue ">
Sum: {{order.value.sum}}
</div>
Or you can just check if orderData has the order array and then render using the ngIf directive.
I suggest that you don't do slice().reverse() inside the templates like this because on every change detection cycle you will be creating a new array and reversing it. It would be a good idea to create a new pure pipe called reverse that reverses the array only if the instance has changed because otherwise you might get in trouble when working with larger arrays. Also if you are working with larger arrays providing a TrackByFunction on the ngFor will also increase performance.

I think the problem is here orderData.order, is undefined. That's why it throwing that error. You can make sure orderData.order is present then iterate the list like the below.
Note: ng-container is just a wrapper and Angular doesn't put it in the DOM.
<ng-container *ngIf="orderData.order">
<div *ngFor="let order of orderData.order.slice().reverse() | keyvalue">
Sum: {{order.value.sum}}
</div>
</ng-container>

We can get the last entries of the array by specifying the number inside slice with reverse function.
<div *ngFor="let order of orderData.order?.slice(-10)?.reverse() | keyvalue ">
Sum: {{order.value.sum}}
</div>

Related

How to get value from object angular using *ngFor?

I have a json structure like the image above.
I just want to get the value from the key name.
I was do Like this :
<span *ngFor="let outlet of products.body | keyvalue">{{outlet.value}}</span>
but that way is to call all attributes, I only want to call attribute name. how do?
Sorry for bad grammar, any suggestion or answer will be appreciate. Thank you
If you only want to get the value of name key, there is no need to use *ngFor.
It's enough to put it directly as follows.
<span>{{ products?.body?.name }}</span>
Please bind
{{outlet.name}}
instead of {{outlet.value}}

How to add an offset to an index in a *ngFor angular directive?

I want to display some data from a json but i can't simply add an offset to the index and show all te data from a certain offset but get
ERROR TypeError: Cannot read property 'id' of undefinedand the text in the div doesn't appear.
I have already tried to directly add a fixed number in the html file and it works (see the code below). But when it comes to use a variable "offset" (type:number) from typescript that is supposed to be updated with an input, the return type becomes undifined and the error appears. I also tried to use a method in my typescript file instead of doing the addition in the html file, and return the new index but it doesn't work and show the error. I also tried to call the method using {{addition(i,offset)}} and put the result in a variable that I use as an index but it still showing the error.
For exemple, this html file is working fine :
<ng-container *ngFor="let article of data; let i = index">
<ng-container *ngIf="i<(nbElements)">
<div (click)="checkArticle(data[(i+3)].id)">
<p class="text-center"> {{data[(i+3)][dataKey]}}</p>
</div>
</ng-container>
</ng-container>
The div reacts to my click and the text appears.
However, this html file is not working, even if the offset is set as 3 (as the html above) using an input in the parent component :
<ng-container *ngFor="let article of data; let i = index">
<ng-container *ngIf="i<(nbElements)">
<div (click)="checkArticle(data[(i+offset)].id)">
<p class="text-center"> {{data[(i+offset)][dataKey]}}</p>
</div>
</ng-container>
</ng-container>
The error appears.
The offset (type:number) is defined in my typescript file this way, and is changed by the parent component and can easily be displayed by the child component using console.log(offset):
export class AppColumnComponent implements OnInit {
#Input() offset : number ;
I expect the output to be texts showing the articles of my data json, but as I change the offset using an input like that data[(i+offset)] the result is an error, maybe it's impossible to use an other index using an other variable that a fixed number ?
Thank you for your support, it's my first post on stackoverflow i hope i did it well ! :)
If you want to make a pagination component, you should not rely solely on your HTML and some bindings.
Your component should have an "advanced" logic, in the sense that it should be able to know when it reaches the end/start of the collection (among other things).
Basically, this goes as follow :
Get the full collection (let's say 100 items)
Splice it to your item per page number (let's say 10, so results range is 0-10)
Test if items exist before the range
Test if items exist after the range
Allow/block page changing based on those variables.
This leaves you with
1 variable for the collection
1 variable (or 1 pipe) for the subset of the collection
1 variable for the items per page number
1 variable for the offset
2 booleans to disable pagination buttons.
Try working with this, and if you still have issues, then please provide a stackblitz with what you have tried !
You are accessing an index out of bounds.
data[(i+offset)] will be undefined for the last offset amount of elements in your data array so you are basically trying to do undefined.id which leads to your error.
You should change your method signature to only recieve the index as parameter and handle that case in your component.ts file

Angular 2+ Template Variable for a Group of Elements (Childs, Reusing Value) [duplicate]

This question already has an answer here:
Where does Angular define "as local-var" behavior for *ngIf?
(1 answer)
Closed 4 years ago.
I have a question about declaring temporary variables in Angular template to use it for multiple element (childs) like: (Idea / Expected)
<ng-container *ngVar="let theValue = item.getValue()">
<div>{{ theValue }}</div>
<div [class.foo]="theValue == 42">foo</div>
</ng-container>
I already have a workaround for this. Just wrap the value in a array and use ngFor like: (Workaround)
<ng-container *ngFor="let theValue of [item.getValue()]">
<div>{{ theValue }}</div>
<div [class.foo]="theValue == 42">foo</div>
</ng-container>
But this is a bit dirty. - Is there an official solution?
My idea is to reduce the computing of the value over and over again for the same value. I just want to reuse the computed value for multiple childs and / or attributes.
I do not want to compute getValue() every time. Because I get the same value anyway. To hold the value temporary in a group element it can improve the performance and readability.
It should be possible without a custom directive.
I mean to have seen something like this before.
One possible solution is to 'cache' the return value of getValue(). This technique is called memoization. It works only on pure functions, meaning that for the same inputs, the output is always the same, and when function has no side effect.
You can use a decorator to achieve this in a straightforward manner, here is a project that might be useful to you: https://github.com/darrylhodgins/typescript-memoize.

How to bind json object to angular material form

I'm currently making a simple form using angular framework with the json file given to me. Inside the json were some arrays and objects. Well, I successfully binded the json arrays. My problem now is I don't know how to do it with the json object. I cannot bind the columns stated in json file to my form, instead the number of columns was diplayed in the UI. I already tried using the ngFor but the error says ngFor only supports binding to iterables such as arrays. I'm actually new to angular and this angular material. Any help will be appreciated
Below is the form i am making. Numbers encircled in red supposed to be the columns.
This is the json file. json Object encircled in red was the column i want to bind in my form
This is my app.component.html. I do think this is where my mistake resides
this is what i mean for the columns. as you can see. item 1 and item 1A are in two columns. item 2 is only in one column
You don't need the colums field value. You can simply use display: flex for the <section>:
<section style="display:flex; justify-content: space-between;" class="section" *ngFor="let inputSection of inputs.sections">
<div class="section-content" *ngFor="let field of inputSection.fields; let i = index;">
[...]
</div>
</section>

Sorting dropddown based on a property of JSON object in Angularjs

http://jsfiddle.net/aBccw/
<div ng-options="f.name for f in JSONArray | orderBy:'f.name'" ng-model="selected" ></div>
This is just dirty representation of actual code, it might contain syntactical errors, But what my question is that I don't want whole object in ng-model. I need a property of Object say age. But if I write
<div ng-options="f.age as f.name for f in JSONArray | orderBy:'f.age'"......
orderBy won't work correctly. How can I make orderBy work with the latter one.
To sort using a property, say age in your case, the correct syntax is this:
<select ng-model="selected" ng-options="f.name for f in friends | orderBy:'age'"></select>
Fiddle