Skip to content

Commit

Permalink
feat(kit): Multiselect add ability to use objects in native select (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
vladimirpotekhin authored Jun 23, 2023
1 parent f03187a commit 88bc03d
Show file tree
Hide file tree
Showing 10 changed files with 128 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<span class="tui-text_body-l">Strings:</span>

<tui-multi-select
class="b-form"
[formControl]="itemControl"
class="b-form tui-space_top-5"
[formControl]="itemStringControl"
[tuiTextfieldLabelOutside]="true"
[tuiTextfieldCleaner]="true"
[tuiHintContent]="'hint'"
Expand All @@ -16,8 +18,8 @@
</tui-multi-select>

<tui-multi-select
class="b-form tui-space_top-5"
[formControl]="itemGroupControl"
class="b-form tui-space_vertical-5"
[formControl]="itemStringGroupControl"
[tuiTextfieldLabelOutside]="true"
[editable]="false"
[disabledItemHandler]="disableHandler"
Expand All @@ -31,3 +33,40 @@
[labels]="labels"
></select>
</tui-multi-select>

<span class="tui-text_body-l">Objects (stringify):</span>
<tui-multi-select
class="b-form tui-space_top-5"
[stringify]="stringify"
[formControl]="itemControl"
[tuiTextfieldLabelOutside]="true"
[tuiTextfieldCleaner]="true"
[tuiHintContent]="'hint'"
[editable]="false"
>
Star Wars persons

<select
tuiSelect
multiple
[items]="customItems"
></select>
</tui-multi-select>

<tui-multi-select
class="b-form tui-space_top-5"
[stringify]="stringify"
[formControl]="itemGroupControl"
[tuiTextfieldLabelOutside]="true"
[editable]="false"
[disabledItemHandler]="disableItemHandler"
>
Star Wars persons

<select
tuiSelect
multiple
[items]="customGroupItems"
[labels]="labels"
></select>
</tui-multi-select>
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@ import {Component} from '@angular/core';
import {FormControl} from '@angular/forms';
import {changeDetection} from '@demo/emulate/change-detection';
import {encapsulation} from '@demo/emulate/encapsulation';
import {TuiBooleanHandler} from '@taiga-ui/cdk';
import {TuiBooleanHandler, TuiStringHandler} from '@taiga-ui/cdk';

interface Item {
readonly name: string;
readonly id: number;
}
@Component({
selector: 'tui-multi-select-example-10',
templateUrl: './index.html',
changeDetection,
encapsulation,
})
export class TuiMultiSelectExample10 {
itemStringControl = new FormControl();
itemControl = new FormControl();
itemStringGroupControl = new FormControl();
itemGroupControl = new FormControl();

items = [
Expand All @@ -23,12 +29,36 @@ export class TuiMultiSelectExample10 {
'Yoda',
];

customItems: readonly Item[] = [
{name: 'Luke Skywalker', id: 1},
{name: 'Leia Organa Solo', id: 2},
{name: 'Darth Vader', id: 3},
{name: 'Han Solo', id: 4},
{name: 'Obi-Wan Kenobi', id: 5},
{name: 'Yoda', id: 6},
];

groupItems = [
['Caesar', 'Greek', 'Apple and Chicken'],
['Broccoli Cheddar', 'Chicken and Rice', 'Chicken Noodle'],
];

customGroupItems: readonly Item[][] = [
[
{name: 'Caesar', id: 1},
{name: 'Apple and Chicken', id: 2},
],
[
{name: 'Broccoli Cheddar', id: 3},
{name: 'Chicken and Rice', id: 4},
{name: 'Chicken Noodle', id: 5},
],
];

labels = ['Salad', 'Soup'];

stringify: TuiStringHandler<Item> = item => item.name;

disableHandler: TuiBooleanHandler<string> = item => item.startsWith('Broccoli');
disableItemHandler: TuiBooleanHandler<Item> = ({name}) => name.startsWith('Broccoli');
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export class TuiMultiSelectComponent<T>
private readonly accessor?: TuiDataListAccessor<T>;

@ContentChild(AbstractTuiNativeMultiSelect, {static: true})
private readonly nativeSelect?: AbstractTuiNativeMultiSelect;
private readonly nativeSelect?: AbstractTuiNativeMultiSelect<T>;

@ViewChild(TuiHostedDropdownComponent)
private readonly hostedDropdown?: TuiHostedDropdownComponent;
Expand Down
13 changes: 9 additions & 4 deletions projects/kit/components/multi-select/multi-select.directive.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
import {Directive} from '@angular/core';
import {TuiBooleanHandler} from '@taiga-ui/cdk';
import {AbstractTuiTextfieldHost, tuiAsTextfieldHost} from '@taiga-ui/core';
import {TuiItemsHandlers} from '@taiga-ui/kit/tokens';

import type {TuiMultiSelectComponent} from './multi-select.component';

@Directive({
selector: 'tui-multi-select',
providers: [tuiAsTextfieldHost(TuiMultiSelectDirective)],
})
export class TuiMultiSelectDirective extends AbstractTuiTextfieldHost<
TuiMultiSelectComponent<string>
export class TuiMultiSelectDirective<T = string> extends AbstractTuiTextfieldHost<
TuiMultiSelectComponent<T>
> {
override get readOnly(): boolean {
return true;
}

disableItemHandler: TuiBooleanHandler<string> = item =>
disableItemHandler: TuiBooleanHandler<T> = item =>
this.host.disabledItemHandler(item);

onValueChange(): void {}

onSelectionChange(value: string[]): void {
get stringify(): TuiItemsHandlers<T>['stringify'] {
return this.host.stringify;
}

onSelectionChange(value: T[]): void {
this.host.onValueChange(value);
}
}
2 changes: 2 additions & 0 deletions projects/kit/components/multi-select/multi-select.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {TuiArrowModule} from '@taiga-ui/kit/components/arrow';
import {TuiDataListWrapperModule} from '@taiga-ui/kit/components/data-list-wrapper';
import {TuiInputTagModule} from '@taiga-ui/kit/components/input-tag';
import {TuiMultiSelectOptionModule} from '@taiga-ui/kit/components/multi-select-option';
import {TuiStringifyContentPipeModule} from '@taiga-ui/kit/pipes';
import {PolymorpheusModule} from '@tinkoff/ng-polymorpheus';

import {TuiHideSelectedPipe} from './hide-selected.pipe';
Expand Down Expand Up @@ -49,6 +50,7 @@ import {TuiNativeMultiSelectGroupComponent} from './native-multi-select/native-m
TuiLinkModule,
TuiDataListModule,
TuiTextfieldControllerModule,
TuiStringifyContentPipeModule,
],
declarations: [
TuiMultiSelectComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {AbstractTuiNativeMultiSelect} from './native-multi-select';
{
provide: TemplateRef,
deps: [TuiNativeMultiSelectGroupComponent],
useFactory: ({datalist}: TuiNativeMultiSelectGroupComponent) => datalist,
useFactory: ({datalist}: TuiNativeMultiSelectGroupComponent<unknown>) =>
datalist,
},
{
provide: AbstractTuiNativeMultiSelect,
Expand All @@ -22,17 +23,27 @@ import {AbstractTuiNativeMultiSelect} from './native-multi-select';
'[attr.aria-invalid]': 'host.invalid',
'[disabled]': 'host.disabled || control.readOnly',
'[tabIndex]': 'host.focusable ? 0 : -1',
'(change)': 'onValueChange()',
'(change)': 'onValueChange($event.target.selectedOptions)',
'(click.stop.silent)': '0',
'(mousedown.stop.silent)': '0',
},
styleUrls: ['./native-multi-select.style.less'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TuiNativeMultiSelectGroupComponent extends AbstractTuiNativeMultiSelect {
export class TuiNativeMultiSelectGroupComponent<
T,
> extends AbstractTuiNativeMultiSelect<T> {
@Input()
items: readonly string[][] | null = [];
items: readonly T[][] | null = [];

@Input()
labels: readonly string[] = [];

onValueChange(selectedOptions: HTMLSelectElement['selectedOptions']): void {
const selected = Array.from(selectedOptions).map(option => option.index);
const flatItems = this.items?.reduce((acc, val) => acc.concat(val)) || [];
const value = flatItems.filter((_, index) => selected.includes(index));

this.host.onSelectionChange(value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*tuiDataList
tuiMultiSelectGroup
[items]="items"
[itemContent]="stringify | tuiStringifyContent"
[labels]="labels"
[disabledItemHandler]="disabledItemHandler || host.disableItemHandler"
></tui-data-list-wrapper>
Expand All @@ -13,10 +14,10 @@
>
<option
*ngFor="let option of group"
[selected]="option | tuiMapper : selectedMapper : host.value"
[value]="option"
[selected]="option | tuiMapper : selectedMapper : control.value"
[value]="stringify(option)"
[disabled]="disabledItemHandler ? disabledItemHandler(option) : host.disableItemHandler(option)"
>
{{ option }}
{{ stringify(option) }}
</option>
</optgroup>
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {AbstractTuiNativeMultiSelect} from './native-multi-select';
{
provide: TemplateRef,
deps: [TuiNativeMultiSelectComponent],
useFactory: ({datalist}: TuiNativeMultiSelectComponent) => datalist,
useFactory: ({datalist}: TuiNativeMultiSelectComponent<unknown>) => datalist,
},
{
provide: AbstractTuiNativeMultiSelect,
Expand All @@ -22,14 +22,21 @@ import {AbstractTuiNativeMultiSelect} from './native-multi-select';
'[attr.aria-invalid]': 'host.invalid',
'[disabled]': 'host.disabled || control.readOnly',
'[tabIndex]': 'host.focusable ? 0 : -1',
'(change)': 'onValueChange()',
'(change)': 'onValueChange($event.target.selectedOptions)',
'(click.stop.silent)': '0',
'(mousedown.stop.silent)': '0',
},
styleUrls: ['./native-multi-select.style.less'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TuiNativeMultiSelectComponent extends AbstractTuiNativeMultiSelect {
export class TuiNativeMultiSelectComponent<T> extends AbstractTuiNativeMultiSelect<T> {
@Input()
items: readonly string[] | null = [];
items: readonly T[] | null = [];

onValueChange(selectedOptions: HTMLSelectElement['selectedOptions']): void {
const selected = Array.from(selectedOptions).map(option => option.index);
const value = this.items?.filter((_, index) => selected.includes(index)) || [];

this.host.onSelectionChange(value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
*tuiDataList
tuiMultiSelectGroup
[items]="items"
[itemContent]="stringify | tuiStringifyContent"
[disabledItemHandler]="disabledItemHandler || host.disableItemHandler"
></tui-data-list-wrapper>
<option
*ngFor="let option of items"
[selected]="option | tuiMapper : selectedMapper : host.value"
[value]="option"
[selected]="option | tuiMapper : selectedMapper : control.value"
[value]="stringify(option)"
[disabled]="disabledItemHandler ? disabledItemHandler(option) : host.disableItemHandler(option)"
>
{{ option }}
{{ stringify(option) }}
</option>
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import {Directive} from '@angular/core';
import {TuiMapper} from '@taiga-ui/cdk';
import {AbstractTuiNativeSelect} from '@taiga-ui/kit/abstract';
import {TuiItemsHandlers} from '@taiga-ui/kit/tokens';

import type {TuiMultiSelectDirective} from '../multi-select.directive';

@Directive()
export abstract class AbstractTuiNativeMultiSelect extends AbstractTuiNativeSelect<TuiMultiSelectDirective> {
selectedMapper: TuiMapper<string, boolean> = (option, value) =>
value.includes(option);
export abstract class AbstractTuiNativeMultiSelect<T> extends AbstractTuiNativeSelect<
TuiMultiSelectDirective<T>,
T
> {
selectedMapper: TuiMapper<T, boolean> = (option, value) => value.includes(option);

onValueChange(): void {
this.host.onSelectionChange(
Array.from(this.el.nativeElement.selectedOptions).map(option => option.value),
);
get stringify(): TuiItemsHandlers<T>['stringify'] {
return this.host.stringify;
}
}

0 comments on commit 88bc03d

Please sign in to comment.