how to loop through array using ngFor in angular 11 - html

i have a api responce like
res.attribute
0: {relate_id: 15, pid: 9, attr_slug: "size", items: "s,m,l", id: 1, …}
1: {relate_id: 16, pid: 9, attr_slug: "color", items: "yellow", id: 2, …}
length: 2
i need two set of radio buttons for size and color..i achived that through
<section class="example-section" *ngFor="let attr of Attr" >
<mat-radio-button *ngFor="let checkbox of attr.items.split(',')" class="example-margin">{{checkbox}}</mat-radio-button>
</section>
but, every radio button is like same name(only one from all 4 (s,m,l,yellow) can be selected)
what i am expecting is two different set of radio buttons like size and color

You can bind the input property name with the radio type you want.
[name]="attr.attr_slug"
This way it has a radio group that will be group by your slug name.
<section class="example-section" *ngFor="let attr of Attr" >
<mat-radio-button *ngFor="let checkbox of attr.items.split(',')"
[name]="attr.attr_slug"
class="example-margin">{{checkbox}}</mat-radio-button>
</section>

You should be using a mat-radio-group to group up the radio buttons inside. Try it like below :
<section class="example-section" *ngFor="let attr of Attr" >
<mat-radio-group [name]="attr.attr_slug">
<mat-radio-button *ngFor="let checkbox of attr.items.split(',')" class="example-margin">{{checkbox}}</mat-radio-button>
</mat-radio-group>
</section>
Edit:
For getting the desired "s,yellow" or "m,yellow" output you can do a workaround below.
Since your slugs are size and color. Define a model has those properties in your component:
model = {
size = "",
color = "",
}
Bind the radio group to the corresponding properties like below
<mat-radio-group [name]="attr.attr_slug" [value]="model[attr.attr_slug]">
So later in your component get your combined value like this :
const finalValue = `${this.model.size}, ${this.model.color}`

As #Eldar said you need to include mat-radio-button inside mat-radio-group then you have two different sets of radio button groups. You can refer to the Angular Material docs here.

Related

Is it possible to use [maxSelectedLabels] property in an ngif condition?

I'm using Prime NG Multiselect component and I want to show selectedItemsLabel="{0} Selected" when there are more than 3 selected checkboxes, but if all of the checkboxes are selected, then selectedItemsLabel="All" should be shown in the placeholder.
I'm new to angular and I been following documentation of this MultiSelect component, yet this doesn't show the options to able to implement multiple conditions of properties, and I was wondering if it's even possible.
Example of how It might be
<ng-template pTemplate="filter" let-value let-filter="filterCallback">
<p-multiSelect
[ngModel]="value"
[options]="routeOptions"
placeholder="Any"
(onChange)="filter($event.value)"
optionLabel="name"
selectedItemsLabel="{0} selected"
[maxSelectedLabels]="3"
>
<ng-template let-option pTemplate="item">
<div>
<span class="p-ml-1">{{ option.name }}</span>
</div>
<div *ngIf="[maxSelectedLabels="routeOptions.length - 1"] Then selectedItemsLabel="All"></div>
</ng-template>
</p-multiSelect>
</ng-template>
Yes, you can. First give the component a ref with # like this:
<p-multiSelect
#myMultiSelect
[ngModel]="value"
[options]="routeOptions"
placeholder="Any"
(onChange)="filter($event.value)"
optionLabel="name"
selectedItemsLabel="{0} selected"
[maxSelectedLabels]="3"
>
.......
Then you have access to it:
<div *ngIf="myMultiSelect.maxSelectedLabels === routeOptions.length - 1">Im visible</div>
If the option of maxSelectedLables is the length - 1 of routeOptions then the div is visible. That is how ngIf works
BUT
Thats not what you want. You wanna set the selectedItemsLabel property. And you have it not understand correctly. You set the maxSelectedLables to 3 as example AND set the selectedItemsLabel directly, too! The text of the selectedItemsLabel will be only shown if needed (controlled by the component).
<h5>Basic</h5>
<p-multiSelect #meins [options]="cities" [(ngModel)]="selectedCities" defaultLabel="Select a City" optionLabel="name"
[maxSelectedLabels]="3" selectedItemsLabel="{0} items selected">
</p-multiSelect>
Look here the Stackblitz!
The documentation of ng-prime will helps, too and say:
selectedItemsLabel: Label to display after exceeding max selected labels e.g. ({0} items selected), defaults "ellipsis" keyword to indicate a text-overflow.
UPDATE 18.02.2023
You wanna show "ALL" only if all items selected. So add the onChange event and bind the selectedItemsLabel. Why binding? It has some problems with a condition in it. So we make it inside the code.
HTML
<p-multiSelect [options]="cities" [(ngModel)]="selectedCities" defaultLabel="Select a City" optionLabel="name"
[maxSelectedLabels]="2" [selectedItemsLabel]="bindTest" (onChange)="onChange()">
</p-multiSelect>
Inside the code do the follow with onChange:
Code
onChange() {
if (this.selectedCities.length === this.cities.length) {
this.bindTest = "ALL";
this.changeRef.detectChanges();
}
else {
this.bindTest = "{0} items selected";
this.changeRef.detectChanges();
}
}
Now it works how you wish. One important thing: We use changeRef.detectChanges(); Without this the components selected text will not changing directly. Import it in the components constructor:
constructor(
private countryService: CountryService,
private primengConfig: PrimeNGConfig,
private changeRef: ChangeDetectorRef
) {
.....
I made a Stackblitz of the problem: https://stackblitz.com/edit/primeng-tablefilter-demo-ipt7y1?file=src%2Fapp%2Fapp.component.html,src%2Fapp%2Fapp.component.ts
(Expand the page to the left to view the column filter in the stackblitz)
If you notice, the clear button doesn't clear the selected textbox anymore. After some testing it seems the [(ngModel)] breaks it, I think it got to do something with two-way binding? It is not shown in the stackblitz, but if you include
(onChange)="filter($event.value)"
the clear button still clears the filter from the table, but not in the selected textbox.
I found out that there is this property
[showClear]="true"
That adds an X at the end of the textbox that clears it out. Sadly, the styling/positioning is not what I need.
What could be the ways to fix the clear button ? Add a ts function to clear out the selected values? If so, how to bind it to the clear button because it is generated from
<p-columnFilter
display="menu"
menu property and I had no luck to find the way to try add/change functionality to that button.

Conditionally Display Element in Angular 7

I have a <select> element in my Angular component that, based on the selected item, returns the identifier of that item.
I want to know how I would be able to conditionally display a <div> when the identifier is either not undefinded or 0.
I have the following code
<div *ngIf="this.id != undefined || this.id != null"></div>
However, it still display's the element even though the condition should theoretically be satisfied as, at the point of the <select> not having a value, should be undefined.
Are there any suggestions that would conditionally display an element using the *ngIf directive based on an id returned from a <select>?
It depends on how the select is set up. For eg., if it's of the following form
<select #sel (change)="change(sel.value)" [(ngModel)]="id">
<option [ngValue]="undefined">Undefined</option>
<option *ngFor="let option of options" [ngValue]="option">{{ option }}</option>
</select>
with options = [ 0, 1, 2, 3, 4, 5 ];
And if id is declared as id: any; in the controller, then explicit checks to undefined and null isn't required. You could do null check just with the following
<div *ngIf="id && id !== 0; else undefinedBlock">
ID is defined: {{ id }}
</div>
<ng-template #undefinedBlock>
ID is undefined
</ng-template>
Use ng-template when you want to show something depending on some condition. See example
Instead of:
<div *ngIf="isDisplayed">Item 1</div>
<div *ngIf="!isDisplayed">Item 2</div>
You can do this:
<div *ngIf="isDisplayed; else showItem2">Item 1</div>
<ng-template #showItem2>
Item 2
</ng-template>
I want to know how I would be able to conditionally display a <div>
when the identifier is either undefinded or 0.
First of all make sure this is not undefined in all cases. then you can use sth like this :
<div *ngIf="this.id"></div>
Look at this fiddle which you can manually set id to null or remove it (e.g undefined)

Change selected mat-chips within/after selectionChange

The concept is that I want to filter displayed information on a page based on which mat-chips are selected.
The HTML:
<mat-chip-list [multiple]="true">
<mat-chip
class="item-filter-mat-chip"
*ngFor="let itemFilter of itemFilters"
[selectable]="true"
[selected]="itemFilter.selected"
[value]="itemFilter"
(selectionChange)="updateItemFilter($event)"
(click)="chip.toggleSelected()"
#chip="matChip">
{{itemFilter.displayValue}}
</mat-chip>
</mat-chip-list>
The TypeScript item:
export interface ItemFilter {
itemType: ItemType[];
displayValue: string;
selected: boolean;
}
However I want one of the mat-chips to be the "default" that is selected if all other chips are not selected. However it seems like the logic to do the selection change has to happen in updateItemFilter, which then creates an ExpressionChangedAfterItHasBeenCheckedError. This is because I'm trying to change the selection values inside of the selectionChange method called.
The situation is this. The default filter is selected. Once a different filter is selected, the default filter should be de-selected. Multiple other filters can be selected. If the default filter is selected, all other filters should be de-selected.
After digging in, the fix appears to be no longer use (selectionChange) on the mat-chip and instead change the selection AND update the filter inside a custom (click) method.
<mat-chip-list [multiple]="true">
<mat-chip
class="item-filter-mat-chip"
*ngFor="let itemFilter of itemFilters"
[selectable]="true"
[selected]="itemFilter.selected"
[value]="itemFilter"
(click)="updateItemFilter(chip)"
#chip="matChip">
{{itemFilter.displayValue}}
</mat-chip>
</mat-chip-list>

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.

How to get multiple radio buttons to work in angular2?

I have a array of json, something similar to this:
questions =
[
{
title: Your section is?
choices: [
{
id: 1,
label: "TestA"
},
{
id=2,
label: "TestB"
}
]
},
{
title: Your major is?
choices: [
{
id=3,
label: "Medicine"
},
{
id=4,
label: "Engineering"
}
]
}
]
My html:
<div *ngFor="let choice of questions">
<div *ngFor="let choice of questions.choices;let i=index">
<div class="radio-group" (click)="onSelectChoice(choice.id)">
<input type="radio" class="hide" name="choiceElements" [value]="choice.id" id="choice.label" formControlName="choiceElements">
<label [class.selected]="choice.id === selctedRadio" for="{{choice.label}}" class="" >{{choice.label}}</label>
</div>
</div>
</div>
My TS:
selctedRadio: '';
onSelectChoice(selctedChoice: any){
this.selctedRadio = selctedChoice;
}
So, in html I need two questions, each question having two buttons, for each question I should be able to select one radio button.
But in my case, I am able to select only one radio button and when I go to second question the selected first question becomes unselected.
Let me know how I can be able to select one radio answer from each question.
Your radio buttons must have the same name if and only if they belong to the same group.
You will have to find a way to create a unique-per-group name.
By the way, this is not angular specific, it's just how radio buttons work in plain HTML.
however, for more info about how to handle radio buttons in angular, you can check this :
Angular2 ReactiveFormsControl: how to bind radio buttons?
Angular2 - Radio Button Binding