Angular NgFor loop 2 arrays of objects - html

I want to loop through two different arrays with ngFor and display them in html.
<div class="form-check ml-5" *ngFor="let item of competencias.competencias; let i = index">
<input class="form-check-input" type="checkbox" [value]="item.id [(ngModel)]="arrayCompetencias[i].checked">
<label class="form-check-label">
<strong> {{ item.id }} </strong> : {{ item.descripcion}}
</label>
</div>
Those 2 arrays has the same length but I want to combine them as to show separate data.
First array has a list of data just to display and is fine.
Second array arrayCompetencias I want just to see if user check the checkbox or not and save it as ngModel.
When trying to get the parameter data in arrayCompetencias[i].checked it through me an error that the field is undefined, but I am initializing them before.
First Array
competencias = [{id: string, descripcion: string}]
Second Array
arrayCompetencias = [{checked: boolean, id: string}]
[(ngModel)]="arrayCompetencias[i].checked">
How can i read only this field into the array and set according User checked or not

I fixed some typos on your code and added some edits.
Try to use this example and it should work perfectly with you.
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
competencias = [{id: "1", description: "This is a description"}]
arrayCompetencias = [{checked: true, id: "1"}]
}
<div *ngFor="let item of competencias; let i = index">
<input type="checkbox"
[value]="item.id"
[checked]="arrayCompetencias[i].checked"
(change)="arrayCompetencias[i].checked = !arrayCompetencias[i].checked">
<label>
<strong> {{ item.id }} </strong> : {{ item.description}}
</label>
</div>

Nothing I have changes only a problem in your data.
You can check the code here

Related

Angular NgFor Path Issue

In my Angular Application I have a simple ngFor loop showing logo images like this:
<div *ngFor="let item of list" class="logo-wrapper">
<div class="customer-logo">
<span
class="my-icon"
aria-label="My icon"
[inlineSVG]="'./assets/image/projects/logo/' + item.logo">
</span>
</div>
</div>
This is working fine!
But: If I try to slice the Array to limit the output as follow:
<div *ngFor="let item of list | slice: 0:10; let i = index" class="logo-wrapper">
<div class="customer-logo">
<span
class="my-icon"
aria-label="My icon"
[inlineSVG]="'./assets/image/projects/logo/' + item.logo">
</span>
</div>
</div>
I get this Error : "Object is of type 'unknown'".
Error output:
I really don't know what I'm doing wrong here. I hope someone can point me in the right direction.
Edit: The problem appears as soon as I add a index to the loop.
I tried to add the index to the object like: item.i.logo but its also unknown.
PS: Here is my .ts-file
#Component({
selector: 'app-logo-section',
templateUrl: './logo-section.component.html',
styleUrls: ['./logo-section.component.scss']
})
export class LogoSectionComponent implements OnInit {
list : any
constructor()
{
this.list = getProjects()
console.log(this.list)
}
ngOnInit(): void
{
}
private services = [{
slug : "s-l-u-g",
name : "name",
work : "work",
company : "company",
website : "https://www.google.com",
preview : "text",
logo : "logo.svg"
}]
getProjects()
{
return services
}
}
You would have to change the type of list to any[] instead of any. Update the declaration as follows in your typescript file.
list : any[];
It seems like the SlicePipe deprecates with the ng-inline-svg package because it uses HttpClientModule and works asynchronously.
if you use Array.slice method instead of the SlicePipe in the *ngFor it works fine.
Please find the Stackblitz example.
<div *ngFor="let item of list.slice(0, 10); let i = index" class="logo-wrapper">
<div class="customer-logo">
<span class="my-icon" aria-label="My icon" [inlineSVG]="item.logo"> </span>
</div>
</div>

Access nested json object angular 6

I'm trying to access the nested data from the HTML template, but I get undefined or I get nothing as result (empty page with no class list or student list).
The HTML template:
<div class="container">
<label *ngFor="let class of listClass | keyvalue">
<span> {{class.value.name}} </span>
</label>
<div>
<label *ngFor="let student of class.students | keyvalue">
<span>{{student.value.fullName}} </span>
</label>
</div>
</div>
This is the fonction that gets the list of class and the students in it:
getListClasseStudent(){
this.classService.getStudents().subscribe((data) => {
this.listClass = data;
});
}
The nested data:
class:
0:{
code: "Math01"
teacher:
0: {id: 17551, name "Jack"}
students:
0: {studentId: 1, fullName: "Patrick bob"}
1: {studentId: 2, fullName: "Alice Alice"}
}
1:{
code: "English01"
teacher:
0: {id: 2, name "Nicolas"}
students:
0: {studentId: 1, fullName: "Patrick bob"}
1: {studentId: 2, fullName: "Alice Alice"}
}
I want to access to the list of student of each class, is there any efficient way to do it? thanks in advance.
<div class="container">
<div *ngFor="let c of listClass ">
<label >
<span> {{c.code}} </span>
</label>
<div>
<label *ngFor="let student of c.students ">
<span>{{student.fullName}} </span>
</label>
</div>
</div>
Try this (example without your pipe)
A 'Class' object don't have a attribute 'value.name' (probably gonna be injected by your pipe '| keyvalue' ).
Second *ngFor need t be inside of first, because he need's to iterate a students array, inside each class.
I hope this helps.
create a pipe like below
import { Pipe, PipeTransform } from "#angular/core";
#Pipe({ name: 'ObjNgFor', pure: false })
export class ObjNgFor implements PipeTransform {
transform(value: Object): Array<string> { return Object.keys(value); }
}
import the above pipe in app.module.ts and use pipe in the html page like below
<div *ngFor="let key of questions | ObjNgFor" class="row">
{{ questions[key].name}}
<div *ngFor="let r of questions[key].sub_sections | ObjNgFor ; let indx=index"
class="card-body">
{{ questions[key].sub_sections[r].name }}"
</div>
This example should work

How to use *Ngfor in an other *Ngfor

I am trying to create a checkbox for each element of an array "lesCriteres".
Then I want each of these checkboxes to be checked if its value is in the table "actif.lesCriteresActifs"
Here is the code I want but it does not work as I want
<div class="checkbox-inline" *ngFor="let l of lesCriteres">
<div *ngFor="let a of actif.lesCriteresActifs">
<label></label>
<input type="checkbox" (change)="onChangeEvent(l.code, $event.target.checked)" [checked]="a.critere.code==l.code"> {{l.code}}<br>
</div>
</div>
MODELS
actif model
import {TypeActif} from './model.type-actif';
import {CritereActif} from './model.critere-actif';
export class Actif{
ref: string;
nom: string = '';
type_actif: TypeActif = new TypeActif();
lesCriteresActifs: Array<CritereActif> = new Array<CritereActif>();
}
CritereActif model
import {Actif} from './model.actif';
import {LesCriteres} from './model.les-criteres';
import {LesValeurs} from './model.les-valeurs';
export class CritereActif{
id: number;
actif: Actif = new Actif();
critere: LesCriteres = new LesCriteres();
valeur: LesValeurs = new LesValeurs();
}
LesCriteres model
export class LesCriteres{
code: string = null;
nom: string = '';
}
RESULT
i have this when i execute my code :
but i want't something like this :
This should work (using includes() method, without additional *ngFor):
<div class="checkbox-inline" *ngFor="let l of lesCriteres">
<label></label>
<input type="checkbox" (change)="onChangeEvent(l.code, $event.target.checked)" [checked]="actif.lesCriteresActifs.includes(l)"> {{l.code}}<br>
</div>
About includes method: https://www.w3schools.com/jsref/jsref_includes_array.asp
EDIT:
This solution comes to mind.
In .ts file of your component, inside class declare a function:
containsCode = (code) => {
for (let a of this.actif.lesCriteresActifs) {
if (a.critere.code === code) {
return true
}
}
return false
Then in .html file:
<div class="checkbox-inline" *ngFor="let l of lesCriteres">
<label></label>
<input type="checkbox" (change)="onChangeEvent(l.code, $event.target.checked)" [checked]="containsCode(l.code)"> {{l.code}}<br>
</div>

Get a value from a HTML form in a Angular 2 ag-grid

I have a form that appears in a modal in my HTML file and i would like to add the values i get form the form in a ag-grid array, and i have no idea how to do this.
This is my file.html
<template #addTrainContent let-c="close" let-d="dismiss">
<div class="modal-header">
<h4 class="modal-title">Ajouter un train</h4>
<button type="button" class="close" aria-label="Close" (click)="d('Cross click')">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<input type="radio" name="choiceDirection" /> Gauche
<input type="radio" name="choiceDirection" /> Droite
<input type="number" placeholder="Numéro de matériel" value="nMateriel"/>
<select>
<option>1</option>
<option>52</option>
<option>38</option>
</select>
<input type="checkbox" checked /> Créer dans l'ATS
</div>
<div class="modal-footer">
<button class="btn btn-lg btn-primary" (click)="c(createTrain())">Ajouter le train</button>
<button type="button" class="btn btn-secondary" (click)="c('Close click')">Annuler</button>
</div>
</template>
And i was adding a train with value i chose instead of the ones from the form, like that in my file.ts
createNewTrain() {
var newTrain = {
nMateriel: 97,
nRame: 42,
position: 'TB__BLOC_13',
direction: 'droite',
etat: 'mouvement',
vitesse: '24 km/h'
};
return newTrain;
}
createTrain() {
var newItem = this.createNewTrain();
this.gridOptions.api.addItems( [newItem] );
this.rowCount++;
}
How can i get the value from my form and put it in my ag-grid array?
Thank you for your help
Let's step through this example. Here is the initial setup:
//our root app component
import {Component, Directive, ElementRef} from 'angular2/core'
#Component({
selector: 'my-app',
directives: [],
providers: [],
template: `
<div>
<h2>Hello {{name}}</h2>
<label>Name</label>
<select [(ngModel)]="name" name="Select name" class="ui fluid search selection dropdown">
<option *ngFor="#n of names" [attr.value]="n">{{n}}</option>
</select>
<br>
<button (click)="print()">print</button>
</div>
`,
directives: []
})
export class App {
// name: string = "Jane";
names: string[] = ["John", "Paul", "George", "Ringo"]
print = () => console.log(this.name)
constructor() {
setTimeout(() => {
jQuery('.ui.dropdown').dropdown();
}, 1000);)
}
}
NOTE: MODEL refers to variables in the class App, CONTROLLER refers to functions in the class App, and VIEW refers to the HTML template.
The variable that is of most interest to us is name. Notice that it is currently commented out in the MODEL. However, I have a CONTROLLER that is able to print this.name. What is happening is that Angular notices that it is bound in the VIEW and so it decides to create it for us.
In the <h2> it is a one-way binding, meaning that it takes the value of what is in the MODEL. So if something were to change the value of name in the MODEL, Angular would update the VIEW with the new value.
In the Select there is a two-way binding, meaning that if the value of name in the VIEW gets updated, Angular will notify the MODEL that name is now a new value; Also, if something in the MODEL were to change name then the VIEW would get updated.
For example when you change the select to "Ringo", the MODEL gets updated, then the MODEL updates the VIEW so that the title reads "Hello Ringo"
Now if you uncomment name: string = "Jane", then you are basically setting a default value for name. You might also notice that the title will then read "Hello Jane" but the select remains blank. That is because "Jane" isn't one of the options in the select.
What this means for you:
In your VIEW bind each of your inputs to variables with [(ngModel)] for example:
<input [(ngModel)]="materiel" type="number" placeholder="Numéro de matériel" value="nMateriel"/>
Then in your CONTROLLER for creating a new train you will be able to use that variable as a reference:
createNewTrain() {
var newTrain = {
nMateriel: this.materiel,
nRame: 42,
position: 'TB__BLOC_13',
direction: 'droite',
etat: 'mouvement',
vitesse: '24 km/h'
};
return newTrain;
}
Nothing else is really needed, however I would strongly suggest to add some defaults into your TS file/MODEL for readability's sake and so that each of these variables will have a value:
// somewhere in your TS
materiel: number = 97
I solved my problem by doing this in my file.ts :
(I only changed it for nMateriel for the example)
createNewTrain() {
var newTrain = {
nMateriel: (<HTMLInputElement>document.getElementById("nMateriel")).value,
nRame: 42,
position: 'TB__BLOC_13',
direction: 'droite',
etat: 'mouvement',
vitesse: '24 km/h'
};
return newTrain;
}

Angular 2 : HTML property binding

I'm trying to understand the HTML bindings as I'm new to angular.
Can someone please explain the difference between the following syntax:
<!-- 1 -->
<button name1 = "name2" >test</button>
<!-- 2 -->
<button (name1) = "name2" >test</button>
<!-- 3 -->
<button [name1] = "name2" >test</button>
<!-- 4 -->
<button ([name1]) = "name2" >test</button>
I have seen above in multiple places but could not understand the purpose of each case.
Thank you for the help!
There are two different thinks.. bindings and events:
Here's a live-demo: https://plnkr.co/edit/gfJL9RCyYriqzP9zWFSk?p=preview
Binding
binds just a fixed string
<input value="test" />
one-way binding a fixed string with expression-syntax
<input [value]="'test'" />
one-way binding a variable test with expression-syntax
<input [value]="test" />
one-way binding a variable test
<input value="{{ test }}" />
two-way bindig the variable test to this input
<input [(ngModel)]="test" />
Events
bind click-event to our onClick-function
<button (click)="onClick($event)"></button>
official docs: https://angular.io/docs/ts/latest/guide/template-syntax.html
Here is a practical example of event-binding, string-interpolation, and property binding
import {Component} from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
firstString: string = ' This is using string interpolation coming from a variable in a component ';
secondString: string = 'This is using string interpolation coming from a method in a component ';
thirdString: string = 'This is using property-binding';
forthString: string= 'This is the string before you click';
returnsecondString () {
return this.secondString;
}
onClick(){
this.forthString= 'This is the string after you click'
}
}
<div class="col-lg-1">
<UL class="list-group-item-info">
<!--Format for string interpolation: {{ a string from type script or any string }} -->
<!--Format for property binding: []= "" -->
<!--format for event binding: ()="" -->
<li><p> This is an example of string interpolation : {{firstString}}</p></li>
<li><p> This is an example of string interpolation : {{returnsecondString()}}</p></li>
<li><p [innerHTML]="thirdString"></p></li>
<button class="btn btn-primary" (click)="onClick()"> Click here for Event Binding</button> <hr>
<li><p>{{forthString}}</p></li>
</UL>
</div>