I have an issue with the ngIf in Angular. So basically I want to implement a notification system to notify the user of what fields are missing.
Here is a stackblitz for the issue: https://stackblitz.com/edit/angular-behnqj
To reproduce:
1. first select the vehicle type 'plane', here everything is correct, the first error is removed and the second remains with index = 1.
2. Now refresh the stackblitz preview webpage and this time select the vehicle type 'car', we can now see that the first error is removed but the second remains with index = 2.
With some debugging I figgured out if I swap between conditions in the ngIf and do something like
<ng-container *ngIf="selectedVehicleType === 'plane'; else carsOptions">
<option *ngFor="let plane of planes; let i=index" [value]="plane" [selected]="plane === selectedVehicle" [hidden]="i===0"> {{plane}}</option>
</ng-container>
</select>
<ng-template #carsOptions>
<option *ngFor="let car of cars; let i=index" [value]="car" [selected]="car === selectedVehicle" [hidden]="i===0" > {{car}}</option>
</ng-template>
This will result to the same issue but this time with the issue occuring when we select 'plane' and not 'car'.
change it to this it will work :)
<div class="content">
<span>errors:</span>
<ul style="list-style: none;">
<li *ngFor="let error of errors; let i=index;"> {{(i+1)+ ". "+error}}</li>
</ul>
</div>
hope it helps.
Related
what I want to do is when I check an item the div of that item appears
for example if I select Crédit bancaire and Compte courant associé.
the two divs corresponding to these items are displayed
Here is the example:
https://stackblitz.com/edit/angular-d163sn?file=src%2Fapp%2Fapp.component.ts
here is a simple workaround, try changing bindValue from id to name
and change this code
<div>
<div *ngIf=" selected == 1">Crédit bancaire</div>
<div *ngIf=" selected == 2">Compte courant Associe</div>
<div *ngIf=" selected == 3">Fonds Propres</div>
</div>
to this
<div *ngFor="let item of selected | keyvalue">
<h1>{{item.value}}</h1>
</div>
the idea is to store that object to an iterable object, but keep in mind we need to use keyValue pipe to make it work with ngFor.
<tr *ngFor = "let item of list; let i = index;">
The above code gives error:
Type 'number' is not assignable to type 'string'. td [ngModelGroup]="j" #temp="ngModelGroup"
But the below code runs fine
<tr *ngFor = "let item of list; let i as index;">
What is the difference in using i = index and i as index.Previously I was using i = index and it was working fine.
Can someone help me with this?
You forgot the let before the i...
That happens because Angular is searching for the i variable in your component logic (the .ts file). And it doesn't find it, so by adding let behind the variable, Angular knows that this is not a variable in the component logic but inside the view that should be created.
Here you can find more information about that:
https://angular.io/api/common/NgForOf#local-variables
You lack of the double quote sign.
Try this with 3 case below to better understand:
<tr *ngFor="let item of list; let i = index">
<td>{{i}}/{{item}}</td>
</tr>
<p>In this case variable i is a index of list, begin from 0.</p>
<hr>
<tr *ngFor="let item of list1; let j as index">
<td>{{j}}/{{item}}</td>
</tr>
<p>In this case variable j is a value of index in list.</p>
<hr>
<tr *ngFor="let item of list1; index as k">
<td>{{k}}/{{item}}</td>
</tr>
<p>In this case variable k is a index of list.</p>
Demo: https://stackblitz.com/edit/angular-ivy-zldcpt?file=src%2Fapp%2Fapp.component.html
let i = index is not proper Angular syntax anymore. Starting with Angular 5 (IIRC) it became let i as index. Did you upgrade Angular recently?
You can check the documentation to verify: https://angular.io/api/common/NgForOf
I have a requirement to always display minimum of 5 rows(5 or more rows) in a table. For example, if there are 2 rows available in Database, I need to display other 3 more rows in UI with empty rows.
Here is what I tried so far:
<div *ngFor="let task of tasks; let i = index">
<div class="rowDiv">{{task.id}}</div>
</div>
Here I want to run the loop from i = tasks.size to i < = 5. So that I have total of 5 rows in UI. How to achieve this?
<div *ngFor=" let i = index">
<div class="rowDiv"></div>
</div>
You can loop over an array of 5 items, and use *ngIf to display an additional row if no data item exists at a given index:
<div *ngFor="let task of tasks">
<div class="rowDiv">{{task.id}}</div>
</div>
<ng-container *ngFor="let i of [0,1,2,3,4]">
<div *ngIf="!tasks[i]">
<div class="rowDiv">This row is empty</div>
</div>
</ng-container>
See this stackblitz for a demo.
you can also add so many rows you need after
<table>
<row *ngFor="let task in task">
</row>
<!--if task.length<5-->
<ng-container *ngIf="tasks.length<5">
<!-use slice:0:5-tasks.length-->
<row *ngFor="let i of [0,1,2,3,4] |slice:0:5-tasks.length">
</row>
</ng-container>
</table>
You don't need to keep this logic in html.
In you class you can do something like this: (suppose you fetch tasks from server)
this.getTasks().subscribe((tasks) => {
const emptyTasks = Array(5).fill({id: 'empty'});
this.tasks = tasks.map((t, index) => t || emptyTasks[index]);
})
This could be better handled in the controller. In case of default change detection strategy, the template is reloaded multiple times without our control or knowledge. So it's better to make sure the tasks variable has atleast 5 elements in the controller rather than to control the flow in the template. You could something like the following in the controller and leave the template unchanged.
for (let i = 0; i < 5; i++) {
if(!this.tasks[i].id) {
this.tasks[i].id = '';
}
}
I display 51 questions with their related answers on a page.
Both information come from one web-service call.
<tbody>
<tr *ngFor="let QuestionOption of questions; trackBy: trackQuestionById; let i = index;">
<th scope="row">{{QuestionOption.id}}</th>
<td>{{QuestionOption.name}} {{QuestionOption.description}}
</p>
<select class="form-control" name="selectAnswer" [(ngModel)]="answer[i]">
<option *ngFor="let answers of QuestionOption.Answers" [ngValue]="answers.id">{{answers.description}}</option>
</p>
</td>
</tr>
</tbody>
on the typescript code I try the following:
answer: Answer[];
this.answer = new Array<Answer>();
The type Answer has multiple fields like: Id, Name, Score, Description
What is not working is that I always have get the Id into the answer[i]
but I want to have the id in the field answer[i].id
If i change the
[(ngModel)]="answer[i]"
into
[(ngModel)]="answer[i].id"
I get the following exception:
ERROR TypeError: "_co.caaAnswer[_v.context.index] is undefined"
I also tried:
[(ngModel)]="answer[i]?.id"
So is it correct to use answer[i] ? and then in the option I should somehow assign to answer[i].id the selected value. If so somebody can help how to do it.
Any help is appreciated! Thanks a lot.
augeres
I found the solution. The problem was that the compareWith function did not work properly because of the Array. It only works in case you name the html select based upon the array index:
Working version:
<select class="form-control" id="field_answer{{i}}" name="field_answer{{i}}" [(ngModel)]="resultAnswer[i].answer" [compareWith]="compareFn">
<option [ngValue]="answer" *ngFor="let answer of Question.answers; trackBy: trackAnswerById">{{answer.id}} {{answer.description}}</option>
</select>
You have to push into answer on select change like this
<select class="form-control" name="selectAnswer" [(ngModel)]="selectedAnswerId" (change)="setAnswer(i)">
<option *ngFor="let answers of QuestionOption.Answers" [ngValue]="answers.id">{{answers.description}}</option>
<select>
in component.ts
selectedAnswerId : number;
setAnswer(index){
this.answer[index].push({id : this.selectedAnswerId})
}
I need to show data in select with two lines each. I am using ng-select.
<ng-select [(ngModel)]="selectedData" placeholder="Select Data">
<div *ngFor="let data of Data">
<ng-option [value]="data.id">
{{data.name}} - {{data.price | currency}}
{{data.description}} - {{data.code}}
</ng-option>
</div>
</ng-select>
I am using ng-select and trying to show the data in ng-option, it is showing the data in one line. already tried br and /n.
Thanks in advance.
No, you can't!
None browser will allow doing this formatting of text.
But yes you can use some another alternate for show text if needed may be using title which will show data as a tooltip.
This is not supported.
Try this instead,
Data.forEach(element => {
dropDownDataSource.push(id: element.name, value: element.name)
dropDownDataSource.push(id: element.description, value: element.description)
});
<ng-select [(ngModel)]="selectedData" placeholder="Select Data">
<option *ngFor="let data of dropDownDataSource" value="{{data.value}}">
{{data.id}}
</option>
</ng-select>