diff --git a/components/locale-provider/demo/basic.ts b/components/locale-provider/demo/basic.ts index 25bdb7c6..8eb5f03d 100644 --- a/components/locale-provider/demo/basic.ts +++ b/components/locale-provider/demo/basic.ts @@ -11,9 +11,9 @@ import { en_US, ru_RU, zh_CN, sv_SE, da_DK } from 'ng-zorro-antd-mobile'; [arrow]="'horizontal'" [cols]="1" [extra]="locale" - [value]="[locale]" + [(ngModel)]="lang" [data]="languages" - (onOk)="onChange($event)" + (ngModelChange)="onChange($event)" > Choose language @@ -47,6 +47,13 @@ import { en_US, ru_RU, zh_CN, sv_SE, da_DK } from 'ng-zorro-antd-mobile'; providers: [] }) export class DemoLocaleProviderBasicComponent { + lang = [ + { + value: '中文', + label: '中文', + language: zh_CN + } + ]; locale = '中文'; data = [ { @@ -121,9 +128,9 @@ export class DemoLocaleProviderBasicComponent { constructor(private _localeProviderService: LocaleProviderService) {} - onChange = item => { + onChange = (item) => { this.locale = item[0].value; const currentLocale = this.languages.find(i => i.value === this.locale).language; this._localeProviderService.setLocale(currentLocale); - }; + } } diff --git a/components/picker/demo/basic.ts b/components/picker/demo/basic.ts index 2ae61c98..c9c4b58f 100644 --- a/components/picker/demo/basic.ts +++ b/components/picker/demo/basic.ts @@ -11,8 +11,8 @@ import { Picker } from 'ng-zorro-antd-mobile'; [arrow]="'horizontal'" [mask]=true [title]="'Areas'" - [value]="value1" - (onOk)="onOk1($event)" + [(ngModel)]="value1" + (ngModelChange)="onOk1($event)" > Multiple & cascader @@ -22,8 +22,8 @@ import { Picker } from 'ng-zorro-antd-mobile'; [cascade]="false" [data]="seasons" [title]="'选择季节'" - [value]="value2" - (onOk)="onOk2($event)" + [(ngModel)]="value2" + (ngModelChange)="onOk2($event)" > Multiple @@ -31,17 +31,17 @@ import { Picker } from 'ng-zorro-antd-mobile'; [extra]="name3" [arrow]="'horizontal'" [data]="singleArea" - [value]="value3" - (onOk)="onOk3($event)" + [(ngModel)]="value3" + (ngModelChange)="onOk3($event)" > Single Multiple & async @@ -113,22 +113,18 @@ export class DemoPickerBasicComponent { onOk1(result) { this.name1 = this.getResult(result); - this.value1 = this.getValue(result); } onOk2(result) { this.name2 = this.getResult(result); - this.value2 = this.getValue(result); } onOk3(result) { this.name3 = this.getResult(result); - this.value3 = this.getValue(result); } onOk4(result) { this.name4 = this.getResult(result); - this.value4 = this.getValue(result); } onPickerChange(result) { diff --git a/components/picker/doc/index.en-US.md b/components/picker/doc/index.en-US.md index 81906716..92db153c 100644 --- a/components/picker/doc/index.en-US.md +++ b/components/picker/doc/index.en-US.md @@ -14,14 +14,14 @@ Choose from a set of data, e.g. Country choice. Properties | Descrition | Type | Default -----------|------------|------|-------- +| ngModel | Current selected value, the format is `[value1, value2, value3]`, corresponds to the level value of the data source,double binding | Array | - | | data | data source | `Array<{value, label, children: Array}>` | - | -| value | the value, the format is `[value1, value2, value3]`, corresponds to the level value of the data source | Array | - | | cols | col numbers | Number | `3` | | onChange | selected callback function | (val): void | - | | onPickerChange | trigger on each column of selected data is changed | (val): void | - | | okText | ok text | String | `确定` | | dismissText | dismiss text | String | `取消` | -| onOk | handler called when click ok | (val): void | - | +| ngModelChange | handler called when click ok | EventEmitter | - | | onDismiss | handler called when click cancel | (): void | - | | title | title | String | - | | disabled | set disabled | Boolean | false | diff --git a/components/picker/doc/index.zh-CN.md b/components/picker/doc/index.zh-CN.md index 9c2d172d..34cc8ac3 100644 --- a/components/picker/doc/index.zh-CN.md +++ b/components/picker/doc/index.zh-CN.md @@ -15,14 +15,14 @@ subtitle: 选择器 属性 | 说明 | 类型 | 默认值 ----|-----|------|------ +| ngModel | 当前值, 格式是`[value1, value2, value3]`, 对应数据源的相应级层value, 可双向绑定 | Array | - | | data | 数据源 | `Array<{value, label, children: Array}>` | - | -| value | 值, 格式是`[value1, value2, value3]`, 对应数据源的相应级层value | Array | - | | cols | 列数 | Number | `3` | | onChange | 选中后的回调 | (val): void | - | | onPickerChange | 每列数据选择变化后的回调函数 | (val): void | - | | okText | 选中的文案 | String | `确定` | | dismissText | 取消选中的文案 | String | `取消` | -| onOk | 点击选中时执行的回调 | (val): void | 无 | +| ngModelChange | 点击选中时执行的回调 | EventEmitter | - | | onDismiss | 点击取消时执行的回调 | (): void | 无 | | title | 大标题 | String | - | | disabled | 是否不可用 | Boolean | false | diff --git a/components/picker/picker-options.provider.ts b/components/picker/picker-options.provider.ts index 70b472f8..1dfa314f 100644 --- a/components/picker/picker-options.provider.ts +++ b/components/picker/picker-options.provider.ts @@ -22,13 +22,13 @@ export class PickerOptions implements PickerOptionsInterface { disabled?: boolean = false; cascade?: boolean = true; appendToBody?: boolean = false; - onOk?: EventEmitter = new EventEmitter(); onDismiss?: EventEmitter = new EventEmitter(); onPickerChange?: EventEmitter = new EventEmitter(); indicatorStyle?: object = {}; hidePicker?: () => void; confirm?: (result) => void; cancel?: () => void; + updateNgModel?: (value: any[]) => void; } export type PickerCallBack = (result?: any) => PromiseLike | void; diff --git a/components/picker/picker.component.spec.ts b/components/picker/picker.component.spec.ts index 2166f137..e3d607dd 100644 --- a/components/picker/picker.component.spec.ts +++ b/components/picker/picker.component.spec.ts @@ -1,4 +1,5 @@ import { Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; import { By } from '@angular/platform-browser'; import { async, ComponentFixture, TestBed, fakeAsync } from '@angular/core/testing'; import { ListModule, PickerModule, PickerComponent } from '../..'; @@ -9,6 +10,7 @@ import { LocaleProviderService, LocaleProviderModule } from '../..'; import { Button } from '../button/button.component'; import { ButtonModule } from '../button/button.module'; import { Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; + describe('PickerComponent', () => { let component: TestPickerBasicComponent; let fixture: ComponentFixture; @@ -20,7 +22,7 @@ describe('PickerComponent', () => { TestBed.configureTestingModule({ declarations: [TestPickerBasicComponent], providers: [PickerOptions, LocaleProviderService, Picker, Overlay], - imports: [ListModule, PickerModule, LocaleProviderModule, ButtonModule] + imports: [ListModule, PickerModule, LocaleProviderModule, ButtonModule, FormsModule] }).compileComponents(); TestBed.overrideModule(PickerModule, { set: { entryComponents: [PickerComponent] } @@ -84,15 +86,14 @@ describe('PickerComponent', () => { pickerEle.querySelector('.am-picker-popup-header-right').click(); }); - it('onOk work', () => { + it('should ngModel work', () => { const list = lists[0].nativeElement; list.click(); fixture.detectChanges(); pickerEle = document.querySelector('picker'); - component.onOk1 = jasmine.createSpy('onOk1 is callback'); pickerEle.querySelector('.am-picker-popup-header-right').click(); fixture.detectChanges(); - expect(component.onOk1).toHaveBeenCalledTimes(1); + expect(component.modelChange).toHaveBeenCalledTimes(1); }); it ('should touch event work', () => { @@ -134,10 +135,10 @@ describe('PickerComponent', () => { [mask]="mask" [extra]="name1" [title]="title" - [value]="value1" + [(ngModel)]="value1" [data]="singleArea" [arrow]="'horizontal'" - (onOk)="onOk1($event)" + (ngModelChange)="modelChange($event)" > Multiple & cascader @@ -172,19 +173,10 @@ export class TestPickerBasicComponent { value1 = ['宣武区']; title = 'result'; mask = true; + modelChange = jasmine.createSpy('ngModel change callback'); - constructor (private _picker: Picker ) { - - } - - onOk1(result) { - this.name1 = this.getResult(result); - this.value1 = this.getValue(result); - } + constructor (private _picker: Picker) { - onPickerChange(result) { - this.name1 = this.getResult(result); - this.value1 = this.getValue(result); } getResult(result) { diff --git a/components/picker/picker.component.ts b/components/picker/picker.component.ts index 765168c8..eb634782 100644 --- a/components/picker/picker.component.ts +++ b/components/picker/picker.component.ts @@ -227,7 +227,7 @@ export class PickerComponent implements OnInit, AfterViewInit, OnDestroy { } ok() { - this.options.onOk.emit(this.combineReslut()); + this.options.updateNgModel(this.combineReslut()); if (this.options.confirm) { this.options.confirm(this.combineReslut()); } diff --git a/components/picker/picker.directive.ts b/components/picker/picker.directive.ts index f041b6f6..ac79ffe0 100644 --- a/components/picker/picker.directive.ts +++ b/components/picker/picker.directive.ts @@ -14,23 +14,31 @@ import { ComponentFactoryResolver, Renderer2, ComponentFactory, - SimpleChanges + SimpleChanges, + forwardRef } from '@angular/core'; import { PickerComponent } from './picker.component'; import { PickerOptions } from './picker-options.provider'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; @Directive({ - selector: '[Picker], [nzm-picker]' + selector: '[Picker], [nzm-picker]', + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => PickerDirective), + multi: true + } + ] }) -export class PickerDirective implements OnDestroy, OnChanges, OnInit { +export class PickerDirective implements OnDestroy, OnChanges, OnInit, ControlValueAccessor { picker: ComponentRef; + value: Array; private _eventListeners: Array<() => void> = []; @Input() data: Array; @Input() - value: Array; - @Input() cols: Number; @Input() mask: boolean; @@ -55,10 +63,11 @@ export class PickerDirective implements OnDestroy, OnChanges, OnInit { @Output() onPickerChange: EventEmitter = new EventEmitter(); @Output() - onOk: EventEmitter = new EventEmitter(); - @Output() onDismiss: EventEmitter = new EventEmitter(); + onChange: (value: any[]) => void = () => null; + onTouched: () => void = () => null; + @HostListener('click') togglePicker(): void { if (!this.picker) { @@ -117,6 +126,9 @@ export class PickerDirective implements OnDestroy, OnChanges, OnInit { Object.assign(options, this._defaultOptions, { hidePicker: (event): void => { this.hidePicker(); + }, + updateNgModel: (value: any[]): void => { + this.onChange(value); } }); @@ -132,7 +144,6 @@ export class PickerDirective implements OnDestroy, OnChanges, OnInit { 'cascade', 'appendToBody', 'indicatorStyle', - 'onOk', 'onPickerChange' ]; optionalParams.forEach(param => { @@ -168,4 +179,20 @@ export class PickerDirective implements OnDestroy, OnChanges, OnInit { this._eventListeners = []; } } + + writeValue(value: any[]): void { + this.value = Array.isArray(value) ? value : []; + } + + registerOnChange(fn: (value: any[]) => void): void { + this.onChange = fn; + } + + registerOnTouched(fn: () => void): void { + this.onTouched = fn; + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + } }