Angular8 PrimeNG multiselect disabled property is not working - html

I'm trying to integrate PrimeNG multi select, in that I want to disable some options.
I've used disabled property as mentioned in PrimeNG document but it's not working.
Here are a code snippet and options values:
<p-multiSelect [filter]="true" [virtualScroll]="true" [resetFilterOnHide]="true" optionLabel="label" [(ngModel)]="rowData[col.dataField]"
name="{{col.dataField}}_{{topIndex}}_{{rowIndex}}_{{colIndex}}" [options]="calculationVariables"
defaultLabel="Please Select" autoWidth="false" [style]="{'width':'100%'}" styleClass="priliminary-dorpdown-style {{rowData[col.dataField]?.length == 0 ? 'invalid-control': null}}">
<ng-template let-item pTemplate="selectedItem">
<span class="multicheck-label">{{item.label}}</span>
</ng-template>
<ng-template let-variable pTemplate="item">
<div pTooltip="{{variable.label}}" tooltipPosition="right">
<span class="multicheck-label">{{variable.label}}</span>
</div>
</ng-template>
</p-multiSelect>

You can also disable any item in primeng multiSelect using ng-template, click event and custom style as below:
Method that gets triggered on click event
onClick(disabled: boolean) {
if(disabled) {
event.stopPropagation();
}
}
Customizing the Primeng MultiSelect using ng-template and adding ng-style
<p-multiSelect optionLabel="label"
name="{{col.dataField}}_{{topIndex}}_{{rowIndex}}_{{colIndex}}"
defaultLabel="Please Select"
autoWidth="false"
[filter]="true"
[virtualScroll]="true"
[resetFilterOnHide]="true"
[(ngModel)]="rowData[col.dataField]"
[options]="calculationVariables"
[style]="{'width':'100%'}"
styleClass="priliminary-dorpdown-style {{rowData[col.dataField]?.length == 0 ? 'invalid-control': null}}">
<ng-template let-option pTemplate="item">
<div class="multicheck-label"
(click)="onClick(item.disabled)"
[ngStyle]="item.disabled? {'color': '#ccc', 'cursor': 'default'} : ''"> {{item.label}}
</div>
</ng-template>
<ng-template let-variable pTemplate="item">
<div pTooltip="{{variable.label}}" tooltipPosition="right">
<span class="multicheck-label">{{variable.label}}</span>
</div>
</ng-template>
</p-multiSelect>

In primeng 11 new property "optionDisabled" has introduced.
use case:
<p-multiSelect [options]="cities" [(ngModel)]="selectedCities" optionLabel="name" optionDisabled="inactive"></p-multiSelect>
export class MultiSelectDemo {
cities: City[];
selectedCities: City[];
constructor() {
this.cities = [
{name: 'New York', code: 'NY', inactive: false},
{name: 'Rome', code: 'RM', inactive: true},
{name: 'London', code: 'LDN', inactive: false},
{name: 'Istanbul', code: 'IST', inactive: true},
{name: 'Paris', code: 'PRS', inactive: false}
];
}
}
Particular options can be prevented from selection using the optionDisabled property.

Related

How can I display selectBox items in chips?

I want to display data in chips using selectBox, but I got a problem while displaying these items like this:
My TS:
selectedPointsForts: any[]=[];
listPointsForts: any[]=[];
SelectPointsForts() {
this.PointsFortsService.findAll().then((res) => {
this.listPointsForts= res.map(function(obj: any) {
return {
value: {
id: obj.id,
name: obj.libelle
},
label: obj.libelle
};
});
});
}
My HTML:
<p-multiSelect [options]="listPointsForts" [(ngModel)]=" selectedPointsForts" [selectionLimit]=3 [panelStyle]="{minWidth:'12em'}" [maxSelectedLabels]=2></p-multiSelect>
<p>Selected Cars: </p>
<p-chips [(ngModel)]=" selectedPointsForts" > </p-chips>
Can anyone help me to fix this problem !
You can place pTemplate in <p-chips> element to format the chip items' displayed output.
<p-chips [(ngModel)]="selectedPointsForts">
<ng-template let-item pTemplate="item">
{{ item.id }} - {{ item.name }}
</ng-template>
</p-chips>
Sample Solution on StackBlitz
Output
References
Chips (Custom Content)

ng select - multiple values - select same values more than once

is there a way to use ng select to have multiple selections and the possibility to have the same value/s more than once in the same selection?
I could only achieve multiple with each value possible to choose only once:
HTML code:
<ng-select [closeOnSelect]="false" [selectableGroup]="true" [items]="allowedValues"
[(ngModel)]="selectedValuesArray" [selectableGroupAsModel]="false"
(change)="raiseChangeEvent($event)" name="dropdown-element" [multiple]="true" [maxSelectedItems]="maxLength"
[clearable]="false">
<ng-template ng-option-tmp let-item="item">
<div class="option-line">
<p>{{item == null ? 'N/A' : item}}</p>
</div>
</ng-template>
</ng-select>
You could exploit the bindLabel and bindValue attributes.
suppose you pass in the following items:
allowedValues= [
{label: 1, value: 'first_0'},
{label: 2, value: 'second_0'}
]
Your HTML will look like this, mind the addition of bindLabel and bindValue, the change in (change) and the [hideSelected] attribute:
<ng-select [closeOnSelect]="false" [selectableGroup]="true" [items]="allowedValues"
[(ngModel)]="selectedValuesArray" [selectableGroupAsModel]="false"
(change)="raiseChangeEvent($event); addItem($event)" name="dropdown-element" [multiple]="true" [maxSelectedItems]="maxLength"
[clearable]="false" bindLabel="label" bindValue="value" [hideSelected]="true">
<ng-template ng-option-tmp let-item="item">
<div class="option-line">
<p>{{item == null ? 'N/A' : item}}</p>
</div>
</ng-template>
</ng-select>
Whenever an item is selected you could insert a new one in the list with the addItem() function. For example when the user selects 1, add {label: 1, value: 'first_1'} to the allowedValues. This way you will end up with an array of values that are unique, but the user is tricked into believing he is actually clicking the same items over and over again.

Angular 6 :material checkbox checked all checkbox in loop

In loop
<li *ngFor="let item of verticalList;let i=index;">
<mat-checkbox [(ngModel)]="checked" name="i">Checked</mat-checkbox>
</li>
I want to give each checkbox a different checked value. How to do it?
I don't know what is verticalList type, but id you use a list of object you could do something like this:
verticalList = [
{
name: 'foo',
checked: false
},
{
name: 'foo1',
checked: false
},
{
name: 'foo2',
checked: false
}
]
<li *ngFor="let item of verticalList;let i=index;">
<mat-checkbox [(ngModel)]="item.checked" name="i">Checked {{ item.name }}</mat-checkbox>
</li>

Angular: How to dynamically add components to parent Dashboard component?

I have two components. One is a dashboard of cards (created with ng generate #angular/material:material-dashboard --name=my-dashboard) where the cards are created like this:
<div class="grid-container">
<h1 class="mat-h1">Dashboard</h1>
<mat-grid-list cols="2" rowHeight="350px">
<mat-grid-tile *ngFor="let card of cards" [colspan]="card.cols" [rowspan]="card.rows">
<mat-card class="dashboard-card">
<mat-card-header>
<mat-card-title> {{card.title}}
<button mat-icon-button class="more-button" [matMenuTriggerFor]="menu" aria-label="Toggle menu">
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #menu="matMenu" xPosition="before">
<button mat-menu-item>Expand</button>
<button mat-menu-item>Remove</button>
</mat-menu>
</mat-card-title>
</mat-card-header>
<mat-card-content class="dashboard-card-content">
<div>{{ card.content }}</div>
</mat-card-content>
</mat-card>
</mat-grid-tile>
</mat-grid-list>
</div>
And is filled like that:
export class DashComponent {
cards = [
{ title: 'Character', cols: 2, rows: 1, content: '<app-character-sheet></app-character-sheet>' },
{ title: 'Card 2', cols: 1, rows: 1 },
{ title: 'Card 3', cols: 1, rows: 2 },
{ title: 'Card 4', cols: 1, rows: 1 }
];
}
I want to fill the cards with different components. But when I went and tried it like you can see above (with the content variable), the HTML didn't parse the selector. The card just hat the literal content: .
How can I dynamically fill my cards with components?
Cheers
If you really need to dynamically insert components, read this article.
Alternative solution is to use structural directives like ngIf or ngSwitchCase for the case where you have limited set of content options:
<mat-card-content class="dashboard-card-content">
<div *ngIf="card.content"><app-character-sheet></app-character-sheet></div>
</mat-card-content>
You can unsafely insert HTML without post processing (but it is not recommended):
<div [innerHTML]="card.content"></div>

How to toggle mat-expansion-panel with button click?

Is there any way in which I can expand a particular mat-expansion-panel by clicking an external button?
I have tried linking to the ID of the panel, but with no success...
<mat-expansion-panel id="panel1"> ... </>
...
<button (click)="document.getElementById('panel1').toggle()>Click me</button>
Here is my stackblitz code for example
My eventual plan is to use this method to open different panels within a list generated from an array: <mat-expansion-panel *ngFor="let d of data"> ...
In your html file:
<mat-expansion-panel [expanded]="panelOpenState">
<mat-expansion-panel-header>
<mat-panel-title>
TITLE
</mat-panel-title>
</mat-expansion-panel-header>
<p>BODY</p>
</mat-expansion-panel>
<button mat-raised-button (click)="togglePanel">TOGGLE</button>
In your TS file:
panelOpenState: boolean = false;
togglePanel() {
this.panelOpenState = !this.panelOpenState
}
If you use *ngFor to generate the expansion panels:
<mat-expansion-panel [expanded]="isOpen" *ngFor="let d of data">
<mat-expansion-panel-header>
{{ d.header }}
</mat-expansion-panel-header>
<p>{{ d.content }}</p>
</mat-expansion-panel>
<button mat-raised-button (click)="togglePanel">TOGGLE</button>
If you press the button all of the expanded panels opens
simultaneously.
To open only one panel with one button, add a "expanded" property to the data array for each element like this:
data = [
{id:1, header:'HEADER 1', content:'CONTENT 1', expanded: false},
{id:2, header:'HEADER 2', content:'CONTENT 2', expanded: false},
{id:3, header:'HEADER 3', content:'CONTENT 3', expanded: false},
{id:4, header:'HEADER 4', content:'CONTENT 4', expanded: false},
]
Then in your template:
<mat-expansion-panel [(ngModel)]="d.expanded"
[expanded]="d.expanded" *ngFor="let d of data" ngDefaultControl>
<mat-expansion-panel-header>
<button (click)="toggle(d.expanded)">TOGGLE</button>
{{ d.header }}
</mat-expansion-panel-header>
<p>{{ d.content }}</p>
</mat-expansion-panel>
And the method raised by the button click:
toggle(expanded) {
expanded = !expanded;
}
<mat-expansion-panel [disabled]="true"
#mep="matExpansionPanel"
*ngFor="let foo of list">
<mat-expansion-panel-header>
<button (click)="mep.expanded = !mep.expanded">Toggle</button>
</mat-expansion-panel-header>
<p>Text</p>
</mat-expansion-panel>
Use two-way binding on the expanded attribute of mat-expansion-panel. Here is an example live in StackBlitz:
https://stackblitz.com/edit/angular-gtsqg8
<button (click)='xpandStatus=xpandStatus?false:true'>Toggle it</button>
<p>
<mat-expansion-panel [(expanded)]="xpandStatus">
<mat-expansion-panel-header>
<mat-panel-title>This an expansion panel</mat-panel-title>
<mat-panel-description>xpandStatus is {{xpandStatus}}</mat-panel-description>
</mat-expansion-panel-header>
Two-way binding on the expanded attribute gives us a way to store and manipulate the expansion status.
</mat-expansion-panel>
</p>
You can use the method toggle().
First give the element an id.
<mat-expansion-panel #matExpansionPanel>
Next, access the element from javascript. Import necessary libraries (MatExpansionPanel, ViewChild)
#ViewChild(MatExpansionPanel, {static: true}) matExpansionPanelElement: MatExpansionPanel;
Lastly, call the toggle function
this.matExpansionPanelElement.toggle(); //open(), close()
<mat-nav-list>
<mat-expansion-panel *ngFor="let row of rows" #mep="matExpansionPanel">
<mat-expansion-panel-header>
{{row}}
</mat-expansion-panel-header>
<h2>Test</h2>
<button (click)="mep.toggle()">Toggle</button>
</mat-expansion-panel>
</mat-nav-list>
Working Example:
https://stackblitz.com/edit/mat-expansion-panel-vymjsq?file=app%2Fexpansion-overview-example.html
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<mat-accordion displayMode="flat" multi class="mat-table">
<section matSort class="mat-elevation-z8 mat-header-row">
<span class="mat-header-cell" mat-sort-header="vesselName"></span>
<span class="mat-header-cell" mat-sort-header="vesselName">d</span>
</section>
<mat-expansion-panel [disabled]="true" #mep="matExpansionPanel"
*ngFor="let d of data">
<mat-expansion-panel-header>
<span class="mat-cell" (click)="mep.expanded = !mep.expanded">
<mat-icon class="icon" *ngIf="!mep.expanded">expand_more</mat-icon>
<mat-icon class="icon" *ngIf="mep.expanded">expand_less</mat-icon>
</span>
<span (click)="dClicked(d)" class="mat-cell">{{d.dataSet}}</span>
</mat-expansion-panel-header>
<div><pre>{{d | json}}</pre></div>
</mat-expansion-panel>
<div class="well" *ngIf="!d || d.length == 0">
<p>There are no d for this.</p>
</div>
</mat-accordion>
html:
<mat-accordion >
<mat-expansion-panel #first="matExpansionPanel">
<mat-expansion-panel-header>
<mat-panel-title>...</mat-panel-title>
</mat-expansion-panel-header>
...
</mat-expansion-panel>
<mat-expansion-panel #second="matExpansionPanel" expanded="true">
<mat-expansion-panel-header>
<mat-panel-title>...</mat-panel-title>
</mat-expansion-panel-header>
...
</mat-expansion-panel>
</mat-accordion>
<button (click)="doSomething(first, second)">Click</button>
ts:
import { Component } from '#angular/core';
import { MatExpansionPanel } from '#angular/material';
#Component({
selector: 'app-home',
templateUrl: './home.component.html'
})
export class HomeComponent {
doSomething(first: MatExpansionPanel, second: MatExpansionPanel) {
if (first.expanded ) { // check if first panel is expanded
first.close(); // close first panel
second.open(); // open second panel
// ...
}
}
}
Read more