PrimeNG dropdown - disable certain SelectItems
Asked Answered
M

2

7

Is there an option to disable some of PrimeNG's dropdown items (SelectItems)?

I notice this discussion, is something changed?

Madaras answered 9/5, 2017 at 14:54 Comment(0)
R
8

here is my workaround:

1) extend original SelectItem's interface (reference) with disabled property, so merged interface will look like

interface SelectItem {
  label: string;
  value: any;
  disabled: boolean;
}

this may be done by declaring new interface with the same name:

interface SelectItem {
  disabled: boolean;
}

2) based on p-dropdown component's template, modify this part of template:

<li *ngFor="let option of optionsToDisplay;let i=index" 
    [ngClass]="{'ui-dropdown-item ui-corner-all':true, 'ui-state-highlight':(selectedOption == option), 
                        'ui-dropdown-item-empty':!option.label||option.label.length === 0}"
    (click)="onItemClick($event, option)">
  <span *ngIf="!itemTemplate">{{option.label||'empty'}}</span>
  <ng-template [pTemplateWrapper]="itemTemplate" 
               [item]="option" 
               *ngIf="itemTemplate"></ng-template>
</li>

by adding disabled: option.disabled to li's ngClass directive, so when option is set to disabled, 'disabled' CSS class will be added to the il element. Also, onItemClick($event, option) should not be triggered by clicking on disabled options, and itemClick flag should be set to true, which will prevent dropdown closing. This can be achieved by rewriting the click function to

(click)="!option.disabled && onItemClick($event, option) || itemClick = true"

dropdown closing is done by onMouseclick($event) function, which has following condition:

if (!this.itemClick) {
  ...
}

so, setting itemClick flag true for disabled options will prevent dropdown closing when clicking on disabled items.

This may be done by using metadata reflection API. Import Dropdown class and get its metadata:

import { DropdownModule, Dropdown, SelectItem } from 'primeng/primeng';

...

// modify dropdown component's template
Reflect.getMetadata('annotations', Dropdown).forEach(annotation => {
  if (annotation.constructor.name === 'DecoratorFactory') {
    // add 'disabled' CSS class for disabled options
    annotation.template = annotation.template.replace("'ui-dropdown-item ui-corner-all':true, ", "'ui-dropdown-item ui-corner-all':true, disabled: option.disabled, ");
    // do not trigger click function on disabled options and set itemClick flag to prevent dropdown closing
    annotation.template = annotation.template.replace('(click)="onItemClick($event, option)"', '(click)="!option.disabled && onItemClick($event, option) || itemClick = true"');
  }
}); 

3) add desired CSS for disabled items, for example:

.ui-dropdown-item.ui-corner-all.disabled {
  opacity: 0.3;
  cursor: not-allowed;
}

That is it :) Tested on [email protected]

plunker: https://plnkr.co/edit/0Pqq565BPowABUauW7Y7

Rodeo answered 27/7, 2017 at 23:32 Comment(6)
It's perfect!. Thank so muchHotpress
it may not work as expected with AOT builds, so check it carefully when using AOT. I will post update to my answer when will have a chance to check itRodeo
We "extract" the dropdown component and edit it in local. So now for dropdowns we use our own component based in the primng component. (Only need to changes all his references like ../shared/common, etc.)Hotpress
My dropdown is not displayed in page load, it is loaded when another drop down is selected. What I have to do to achieve this in that case?Rascon
please create a olunker showing your issue and I will try to help with non-metadata solutionRodeo
The plunker doesn't seems to be working @Rodeo plnkr.co/edit/0Pqq565BPowABUauW7Y7Ration
S
14

You can also disable any item in primeng dropdown using ng-template, click event and custom style as below:

    cars: any[];
    selectedCar: string;
  1. Initialize the cars array of object that is essentially an extension of Interface SelectItem with added property disabled: boolean

     ngOnInit(): void {
      this.cars = [];
      this.cars.push({label: 'Audi', value: 'Audi'});
      this.cars.push({label: 'BMW', value: 'BMW'});
      this.cars.push({label: 'Fiat', value: 'Fiat', disabled: true});
      this.cars.push({label: 'Ford', value: 'Ford'});
      this.cars.push({label: 'Honda', value: 'Honda', disabled: true});
      this.cars.push({label: 'Jaguar', value: 'Jaguar'});
      this.cars.push({label: 'Mercedes', value: 'Mercedes'});
      this.cars.push({label: 'Renault', value: 'Renault'});
      this.cars.push({label: 'VW', value: 'VW'});
      this.cars.push({label: 'Volvo', value: 'Volvo'});
     }
    
  2. Method that gets triggered on click event

     onClick(disabled: boolean) {
             if(disabled) {
                 event.stopPropagation();
             }
         }
    
  3. Customizing the Primeng Dropdown using ng-template and adding ng-style

     <p-dropdown [options]="cars" [(ngModel)]="selectedCar" [style]="{'width':'150px'}">
             <ng-template let-option pTemplate="item">
                 <div>
                     <div (click)="onClick(option.disabled)" [ngStyle]="option.disabled? {'color': '#ccc', 'cursor': 'default'} : ''"> {{option.label}} </div>
                 </div>
             </ng-template>
         </p-dropdown>
    

Credit: ogousa (primeng forum)

Shill answered 22/3, 2018 at 13:24 Comment(2)
solution is awesome but require some changes in default style that I did and it's working fineRetch
to expand on what @Retch said. You can use ngClass to add "disabled" class on the div. In CSS, clear default padding, hover, highlight styles from .ui-list-item, and then apply them to that div instead.Matthei
R
8

here is my workaround:

1) extend original SelectItem's interface (reference) with disabled property, so merged interface will look like

interface SelectItem {
  label: string;
  value: any;
  disabled: boolean;
}

this may be done by declaring new interface with the same name:

interface SelectItem {
  disabled: boolean;
}

2) based on p-dropdown component's template, modify this part of template:

<li *ngFor="let option of optionsToDisplay;let i=index" 
    [ngClass]="{'ui-dropdown-item ui-corner-all':true, 'ui-state-highlight':(selectedOption == option), 
                        'ui-dropdown-item-empty':!option.label||option.label.length === 0}"
    (click)="onItemClick($event, option)">
  <span *ngIf="!itemTemplate">{{option.label||'empty'}}</span>
  <ng-template [pTemplateWrapper]="itemTemplate" 
               [item]="option" 
               *ngIf="itemTemplate"></ng-template>
</li>

by adding disabled: option.disabled to li's ngClass directive, so when option is set to disabled, 'disabled' CSS class will be added to the il element. Also, onItemClick($event, option) should not be triggered by clicking on disabled options, and itemClick flag should be set to true, which will prevent dropdown closing. This can be achieved by rewriting the click function to

(click)="!option.disabled && onItemClick($event, option) || itemClick = true"

dropdown closing is done by onMouseclick($event) function, which has following condition:

if (!this.itemClick) {
  ...
}

so, setting itemClick flag true for disabled options will prevent dropdown closing when clicking on disabled items.

This may be done by using metadata reflection API. Import Dropdown class and get its metadata:

import { DropdownModule, Dropdown, SelectItem } from 'primeng/primeng';

...

// modify dropdown component's template
Reflect.getMetadata('annotations', Dropdown).forEach(annotation => {
  if (annotation.constructor.name === 'DecoratorFactory') {
    // add 'disabled' CSS class for disabled options
    annotation.template = annotation.template.replace("'ui-dropdown-item ui-corner-all':true, ", "'ui-dropdown-item ui-corner-all':true, disabled: option.disabled, ");
    // do not trigger click function on disabled options and set itemClick flag to prevent dropdown closing
    annotation.template = annotation.template.replace('(click)="onItemClick($event, option)"', '(click)="!option.disabled && onItemClick($event, option) || itemClick = true"');
  }
}); 

3) add desired CSS for disabled items, for example:

.ui-dropdown-item.ui-corner-all.disabled {
  opacity: 0.3;
  cursor: not-allowed;
}

That is it :) Tested on [email protected]

plunker: https://plnkr.co/edit/0Pqq565BPowABUauW7Y7

Rodeo answered 27/7, 2017 at 23:32 Comment(6)
It's perfect!. Thank so muchHotpress
it may not work as expected with AOT builds, so check it carefully when using AOT. I will post update to my answer when will have a chance to check itRodeo
We "extract" the dropdown component and edit it in local. So now for dropdowns we use our own component based in the primng component. (Only need to changes all his references like ../shared/common, etc.)Hotpress
My dropdown is not displayed in page load, it is loaded when another drop down is selected. What I have to do to achieve this in that case?Rascon
please create a olunker showing your issue and I will try to help with non-metadata solutionRodeo
The plunker doesn't seems to be working @Rodeo plnkr.co/edit/0Pqq565BPowABUauW7Y7Ration

© 2022 - 2024 — McMap. All rights reserved.