Restructure the display of instantiated elements in *ngFor - html

I am currently just adding randomized numbers to an array and displaying them to the user.
<div *ngFor="let temp of randomIntArray; let i = index">
<div *ngIf="i == randomIntArray.length - 1">
This is the real random number {{ temp }}
<div>
<button (click)="addRandomValueIntoRandomIntArray()">
add random number
</button>
</div>
</div>
<div *ngIf="i != randomIntArray.length - 1">
{{ temp }}
</div>
</div>
I think I understand what's happening here as I am creating a new element on the DOM each time the user clicks : addRandomValueIntoRandomIntArray() as its increasing the length of the randomIntArray.
Due to the: *ngIf="i == randomIntArray.length - 1 this will always be the last element and will be always be displayed at the bottom. Is there any feasible way for me to to swap them around and have all the new elements created at the bottom going downwards instead? Below is an image of how it currently looks.

You can reverse the order of ngFor items using randomIntArray.slice().reverse()
and you need to change ngIf condition to i==0.
app.component.html
<div *ngFor="let temp of randomIntArray.slice().reverse(); let i = index">
<div *ngIf="i ==0">
This is the real random number {{ temp }}
<div>
<button (click)="addRandomValueIntoRandomIntArray()">
add random number
</button>
</div>
</div>
<div *ngIf="i != randomIntArray.length - 1">
{{ temp }}
</div>
</div>

Related

how to create custom tree model WITHOUT mat-tree in angular?

I have a tree structure like below :
every item can have unlimited nested children. I created it like below but it only shows the parent and their children. It doesn't show the children of their children(only shows 2 level). This is the html code:
<div *ngFor="let parent of phonebookTreeModelArray; let i = index">
<div
class="tree-parent"
(mouseenter)="showButtons(i)"
(mouseleave)="hideButtons(i)"
>
<p class="phonebook-title" (click)="displayChilds(i)">
{{ parent.name }}
</p>
</div>
<div
class="tree-children"
*ngIf="parent.children.length > 0 && currentDisplayChildIndex === i"
>
<div class="tree-child" *ngFor="let child of parent.children">
<p class="phonebook-title">
{{ child.name }}
</p>
</div>
</div>
</div>
I don't know how to implement it when the nested tree is infinite.

How to assign the first element context with default value?

I am using the follwing code to display some values from the array
<div class="row">
<div class="column" *ngFor="let card of cards; let i=index">
<div class="card">
<h3>Card {{card.id}}</h3>
<p>{{card.text}}</p>
</div>
</div>
</div>
But I would like to set the first one is a button with given hard code text. It shouldn't from the array.
I think that probably using ngClass to compare when the index is 0. But not sure how?
Angular has the first and last variables out of the box.
I can't clearly understand what you are asking, but I think you want to show a button only on the first? You can also target the last like below.
<div class="row">
<div class="column" *ngFor="let card of cards; let i=index let first = first; let last = last">
<div class="card">
<h3>Card {{card.id}}</h3>
<p>{{card.text}}</p>
<ng-container *ngIf="first"><button>first item only</button></ng-container>
<ng-container *ngIf="last"><button>last item only</button></ng-container>
</div>
</div>
</div>
You might try something like this:
<div class="row">
<div class="column" *ngFor="let card of cards; let i=index">
<div
class="card"
(click)="((i === 0) || (i === cards.length)) && yourClickEvent($event)"
>
<h3>Card {{ (i === 0) ? 'Your Hard code ID' : card.id }}</h3>
<p>{{card.text}}</p>
</div>
</div>
</div>
The condition in the click event above, will check if its either the first or last card and then implement your click functionality.. so is the case with the ID
Is this what you are trying to achieve?

highlight word by start and end matches using angular 7

I have a collection of array which is having datas like
[0]: username {kavya} secret {password}
[1]: lorem ipsem text data value
[2]: lorem {{lrm}} datas {{pp}}
I am using foreach to show this data in frontend with
<div *ngFor="let data of output;let i=index">
<div *ngIf="data.includes('{') || data.includes('{{');else isNotEdited;" >
<div class="variable-textarea" contenteditable="false" >
<span>
{{data | slice:' ' }}
</span>
</div>
</div>
<ng-template #isNotEdited>
<ngx-md>{{data}}</ngx-md>
</ng-template>
</div>
Here I achieved like 0,2 row of div will be editable and in case of 1st array is non-editable.
But I want to do like specific matches which word starts with { or {{ and that particular word needs to be highlight and editable.
Is there any option to do in this way
Thanks in advance.
You could split the data into words:
<div *ngFor="let data of arr">
<span *ngFor="let word of data.split(' ')">
<span *ngIf="word.indexOf('{') > -1;else isNotEdited;">
<span class="variable-textarea-2" contenteditable="true">
{{word | slice:' ' }}
</span>
</span>
<ng-template #isNotEdited>
<span class="variable-text-2" contenteditable="false">
{{word}}
</span>
</ng-template>
</span>
</div>
Check this Stackblitz example I made based on your code: https://stackblitz.com/edit/angular-pkg6i9
this is a performance nightmare, you don't want to be running this many functions in template, and your format isn't helping you. map your data ahead of time into a friendlier view model:
this.mappedOutput = this.output.map(data => {
const editable = data.includes('{'); // checking for doubles is redundant
return {
editable,
data: !editable
? data
: data.split(' ')
.map(word => ({
word,
editable: word.trim().startsWith('{') && word.trim().endsWith('}')
}))
};
})
run this whenever your output changes, then use it in template:
<div *ngFor="let data of mappedOutput;let i=index">
<div *ngIf="data.editable;else isNotEdited;" >
<div class="variable-text">
<ng-container *ngFor="let word of data.data">
<div *ngIf="word.editable; else wordTmp" class="variable-textarea inline" contenteditable="true" >
<span>{{word.word}}</span>
</div>
<ng-template #wordTmp>
{{word.word}}
</ng-template>
</ng-container>
</div>
</div>
<ng-template #isNotEdited>
<ngx-md>{{data.data}}</ngx-md>
</ng-template>
</div>
and adjust the styles by adding this to your css:
.variable-textarea.inline {
display: inline-block;
width: fit-content;
margin: 0;
}
here's an edited blitz: https://stackblitz.com/edit/angular-arayve?file=src/app/app.component.html

ng-if and col col-50 don't seem to go together?

I am trying to generate a table using angular code in HTML. Now I seem to have how I want the table to look which is how I have set up this code:
<div class="row">
<div class="col col-25">Date</div>
<div class="col col-50">Name of Customer</div>
<div class="col col-25">Hours Used</div>
</div>
What I have done is generated a list in angular code (which is done correctly) and I have ordered them in a certain way with Date being the first entry and Hours Used being the last. To generate the table in HTML, I use this code:
<div class="row">
<div ng-repeat="B in ConvertToTableRow(T) track by $index">
<div class="col col-25" ng-if="$index == 0">
{{ B }} &nbsp
</div>
<div class="col col-50" ng-if="$index == 1">
{{ B }} &nbsp
</div>
<div class="col col-25" ng-if="$index == 2">
{{ B }} &nbsp
</div>
</div>
</div>
Everything in the first row works well and styled to what I need it to be but the second entry (when the index is 1) will never style its table to a col-50 but instead will stick with a col-25. Now I have tested to see the if the values are equal to 1 or 2 but it seems that is working correctly and the infomation is also coming out correctly but its just not styling correctly.
Is it possible to style a table this way using Angular and HTML?
Would it not be better to use ng-class? I think there's an even better way, but this is just off the top of my head. I hope this helps! :) Documentation for ng-class
<div class="row">
<div ng-repeat="B in ConvertToTableRow(T) track by $index">
<div class="col" ng-class="{'col-25': $index % 3 !== 1, 'col-50': $index % 3 === 1}">
{{ B }} &nbsp
</div>
</div>
</div>

Can you use a ngFor with a modulus operator in Angular 2

I'm writing out images to the web page. Every three images I would like to start a new row. Does angular 2 support this?
You can achieve it by doing following:
<div *ngFor="let t of temp(math.ceil(arr.length/3)).fill(); let i = index" class="row">
<div *ngFor="let item of arr.slice(3*i,3*i + 3);" class="item">
{{item}}
</div>
</div>
And in your component:
export class App {
temp = Array;
math = Math;
arr= [1,2,3,4,5,6,7,8,9,10,11];
}
Here's working Plunker
You can access the index of the iteration from the *ngFor like so:
*ngFor="let x of container; let i = index;"
you can then reference that index in an *ngIf inside of the *ngFor to display your new row:
<div *ngIf="i%3 === 0">
Borrowing from both answers, but leaning more on Alex's, here's how I accomplished it in ng2 (v2.0.1).
<template ... is deprecated. Where you see <template ... you should use <ng-template ... after v5.
<template ngFor let-peer [ngForOf]="peers" let-p="index" let-last="last">
<div class="row" *ngIf="p % 2 === 0">
<div class="col-xs-8 col-sm-6">
<label><input type="checkbox" ... {{peers[p].name}}</label>
</div>
<div class="col-xs-8 col-sm-6" *ngIf="!last">
<label><input type="checkbox" ... {{peers[p+1].name}}</label>
</div>
</div>
</template>
Note that while I get each item from the collection, let-peer [ngForOf]="peers", I don't specifically use it. Instead I use the collection and the index, let-p="index", adding to the index as needed, e.g., peers[p] and peers[p+n].
Adjust your modulus as needed. The last row should check to be sure that the first column to the last column is not the last item in the iterable.