Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/primefaces/primeng
Browse files Browse the repository at this point in the history
  • Loading branch information
cetincakiroglu committed Nov 17, 2023
2 parents 2f9ce2c + 1774eba commit 60e0c93
Show file tree
Hide file tree
Showing 6 changed files with 248 additions and 65 deletions.
15 changes: 15 additions & 0 deletions src/app/components/listbox/listbox.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,21 @@ export interface ListboxChangeEvent {
*/
value: any;
}
/**
* Custom change event.
* @see {@link Listbox.onSelectAllChange}
* @group Events
*/
export interface ListboxSelectAllChangeEvent {
/**
* Browser event.
*/
originalEvent: Event;
/**
* Boolean value indicates whether all data is selected.
*/
checked: boolean;
}
/**
* Custom filter event.
* @see {@link Listbox.onFilter}
Expand Down
53 changes: 41 additions & 12 deletions src/app/components/listbox/listbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { Subscription } from 'rxjs';
import { SearchIcon } from 'primeng/icons/search';
import { CheckIcon } from 'primeng/icons/check';
import { Nullable } from 'primeng/ts-helpers';
import { ListboxChangeEvent, ListboxClickEvent, ListboxDoubleClickEvent, ListboxFilterEvent, ListboxFilterOptions } from './listbox.interface';
import { ListboxChangeEvent, ListboxClickEvent, ListboxDoubleClickEvent, ListboxFilterEvent, ListboxFilterOptions, ListboxSelectAllChangeEvent } from './listbox.interface';
import { Scroller, ScrollerModule } from 'primeng/scroller';

export const LISTBOX_VALUE_ACCESSOR: any = {
Expand Down Expand Up @@ -473,6 +473,16 @@ export class Listbox implements AfterContentInit, OnInit, ControlValueAccessor,
set filterValue(val: string) {
this._filterValue.set(val);
}
/**
* Whether all data is selected.
* @group Props
*/
@Input() get selectAll(): boolean | undefined | null {
return this._selectAll;
}
set selectAll(value: boolean | undefined | null) {
this._selectAll = value;
}
/**
* Callback to invoke on value change.
* @param {ListboxChangeEvent} event - Custom change event.
Expand Down Expand Up @@ -509,6 +519,12 @@ export class Listbox implements AfterContentInit, OnInit, ControlValueAccessor,
* @group Emits
*/
@Output() onBlur: EventEmitter<FocusEvent> = new EventEmitter<FocusEvent>();
/**
* Callback to invoke when all data is selected.
* @param {ListboxSelectAllChangeEvent} event - Custom select event.
* @group Emits
*/
@Output() onSelectAllChange: EventEmitter<ListboxSelectAllChangeEvent> = new EventEmitter<ListboxSelectAllChangeEvent>();

@ViewChild('headerchkbox') headerCheckboxViewChild: Nullable<ElementRef>;

Expand Down Expand Up @@ -630,6 +646,8 @@ export class Listbox implements AfterContentInit, OnInit, ControlValueAccessor,

searchTimeout: any;

_selectAll: boolean | undefined | null = null;

_options = signal<any>(null);

startRangeIndex = signal<number>(-1);
Expand Down Expand Up @@ -745,8 +763,11 @@ export class Listbox implements AfterContentInit, OnInit, ControlValueAccessor,
this.onOptionSelect(null, this.visibleOptions()[this.focusedOptionIndex()]);
}
}

updateModel(value, event?) {
/**
* Updates the model value.
* @group Method
*/
public updateModel(value, event?) {
this.value = value;
this.modelValue.set(value);
this.onModelChange(value);
Expand Down Expand Up @@ -841,20 +862,28 @@ export class Listbox implements AfterContentInit, OnInit, ControlValueAccessor,
}
DomHandler.focus(this.headerCheckboxViewChild.nativeElement);

const value = this.allSelected()
? []
: this.visibleOptions()
.filter((option) => this.isValidOption(option))
.map((option) => this.getOptionValue(option));
this.updateModel(value, event);
if(this.selectAll !== null) {
this.onSelectAllChange.emit({
originalEvent: event,
checked: !this.allSelected()
})
} else {
const value = this.allSelected()
? []
: this.visibleOptions()
.filter((option) => this.isValidOption(option))
.map((option) => this.getOptionValue(option));

this.updateModel(value, event);
this.onChange.emit({ originalEvent: event, value: this.value });
}

event.preventDefault();
event.stopPropagation();
// event.stopPropagation();
}

allSelected() {
const allSelected = this.visibleOptions().length > 0 && this.visibleOptions().every((option) => this.isOptionGroup(option) || this.isOptionDisabled(option) || this.isSelected(option));
return ObjectUtils.isNotEmpty(this.visibleOptions()) && allSelected;
return this.selectAll !== null ? this.selectAll : ObjectUtils.isNotEmpty(this.visibleOptions()) && this.visibleOptions().every((option) => this.isOptionGroup(option) || this.isOptionDisabled(option) || this.isSelected(option));
}

onOptionTouchEnd() {
Expand Down
15 changes: 15 additions & 0 deletions src/app/components/multiselect/multiselect.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,21 @@ export interface MultiSelectChangeEvent {
*/
itemValue?: any;
}
/**
* Custom change event.
* @see {@link MultiSelect.onSelectAllChange}
* @group Events
*/
export interface MultiSelectSelectAllChangeEvent {
/**
* Browser event.
*/
originalEvent: Event;
/**
* Boolean value indicates whether all data is selected.
*/
checked: boolean;
}
/**
* Custom filter event.
* @see {@link MultiSelect.onFilter}
Expand Down
67 changes: 51 additions & 16 deletions src/app/components/multiselect/multiselect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
QueryList,
Renderer2,
signal,
SimpleChanges,
TemplateRef,
ViewChild,
ViewEncapsulation
Expand All @@ -41,7 +42,7 @@ import { TimesCircleIcon } from 'primeng/icons/timescircle';
import { TimesIcon } from 'primeng/icons/times';
import { ChevronDownIcon } from 'primeng/icons/chevrondown';
import { Nullable } from 'primeng/ts-helpers';
import { MultiSelectRemoveEvent, MultiSelectFilterOptions, MultiSelectFilterEvent, MultiSelectBlurEvent, MultiSelectChangeEvent, MultiSelectFocusEvent, MultiSelectLazyLoadEvent } from './multiselect.interface';
import { MultiSelectRemoveEvent, MultiSelectFilterOptions, MultiSelectFilterEvent, MultiSelectBlurEvent, MultiSelectChangeEvent, MultiSelectFocusEvent, MultiSelectLazyLoadEvent, MultiSelectSelectAllChangeEvent } from './multiselect.interface';

export const MULTISELECT_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
Expand Down Expand Up @@ -251,7 +252,7 @@ export class MultiSelectItem {
<ng-container *ngIf="allSelected()">
<CheckIcon [styleClass]="'p-checkbox-icon'" *ngIf="!checkIconTemplate" [attr.aria-hidden]="true" />
<span *ngIf="checkIconTemplate" class="p-checkbox-icon" [attr.aria-hidden]="true">
<ng-template *ngTemplateOutlet="checkIconTemplate"></ng-template>
<ng-template *ngTemplateOutlet="checkIconTemplate; context: { $implicit: allSelected() }"></ng-template>
</span>
</ng-container>
</div>
Expand All @@ -268,6 +269,7 @@ export class MultiSelectItem {
[value]="_filterValue() || ''"
(input)="onFilterInputChange($event)"
(keydown)="onFilterKeyDown($event)"
(click)="onInputClick($event)"
(blur)="onFilterBlur($event)"
class="p-multiselect-filter p-inputtext p-component"
[disabled]="disabled"
Expand Down Expand Up @@ -758,6 +760,16 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft
this._itemSize = val;
console.warn('The itemSize property is deprecated, use virtualScrollItemSize property instead.');
}
/**
* Whether all data is selected.
* @group Props
*/
@Input() get selectAll(): boolean | undefined | null {
return this._selectAll;
}
set selectAll(value: boolean | undefined | null) {
this._selectAll = value;
}
/**
* Fields used when filtering the options, defaults to optionLabel.
* @group Props
Expand Down Expand Up @@ -835,6 +847,12 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft
* @group Emits
*/
@Output() onRemove: EventEmitter<MultiSelectRemoveEvent> = new EventEmitter<MultiSelectRemoveEvent>();
/**
* Callback to invoke when all data is selected.
* @param {MultiSelectSelectAllChangeEvent} event - Custom select event.
* @group Emits
*/
@Output() onSelectAllChange: EventEmitter<MultiSelectSelectAllChangeEvent> = new EventEmitter<MultiSelectSelectAllChangeEvent>();

@ViewChild('container') containerViewChild: Nullable<ElementRef>;

Expand Down Expand Up @@ -864,6 +882,8 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft

searchTimeout: any;

_selectAll: boolean | undefined | null = null;

_autoZIndex: boolean | undefined;

_baseZIndex: number | undefined;
Expand All @@ -880,7 +900,7 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft

_selectionLimit: number | undefined;

public value: any[] | undefined | null;
value: any[];

public _filteredOptions: any[] | undefined | null;

Expand Down Expand Up @@ -1066,7 +1086,7 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft
return ObjectUtils.isNotEmpty(this.maxSelectedLabels) && this.modelValue() && this.modelValue().length > this.maxSelectedLabels ? this.modelValue().slice(0, this.maxSelectedLabels) : this.modelValue();
});

constructor(public el: ElementRef, public renderer: Renderer2, public cd: ChangeDetectorRef, public zone: NgZone, public filterService: FilterService, public config: PrimeNGConfig, public overlayService: OverlayService) {}
constructor( public el: ElementRef, public renderer: Renderer2, public cd: ChangeDetectorRef, public zone: NgZone, public filterService: FilterService, public config: PrimeNGConfig, public overlayService: OverlayService) {}

ngOnInit() {
this.id = this.id || UniqueComponentId();
Expand Down Expand Up @@ -1187,12 +1207,22 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft
}
}

updateModel(value, event?) {
/**
* Updates the model value.
* @group Method
*/
public updateModel(value, event?) {
this.value = value;
this.onModelChange(value);
this.modelValue.set(value);
}

onInputClick(event) {
event.stopPropagation();
event.preventDefault();
this.focusedOptionIndex.set(-1);
}

onOptionSelect(event, isFocus = false, index = -1) {
const { originalEvent, option } = event;
if (this.disabled || this.isOptionDisabled(option)) {
Expand Down Expand Up @@ -1314,7 +1344,6 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft

isSelected(option) {
const optionValue = this.getOptionValue(option);

return (this.modelValue() || []).some((value) => ObjectUtils.equals(value, optionValue, this.equalityKey()));
}

Expand Down Expand Up @@ -1648,7 +1677,7 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft
}
this.focusInputViewChild?.nativeElement.focus({ preventScroll: true });
this.onClick.emit(event);
this.cd.detectChanges();
this.cd.detectChanges()
}

onFirstHiddenFocus(event) {
Expand Down Expand Up @@ -1738,15 +1767,22 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft
return;
}

DomHandler.focus(this.headerCheckboxViewChild.nativeElement);

const value = this.allSelected()
if(this.selectAll !== null) {
this.onSelectAllChange.emit({
originalEvent: event,
checked: !this.allSelected()
})
} else {
const value = this.allSelected()
? []
: this.visibleOptions()
.filter((option) => this.isValidOption(option))
.map((option) => this.getOptionValue(option));
this.updateModel(value, event);
this.onChange.emit({ originalEvent: event, value: this.value });

this.updateModel(value, event)
}

DomHandler.focus(this.headerCheckboxViewChild.nativeElement);
this.headerCheckboxFocus = true;

event.preventDefault();
Expand Down Expand Up @@ -1797,11 +1833,11 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft
this.cd.markForCheck();
}

registerOnChange(fn: Function): void {
public registerOnChange(fn: Function): void {
this.onModelChange = fn;
}

registerOnTouched(fn: Function): void {
public registerOnTouched(fn: Function): void {
this.onModelTouched = fn;
}

Expand All @@ -1811,8 +1847,7 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft
}

allSelected() {
const allSelected = this.visibleOptions().length > 0 && this.visibleOptions().every((option) => this.isOptionGroup(option) || this.isOptionDisabled(option) || this.isSelected(option));
return ObjectUtils.isNotEmpty(this.visibleOptions()) && allSelected;
return this.selectAll !== null ? this.selectAll : ObjectUtils.isNotEmpty(this.visibleOptions()) && this.visibleOptions().every((option) => this.isOptionGroup(option) || this.isOptionDisabled(option) || this.isSelected(option));
}

/**
Expand Down
Loading

1 comment on commit 60e0c93

@vercel
Copy link

@vercel vercel bot commented on 60e0c93 Nov 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.