Skip to content

Commit

Permalink
feat(core/select): support for angular forms (#738)
Browse files Browse the repository at this point in the history
Co-authored-by: Tiago Viegas <tiago.viegas@siemens.com>
  • Loading branch information
Tiagogv and tiagogviegas authored Sep 6, 2023
1 parent e3c7193 commit c0bb78f
Show file tree
Hide file tree
Showing 15 changed files with 286 additions and 67 deletions.
2 changes: 2 additions & 0 deletions packages/angular-test-app/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ import Radiobutton from 'src/preview-examples/radio-button';
import Select from 'src/preview-examples/select';
import SelectEditable from 'src/preview-examples/select-editable';
import SelectMultiple from 'src/preview-examples/select-multiple';
import SelectNgModel from 'src/preview-examples/select-ng-model';
import Settings from 'src/preview-examples/settings';
import Spinner from 'src/preview-examples/spinner';
import SpinnerLarge from 'src/preview-examples/spinner-large';
Expand Down Expand Up @@ -293,6 +294,7 @@ const routes: Routes = [
{ path: 'radio-button', component: Radiobutton },
{ path: 'select-editable', component: SelectEditable },
{ path: 'select-multiple', component: SelectMultiple },
{ path: 'select-ng-model', component: SelectNgModel },
{ path: 'select', component: Select },
{ path: 'settings', component: Settings },
{ path: 'spinner', component: Spinner },
Expand Down
2 changes: 2 additions & 0 deletions packages/angular-test-app/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ import Radiobutton from 'src/preview-examples/radio-button';
import Select from 'src/preview-examples/select';
import SelectEditable from 'src/preview-examples/select-editable';
import SelectMultiple from 'src/preview-examples/select-multiple';
import SelectNgModel from 'src/preview-examples/select-ng-model';
import Settings from 'src/preview-examples/settings';
import Spinner from 'src/preview-examples/spinner';
import SpinnerLarge from 'src/preview-examples/spinner-large';
Expand Down Expand Up @@ -188,6 +189,7 @@ import { NavigationTestComponent } from './components/navigation-test.component'
Radiobutton,
SelectEditable,
SelectMultiple,
SelectNgModel,
Select,
Settings,
Spinner,
Expand Down
25 changes: 25 additions & 0 deletions packages/angular-test-app/src/preview-examples/select-ng-model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2023 Siemens AG
*
* SPDX-License-Identifier: MIT
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import { Component } from '@angular/core';

@Component({
selector: 'app-example',
template: `
<ix-select name="ix-select-control" [(ngModel)]="value">
<ix-select-item label="Item 1" value="1"></ix-select-item>
<ix-select-item label="Item 2" value="2"></ix-select-item>
<ix-select-item label="Item 3" value="3"></ix-select-item>
<ix-select-item label="Item 4" value="4"></ix-select-item>
</ix-select>
`,
})
export default class Select {
value = '1';
}
12 changes: 8 additions & 4 deletions packages/angular/src/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1774,28 +1774,32 @@ export declare interface IxRow extends Components.IxRow {}


@ProxyCmp({
inputs: ['allowClear', 'disabled', 'editable', 'hideListHeader', 'i18nNoMatches', 'i18nPlaceholder', 'i18nPlaceholderEditable', 'i18nSelectListHeader', 'mode', 'readonly', 'selectedIndices']
inputs: ['allowClear', 'disabled', 'editable', 'hideListHeader', 'i18nNoMatches', 'i18nPlaceholder', 'i18nPlaceholderEditable', 'i18nSelectListHeader', 'mode', 'readonly', 'selectedIndices', 'value']
})
@Component({
selector: 'ix-select',
changeDetection: ChangeDetectionStrategy.OnPush,
template: '<ng-content></ng-content>',
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
inputs: ['allowClear', 'disabled', 'editable', 'hideListHeader', 'i18nNoMatches', 'i18nPlaceholder', 'i18nPlaceholderEditable', 'i18nSelectListHeader', 'mode', 'readonly', 'selectedIndices'],
inputs: ['allowClear', 'disabled', 'editable', 'hideListHeader', 'i18nNoMatches', 'i18nPlaceholder', 'i18nPlaceholderEditable', 'i18nSelectListHeader', 'mode', 'readonly', 'selectedIndices', 'value'],
})
export class IxSelect {
protected el: HTMLElement;
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
c.detach();
this.el = r.nativeElement;
proxyOutputs(this, this.el, ['itemSelectionChange', 'inputChange', 'addItem']);
proxyOutputs(this, this.el, ['valueChange', 'itemSelectionChange', 'inputChange', 'addItem']);
}
}


export declare interface IxSelect extends Components.IxSelect {
/**
* Item selection changed
* Value changed @since 2.0.0
*/
valueChange: EventEmitter<CustomEvent<string | string[]>>;
/**
* Item selection changed @deprecated since 2.0.0. Use `valueChange` instead.
*/
itemSelectionChange: EventEmitter<CustomEvent<string[]>>;
/**
Expand Down
1 change: 1 addition & 0 deletions packages/angular/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ export * from './module';
export * from './theme';
export * from './toast';
export * from './tree';
export * from './select-value-accessor'
8 changes: 7 additions & 1 deletion packages/angular/src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,17 @@ import { appInitialize } from './app-initialize';
import { DIRECTIVES } from './declare-components';
import { IxDropdownTriggerDirective } from './dropdown/trigger.directive';
import { ModalService } from './modal';
import { SelectValueAccessor } from './select-value-accessor';
import { ThemeService } from './theme';
import { ToastService } from './toast';
import * as tree from './tree';

const DECLARATIONS = [...DIRECTIVES, tree.IxTree, IxDropdownTriggerDirective];
const DECLARATIONS = [
...DIRECTIVES,
tree.IxTree,
IxDropdownTriggerDirective,
SelectValueAccessor,
];

@NgModule({
declarations: DECLARATIONS,
Expand Down
24 changes: 24 additions & 0 deletions packages/angular/src/select-value-accessor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Directive, ElementRef } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';

import { ValueAccessor } from './value-accessor';

@Directive({
/* tslint:disable-next-line:directive-selector */
selector: 'ix-select[ngModel],ix-select[formControlName],ix-select[formControl]',
host: {
'(valueChange)': 'handleChangeEvent($event.target.value)'
},
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: SelectValueAccessor,
multi: true
}
]
})
export class SelectValueAccessor extends ValueAccessor {
constructor(el: ElementRef) {
super(el);
}
}
39 changes: 39 additions & 0 deletions packages/angular/src/value-accessor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Directive, ElementRef, HostListener } from '@angular/core';
import { ControlValueAccessor } from '@angular/forms';

@Directive({})
export class ValueAccessor implements ControlValueAccessor {

private onChange: (value: any) => void = () => {/**/};
private onTouched: () => void = () => {/**/};
protected lastValue: any;

constructor(protected el: ElementRef) {}

writeValue(value: any) {
this.el.nativeElement.value = this.lastValue = value == null ? '' : value;
}

handleChangeEvent(value: any) {
if (value !== this.lastValue) {
this.lastValue = value;
this.onChange(value);
}
}

@HostListener('focusout')
_handleBlurEvent() {
this.onTouched();
}

registerOnChange(fn: (value: any) => void) {
this.onChange = fn;
}
registerOnTouched(fn: () => void) {
this.onTouched = fn;
}

setDisabledState(isDisabled: boolean) {
this.el.nativeElement.disabled = isDisabled;
}
}
59 changes: 54 additions & 5 deletions packages/core/component-doc.json
Original file line number Diff line number Diff line change
Expand Up @@ -9082,9 +9082,14 @@
"mutable": true,
"attr": "selected-indices",
"reflectToAttr": false,
"docs": "Indices of selected items\nThis corresponds to the value property of ix-select-items and therefor not necessarily the indices of the items in the list.",
"docsTags": [],
"default": "[]",
"docs": "Indices of selected items.\nThis corresponds to the value property of ix-select-items and therefor not necessarily the indices of the items in the list.",
"docsTags": [
{
"name": "deprecated",
"text": "since 2.0.0. Use the `value` property instead."
}
],
"deprecation": "since 2.0.0. Use the `value` property instead.",
"values": [
{
"type": "string"
Expand All @@ -9093,7 +9098,31 @@
"type": "string[]"
}
],
"optional": false,
"optional": true,
"required": false
},
{
"name": "value",
"type": "string | string[]",
"mutable": true,
"attr": "value",
"reflectToAttr": false,
"docs": "Current selected value.\nThis corresponds to the value property of ix-select-items",
"docsTags": [
{
"name": "since",
"text": "2.0.0"
}
],
"values": [
{
"type": "string"
},
{
"type": "string[]"
}
],
"optional": true,
"required": false
}
],
Expand Down Expand Up @@ -9129,7 +9158,27 @@
"cancelable": true,
"composed": true,
"docs": "Item selection changed",
"docsTags": []
"docsTags": [
{
"name": "deprecated",
"text": "since 2.0.0. Use `valueChange` instead."
}
],
"deprecation": "since 2.0.0. Use `valueChange` instead."
},
{
"event": "valueChange",
"detail": "string | string[]",
"bubbles": true,
"cancelable": true,
"composed": true,
"docs": "Value changed",
"docsTags": [
{
"name": "since",
"text": "2.0.0"
}
]
}
],
"styles": [],
Expand Down
24 changes: 21 additions & 3 deletions packages/core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1575,9 +1575,15 @@ export namespace Components {
*/
"readonly": boolean;
/**
* Indices of selected items This corresponds to the value property of ix-select-items and therefor not necessarily the indices of the items in the list.
* Indices of selected items. This corresponds to the value property of ix-select-items and therefor not necessarily the indices of the items in the list.
* @deprecated since 2.0.0. Use the `value` property instead.
*/
"selectedIndices": string | string[];
"selectedIndices"?: string | string[];
/**
* Current selected value. This corresponds to the value property of ix-select-items
* @since 2.0.0
*/
"value"?: string | string[];
}
interface IxSelectItem {
"hover": boolean;
Expand Down Expand Up @@ -4655,16 +4661,28 @@ declare namespace LocalJSX {
"onInputChange"?: (event: IxSelectCustomEvent<string>) => void;
/**
* Item selection changed
* @deprecated since 2.0.0. Use `valueChange` instead.
*/
"onItemSelectionChange"?: (event: IxSelectCustomEvent<string[]>) => void;
/**
* Value changed
* @since 2.0.0
*/
"onValueChange"?: (event: IxSelectCustomEvent<string | string[]>) => void;
/**
* If true the select will be in readonly mode
*/
"readonly"?: boolean;
/**
* Indices of selected items This corresponds to the value property of ix-select-items and therefor not necessarily the indices of the items in the list.
* Indices of selected items. This corresponds to the value property of ix-select-items and therefor not necessarily the indices of the items in the list.
* @deprecated since 2.0.0. Use the `value` property instead.
*/
"selectedIndices"?: string | string[];
/**
* Current selected value. This corresponds to the value property of ix-select-items
* @since 2.0.0
*/
"value"?: string | string[];
}
interface IxSelectItem {
"hover"?: boolean;
Expand Down
Loading

0 comments on commit c0bb78f

Please sign in to comment.