diff --git a/src/app/components/multiselect/multiselect.interface.ts b/src/app/components/multiselect/multiselect.interface.ts index 4721c38be4e..ebb1ee5e904 100644 --- a/src/app/components/multiselect/multiselect.interface.ts +++ b/src/app/components/multiselect/multiselect.interface.ts @@ -196,8 +196,31 @@ export interface MultiSelectTemplates { filtericon(): TemplateRef; /** * Custom check icon template. + * @deprecated Use headercheckboxicon or itemcheckboxicon instead. */ checkicon(): TemplateRef; + /** + * Custom check icon template for the header checkbox. + */ + headercheckboxicon(context: { + /** + * Defines if all items are selected. + */ + $implicit: boolean; + /** + * Defines if items are partially selected. + */ + partialSelected: boolean; + }): TemplateRef<{ $implicit: boolean; partialSelected: boolean }>; + /** + * Custom check icon template for the item checkbox. + */ + itemcheckboxicon(context: { + /** + * Selection status of the item. + */ + $implicit: boolean; + }): TemplateRef<{ $implicit: boolean }>; /** * Custom close icon template. */ diff --git a/src/app/components/multiselect/multiselect.ts b/src/app/components/multiselect/multiselect.ts index 76de3be2c45..8c25e653bb5 100755 --- a/src/app/components/multiselect/multiselect.ts +++ b/src/app/components/multiselect/multiselect.ts @@ -47,6 +47,7 @@ import { ChevronDownIcon } from 'primeng/icons/chevrondown'; import { Nullable } from 'primeng/ts-helpers'; import { AutoFocusModule } from 'primeng/autofocus'; import { MultiSelectRemoveEvent, MultiSelectFilterOptions, MultiSelectFilterEvent, MultiSelectBlurEvent, MultiSelectChangeEvent, MultiSelectFocusEvent, MultiSelectLazyLoadEvent, MultiSelectSelectAllChangeEvent } from './multiselect.interface'; +import { MinusIcon } from 'primeng/icons/minus'; export const MULTISELECT_VALUE_ACCESSOR: any = { provide: NG_VALUE_ACCESSOR, @@ -78,9 +79,10 @@ export const MULTISELECT_VALUE_ACCESSOR: any = {
- + - + +
@@ -117,6 +119,8 @@ export class MultiSelectItem { @Input() checkIconTemplate: TemplateRef | undefined; + @Input() itemCheckboxIconTemplate: TemplateRef | undefined; + @Output() onClick: EventEmitter = new EventEmitter(); @Output() onMouseEnter: EventEmitter = new EventEmitter(); @@ -263,11 +267,17 @@ export class MultiSelectItem { [attr.aria-checked]="allSelected()" [ngClass]="{ 'p-highlight': allSelected(), 'p-focus': headerCheckboxFocus, 'p-disabled': disabled || toggleAllDisabled }" > - - + + + + + + + +
@@ -349,6 +359,7 @@ export class MultiSelectItem { [disabled]="isOptionDisabled(option)" [template]="itemTemplate" [checkIconTemplate]="checkIconTemplate" + [itemCheckboxIconTemplate]="itemCheckboxIconTemplate" [itemSize]="scrollerOptions.itemSize" [focused]="focusedOptionIndex() === getOptionIndex(i, scrollerOptions)" [ariaPosInset]="getAriaPosInset(getOptionIndex(i, scrollerOptions))" @@ -965,6 +976,10 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft dropdownIconTemplate: TemplateRef | undefined; + itemCheckboxIconTemplate: TemplateRef | undefined; + + headerCheckboxIconTemplate: TemplateRef | undefined; + public headerCheckboxFocus: boolean | undefined; filterOptions: MultiSelectFilterOptions | undefined; @@ -1196,6 +1211,11 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft case 'checkicon': this.checkIconTemplate = item.template; + console.warn('checkicon is deprecated and will removed in v18. Use itemcheckboxicon or headercheckboxicon templates instead.'); + break; + + case 'headercheckboxicon': + this.headerCheckboxIconTemplate = item.template; break; case 'filtericon': @@ -1218,6 +1238,10 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft this.dropdownIconTemplate = item.template; break; + case 'itemcheckboxicon': + this.itemCheckboxIconTemplate = item.template; + break; + default: this.itemTemplate = item.template; break; @@ -1872,6 +1896,11 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft } } + if (this.partialSelected()) { + this.selectedOptions = null; + this.cd.markForCheck(); + } + this.onChange.emit({ originalEvent: event, value: this.value }); DomHandler.focus(this.headerCheckboxViewChild?.nativeElement); this.headerCheckboxFocus = true; @@ -1932,6 +1961,10 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft return this.selectAll !== null ? this.selectAll : ObjectUtils.isNotEmpty(this.visibleOptions()) && this.visibleOptions().every((option) => this.isOptionGroup(option) || this.isOptionDisabled(option) || this.isSelected(option)); } + partialSelected() { + return this.selectedOptions && this.selectedOptions.length > 0 && this.selectedOptions.length < this.options.length; + } + /** * Displays the panel. * @group Method @@ -2160,7 +2193,7 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft } @NgModule({ - imports: [CommonModule, OverlayModule, SharedModule, TooltipModule, RippleModule, ScrollerModule, AutoFocusModule, CheckIcon, SearchIcon, TimesCircleIcon, TimesIcon, ChevronDownIcon, CheckIcon], + imports: [CommonModule, OverlayModule, SharedModule, TooltipModule, RippleModule, ScrollerModule, AutoFocusModule, CheckIcon, SearchIcon, TimesCircleIcon, TimesIcon, ChevronDownIcon, CheckIcon, MinusIcon], exports: [MultiSelect, OverlayModule, SharedModule, ScrollerModule], declarations: [MultiSelect, MultiSelectItem] }) diff --git a/src/app/showcase/doc/apidoc/index.json b/src/app/showcase/doc/apidoc/index.json index 75de354d026..e511b759265 100644 --- a/src/app/showcase/doc/apidoc/index.json +++ b/src/app/showcase/doc/apidoc/index.json @@ -16546,7 +16546,30 @@ "parent": "multiselect", "name": "checkicon", "parameters": [], - "description": "Custom check icon template." + "description": "Custom check icon template.", + "deprecated": "Use headercheckboxicon or itemcheckboxicon instead." + }, + { + "parent": "multiselect", + "name": "headercheckboxicon", + "parameters": [ + { + "name": "context", + "type": "{\n \t $implicit: boolean, // Defines if all items are selected.\n \t partialSelected: boolean, // Defines if items are partially selected.\n }" + } + ], + "description": "Custom check icon template for the header checkbox." + }, + { + "parent": "multiselect", + "name": "itemcheckboxicon", + "parameters": [ + { + "name": "context", + "type": "{\n \t $implicit: boolean, // Selection status of the item.\n }" + } + ], + "description": "Custom check icon template for the item checkbox." }, { "parent": "multiselect", diff --git a/src/app/showcase/doc/multiselect/virtualscrolldoc.ts b/src/app/showcase/doc/multiselect/virtualscrolldoc.ts index 56ef5821fbe..f624aafef33 100644 --- a/src/app/showcase/doc/multiselect/virtualscrolldoc.ts +++ b/src/app/showcase/doc/multiselect/virtualscrolldoc.ts @@ -1,5 +1,6 @@ -import { Component } from '@angular/core'; +import { Component, ViewChild } from '@angular/core'; import { Code } from '../../domain/code'; +import { MultiSelect } from 'primeng/multiselect'; @Component({ selector: 'virtual-scroll-doc', @@ -23,13 +24,20 @@ import { Code } from '../../domain/code'; class="multiselect-custom-virtual-scroll" placeholder="Select Cities" (onSelectAllChange)="onSelectAllChange($event)" - (onChange)="onChange($event)" - > + #ms + > + + + + + ` }) export class VirtualScrollDoc { + @ViewChild('ms') ms: MultiSelect; + items = Array.from({ length: 100000 }, (_, i) => ({ label: `Item #${i}`, value: i })); selectedItems!: any[]; @@ -37,15 +45,10 @@ export class VirtualScrollDoc { selectAll: boolean = false; onSelectAllChange(event) { - this.selectedItems = event.checked ? [...this.items] : []; + this.selectedItems = event.checked ? [...this.ms.visibleOptions()] : []; this.selectAll = event.checked; } - onChange(event) { - const { value } = event; - if (value) this.selectAll = value.length === this.items.length; - } - code: Code = { basic: ``, + #ms +> + + + + +`, html: `
@@ -76,34 +84,37 @@ export class VirtualScrollDoc { class="multiselect-custom-virtual-scroll" placeholder="Select Cities" (onSelectAllChange)="onSelectAllChange($event)" - (onChange)="onChange($event)" - > + #ms + > + + + + +
`, typescript: ` -import { Component } from '@angular/core'; +import { Component, ViewChild } from '@angular/core'; +import { MultiSelect } from 'primeng/multiselect'; @Component({ selector: 'multi-select-virtual-scroll-demo', templateUrl: './multi-select-virtual-scroll-demo.html' }) export class MultiSelectVirtualScrollDemo { + @ViewChild('ms') ms: MultiSelect; + items = Array.from({ length: 100000 }, (_, i) => ({ label: \`Item #\${i}\`, value: i })) selectedItems!: any[]; - selectAll = false; + selectAll: boolean = false; onSelectAllChange(event) { - this.selectedItems = event.checked ? [...this.items] : []; + this.selectedItems = event.checked ? [...this.ms.visibleOptions()] : []; this.selectAll = event.checked; } - onChange(event) { - const { originalEvent, value } = event - if(value) this.selectAll = value.length === this.items.length; - } - }` }; }