Angular #Input array- how to reference different array object field names? - html

I want to setup a reusable dropdown menu whereby I pass an array of objecs to the #Input of my dropdown component and then update some labels in it.
The array fields will be different each time. One array might have a displayName string field, while another array will have a string called id as the field I want to reference, for example.
I'm not sure how to reference these on a per instance basis.
Dropdown HTML:
<ng-container *ngFor="let item of content">
<span class="button-label">{{item.whatever-the-field-is}}</span>
</ng-container>
Dropdown Component:
#Input() content: Array<any> = [];
Dropdown Instance:
<multi-button-dropdown [content]="(myArrayObservable$ | async)"></multi-button-dropdown>
Example Arrays:
users = [
{
id: 'afvnf102841-251',
username: 'Joe Bloggs'
}
...
]
members = [
{
displayName: 'Han Solo',
location: 'Space'
}
...
]
Question:
How do i setup the dropdown.html/component so that the <span> {{item....}} reference will be displayName for the members[] instance, id for the users[] instance and so on, passed in by another #Input value?

One quick way would be to use the keyvalue pipe inside the *ngFor to iterate over the object properties without knowing it's names.
<ng-container *ngFor="let item of content">
<span class="button-label" *ngFor="let prop of item | keyvalue">
{{ prop.key }} - {{ prop.value }}
</span>
</ng-container>

I figured out that I can make a new interface which sets out the label value, and map the Observable array object fields to this value before passing it into the component:
this.dropdownUsers = users.map(user => (
{
label: user.displayName
}
));
<multi-button-dropdown [content]="dropdownUsers"></multi-button-dropdown>

Related

Access an Array inside an Object with square brackets inside a ngFor

Basically, I've created a HTML that similar to the example :
<div *ngFor="let formElements of formTemplate">
<div *ngFor="let opt of staticEnumVals[formElements.testId]">
<!-- do smth here -->
</div>
</div>
Basically formTemplate is an Array with Objects, each Object has a property called "testId".
staticEnumVals is an Object thats build like that
{
"testId": [ {},{},{} ],
"testId2" [ {},{},{} ],
}
The keys "testId" and "testId2" are actual keys that match the Keys from formTemplate[i].testId.
Basically I want to iterate through an array out of my staticEnumVals and the array is selected dynamically based on the id from the first *ngFor
Basically im looking for an elegant way to achieve my second iteration, square brackets doesnt work.
I think my problem is clear enough, im sorry for the weird title.
Thanks in advance
After adding types to the staticEnumVals this worked for me.
#Component({
selector: 'test',
template: `
<div *ngFor="let formElements of formTemplate">
<div *ngFor="let opt of staticEnumVals[formElements.testId]">
{{opt.name}}
</div>
</div>
`
})
export class TestComponent {
private formTemplate: { testId: string }[] = [
{testId: '3'}, {testId: '2'}, {testId: '3'}
];
private staticEnumVals: { [id: string]: [any] } = {
'1': [{name: 'id1'}],
'2': [{name: 'id2'}],
'3': [{name: 'id3'}],
};
}

How to get multiple dynamic drop-down option values in one single list in Angular 7

I am creating a dynamic multiple dropdown in angualar 8. I am receiving list of list from backend and I am running through the list of list to generate multiple dynamic dropdown. Now I need to send selected option values from all the dropdown to backend again in Angular 8. I am unable to send all the value.
I am getting list in this format from which I am looping through to generate dynamic drop-down
cat_dropdown = [['A','B','C'],['1','2','3']]
Based on above list my html code generate two drop-downs one with options A,B,C and another with 1,2,3.
My HTML Code:
<form (ngSubmit)="segmentSelection()" #ff="ngForm">
<div id="userSelection" ngModelGroup="userData" #userData="ngModelGroup">
<div *ngFor="let first of cat_dropdown">
<mat-form-field>
<mat-label>Choose Segment Key</mat-label>
<mat-select id="selectme" name="segmentKey">
<mat-option *ngFor="let segment of first" [value]="segment">
{{segment}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</form>
My component.ts code:
import { NgForm } from '#angular/forms';
export class myComponent implements OnInit {
#ViewChild("ff", { static: true }) segmentData: NgForm;
plotselection = {
segmentKey: []
}
segmentSelection(){
this.plotselection.segmentKey = this.segmentData.value.userData.segmentKey;
fetch("http://localhost:5000/data-decomposition", {
method: "POST",
headers: {
"Content-Type": "application/json"
},body: JSON.stringify({
segmentKey: this.segmentData.value.userData.segmentKey,
})
}).then(res => res.json()).then(myjson => {
console.log(myjson)
})
}
Now in my .ts component I have a dictionary name "plotselection" where I have key name 'segmentKey' which I defined as empty list.
As I have 2 dropdown in frontend so thought that i will receive two values from frontend and I will send those as a list to backend. When I select option from both the dropdowns for example from 1st dropdown I choose 'B' and from 2nd '3' and submit my selection, then when I console log the response I could only see the value '3' in my list not 'B' and '3' together. How can I have both the value to the list.
Thank you, and looking for your suggestion...
For my easiness I have used Select control instead of mat-select control.
In the form I have given specific name by appending the index to control while looping.
Html
<div *ngFor="let first of cat_dropdown; let num = index">
<div>
<Label>Choose Segment Key</Label>
<Select id="selectme{{num}}" [value]="segment" name="segmentKey{{num}}" (change)="ChangeCall($event.target)">
<option *ngFor="let segment of first" >
{{segment}}
</option>
</Select>
</div>
</div>
So that there are two controls with respective selected values.
There is also alternate solution is use to Change event on the Select Control.

Angular: Show list in view with different object keys

I have the following JSON object:
header: {
first: {
title: {
name: "Test
}
},
second: {
title: {
name: "Test 2"
},
desc: {
name: "Description"
}
}
}
Now I want to show it in view like that:
How can I manage to do that in the view? Since the keys will vary every time. For example once you have header, another time main and so on... Something like JSONEditor, where you can edit JSON objects. But I want to create something like that with my own design. I tried with ngIf but it seems really difficult. I'd be really thankful for any suggestions or help.
You can use the KeyValuePipe to iterate over objects using ngFor.
<!-- app-your-node component -->
<div *ngFor="let item of object | keyvalue">
{{ title }}
<app-your-leaf *ngIf="yourLogicThatThisIsALeaf(item); else node"
[title]="item.key" [object]="item.value"><app-your-leaf>
<ng-template #node>
<app-your-node [title]="item.key" [object]="item.value"></app-your-node>
</ng-template>
</div>

Angular 6: How to build a simple multiple checkbox to be checked/unchecked by the user?

I am writing this post after having read several threads concerning this topic but no one of them gives me what I need. This post seems to have the solution but I do not have to read the checked values from the json.
All I need is to:
read countries from an array of objects
build dinamically a list of checkbox representing each country
user should check and uncheck each checkbox
bonus:
get the value of the checked input and send it outside the component
I know It might be really dumb to do but all I have accomplished untile now is to have a list of uncheckable checkboxes and nothing more.
Here is the code:
Template:
<div class="form-group">
<div *ngFor="let country of countries">
<input type="checkbox"
name="countries"
value="{{country.id}}"
[(ngModel)]="country"/>
<label>{{country.name}}</label>
</div>
</div>
And TS:
countries = [
{id: 1, name: 'Italia'},
{id: 2, name: 'Brasile'},
{id: 3, name: 'Florida'},
{id: 4, name: 'Spagna'},
{id: 5, name: 'Santo Domingo'},
]
I tried to use the reactive forms but that gave me more issues then template driven (surely because of bad implementation of mine).
Please, help me, I do not know where to bump my head anymore
Here is a working example, where you can observe that an additional 'checked' value is added to each country, and bound to the value of each checkbox with [(ngModel)].
Stackblitz live example
template:
<p>
Test checkboxes
</p>
<div *ngFor="let country of countries; let i = index;">
<input type="checkbox" name="country{{country.id}}" [(ngModel)]="countries[i].checked">
<label for="country{{country.id}}">{{country.name}}</label>
</div>
<button type="button" (click)="sendCheckedCountries()" *ngIf="countries">Click to send the selected countries (see your javascript console)</button>
<p *ngIf="!countries">loading countries, please wait a second...</p>
<p *ngIf="countries">Debug info : live value of the 'countries' array:</p>
<pre>{{ countries | json }}</pre>
component :
//...
export class AppComponent implements OnInit {
public countries: Country[];
constructor(private countryService: CountryService) {}
public ngOnInit(): void {
// loading of countries, simulate some delay
setTimeout(() => {
this.countries = this.countryService.getCountries();
}, 1000);
}
// this function does the job of sending the selected countried out the component
public sendCheckedCountries(): void {
const selectedCountries = this.countries.filter( (country) => country.checked );
// you could use an EventEmitter and emit the selected values here, or send them to another API with some service
console.log (selectedCountries);
}
}
To use some proper TypeScript, I made an interface Country :
interface Country {
id: number;
name: string;
checked?: boolean;
}
I hope you get the idea now.
Note : the checked value is not "automatically there" at the beginning, but it doesn't matter.
When not there, it is the same as undefined, and this will be treated as false both in the checkbox and in the function that reads which country is checked.
For the "sending value" part :
The button will output the selected value to the browser's console, with some filter similar to what #Eliseo's answer suggests (I just used full country objects instead of ids)
For "real usecase" situation, you could use Angular's EventEmitters and have your component "emit" the value to a parent component, or call some service function that will make a POST request of your values to another API.
Your countries like
{id: 1, name: 'Italia',checked:false},
Your html like
<div *ngFor="let country of countries">
<input type="checkbox" [(ngModel)]="country.checked"/>
<label>{{country.name}}</label>
</div>
You'll get an array like, e.g.
[{id: 1, name: 'Italia',checked:false},{id: 2, name: 'Brasile',checked:tue}..]
you can do
result=this.countries.filter(x=>x.checked).map(x=>x.id)
//result becomes [2,...]
I had an error using [(ngModel)]
In case it serves anyone, I have solved the problem changing
[(ngModel)]
to:
[checked]="countries[i].checked" (change)="countries[i].checked= !countries[i].checked"

How to Iterate JSON properties in TypeScript

My question is very simple, I have a following JSON Typescript Object and I like to Iterate trought the JSON properties
{"work_type":"Fabricación","work_type_resp":"Mesa","looking_for":"Relación Calidad/Precio","image":"https://s3-sa-east-1.amazonaws.com/online-quotation-images/153366018967.png","width":"22","high":"34","depth":"","modifications":"mod"}
The code used is the following angular TypeScript component:
export class DetailsOnlineQuoteModalComponent implements OnInit {
#Input() title;
#Input() values:string;
properties:JSON;
constructor(public activeModal: NgbActiveModal) { }
ngOnInit() {
this.properties=JSON.parse(this.values);
console.log(this.properties);
}
}
What I really need is to go through the key-value attributes of the JSON and show them in my HTML.
Many Thanks!
If you are using angular 6.1 use keyvalue pipe
<div *ngFor="let title of data | keyvalue">
{{title.key}}
</div>
For Angular 5
<div *ngFor="let key of dataKeys">
{{key}} ------------- {{data[key]}}
</div>
get dataKeys() { return Object.keys(this.data); }
Example:https://stackblitz.com/edit/keyvalue-pipe-qtaqnm
As per your comment, I'm assuming you want to do an ngFor on the HTML to display each one of the key-value pairs
<div *ngFor="let key of Object.keys(properties)">
{{properties[key]}} --> this is the value
</div>
You can get all the keys using Object.Keys and assign to a variable as follows,
this.properties=JSON.parse(this.values);
let response = Object.keys(this.propertie);
now you can use ngFor over it,
<div *ngFor="let key of response ">
{{properties[key]}}
</div>
component.ts
let obj = {"work_type":"Fabricación","work_type_resp":"Mesa","looking_for":"Relación Calidad/Precio","image":"https://s3-sa-east-1.amazonaws.com/online-quotation-images/153366018967.png","width":"22","high":"34","depth":"","modifications":"mod"}
this.keyOfObj = Object.keys(obj);
html
<div *ngFor="let key of keyOfObj ">
{{obj[key]}}
</div>
unfortunately seems to be NOT working (with keyvalue) with ANGULAR_9
see here for a comparison of full different way of doing: https://stackblitz.com/edit/angular9-iterate-on-object-attribute
otherwise the answer by defining a method to do the job is still working.