@@ -10,10 +10,13 @@ import {
10
10
OnChanges ,
11
11
OnDestroy ,
12
12
Output ,
13
- SimpleChanges
13
+ SimpleChanges ,
14
+ forwardRef
14
15
} from '@angular/core' ;
15
16
import { ChangeFilter } from './change-filter' ;
16
17
import { normalizeCommonJSImport } from './utils' ;
18
+ import { ControlValueAccessor , NG_VALUE_ACCESSOR } from '@angular/forms' ;
19
+ import { Subject , takeUntil } from 'rxjs' ;
17
20
18
21
export interface NgxLaydateConfig {
19
22
laydate : any | ( ( ) => Promise < any > ) ;
@@ -22,12 +25,19 @@ export interface NgxLaydateConfig {
22
25
23
26
export const NGX_LAYDATE_CONFIG = new InjectionToken < NgxLaydateConfig > ( 'NGX_LAYDATE_CONFIG' ) ;
24
27
28
+ const NGX_LAYDATE_VALUE_ACCESSOR = {
29
+ provide : NG_VALUE_ACCESSOR ,
30
+ useExisting : forwardRef ( ( ) => NgxLaydateDirective ) ,
31
+ multi : true
32
+ } ;
33
+
25
34
@Directive ( {
26
35
selector : 'laydate, [laydate]' ,
27
- exportAs : 'laydate'
36
+ exportAs : 'laydate' ,
37
+ providers : [ NGX_LAYDATE_VALUE_ACCESSOR ]
28
38
} )
29
- export class NgxLaydateDirective implements OnChanges , OnDestroy , AfterViewInit {
30
- @Input ( ) options : any ;
39
+ export class NgxLaydateDirective implements OnChanges , OnDestroy , AfterViewInit , ControlValueAccessor {
40
+ @Input ( ) options : Partial < any > = { } ;
31
41
32
42
// ngx-laydate events
33
43
@Output ( ) laydateInit = new EventEmitter < any > ( ) ;
@@ -44,6 +54,14 @@ export class NgxLaydateDirective implements OnChanges, OnDestroy, AfterViewInit
44
54
private laydateIns : any ;
45
55
private initLaydateTimer ?: number ;
46
56
57
+ // controlValueAccessor
58
+ private isNgModel = false ;
59
+ private currentValue = '' ;
60
+ private destroy$ = new Subject < void > ( ) ;
61
+ private ngLaydateCreated$ = new Subject < void > ( ) ;
62
+ private onChange : any = ( ) => { } ;
63
+ private onTouched : any = ( ) => { } ;
64
+
47
65
constructor (
48
66
@Inject ( NGX_LAYDATE_CONFIG ) public config : NgxLaydateConfig ,
49
67
private el : ElementRef ,
@@ -60,10 +78,38 @@ export class NgxLaydateDirective implements OnChanges, OnDestroy, AfterViewInit
60
78
ngOnDestroy ( ) {
61
79
window . clearTimeout ( this . initLaydateTimer ) ;
62
80
this . dispose ( ) ;
81
+ this . destroy$ . next ( ) ;
82
+ this . destroy$ . complete ( ) ;
63
83
}
64
84
65
85
ngAfterViewInit ( ) : void {
66
- this . initLaydateTimer = window . setTimeout ( ( ) => this . initChart ( ) ) ;
86
+ this . initLaydateTimer = window . setTimeout ( ( ) => this . initLaydate ( ) ) ;
87
+ }
88
+
89
+ writeValue ( obj : any ) : void {
90
+ this . currentValue = obj ;
91
+ }
92
+
93
+ registerOnChange ( fn : any ) : void {
94
+ this . isNgModel = true ;
95
+ this . onChange = fn ;
96
+ // delay execution until ngLaydate instance is created.
97
+ this . ngLaydateCreated$ . asObservable ( ) . pipe (
98
+ takeUntil ( this . destroy$ )
99
+ ) . subscribe ( ( ) => {
100
+ this . setOption ( { ...this . options , value : this . currentValue } ) ;
101
+ } ) ;
102
+ }
103
+
104
+ registerOnTouched ( fn : any ) : void {
105
+ this . onTouched = fn ;
106
+ }
107
+
108
+ setDisabledState ?( isDisabled : boolean ) : void {
109
+ const dom = this . el . nativeElement ;
110
+ if ( dom && dom . nodeName === 'INPUT' ) {
111
+ dom . disabled = isDisabled ;
112
+ }
67
113
}
68
114
69
115
public hint ( value : string ) {
@@ -100,7 +146,7 @@ export class NgxLaydateDirective implements OnChanges, OnDestroy, AfterViewInit
100
146
}
101
147
102
148
private createLaydate ( ) {
103
- const dom = this . el . nativeElement ;
149
+ const dom = ( this . options && this . options . elem ) || this . el . nativeElement ;
104
150
105
151
// here a bit tricky: we check if the laydate module is provided as function returning native import('...') then use the promise
106
152
// otherwise create the function that imitates behaviour above with a provided as is module
@@ -109,27 +155,39 @@ export class NgxLaydateDirective implements OnChanges, OnDestroy, AfterViewInit
109
155
typeof this . laydate === 'function' ? this . laydate : ( ) => Promise . resolve ( this . laydate ) ;
110
156
111
157
return normalizeCommonJSImport ( load ( ) ) . then ( ( laydateInstance : any ) => {
112
- this . options = Object . assign ( { } , this . options , { elem : dom } ) ;
158
+ this . options = Object . assign ( { } , this . options , {
159
+ elem : dom ,
160
+ ...( this . isNgModel && {
161
+ // intercept 'done' callback of the control, continue event propagation when callback is present.
162
+ ...( this . options && this . options . done && { ngDone : this . options . done } ) ,
163
+ done : ( value , date , endDate ) => {
164
+ this . onChange ( value ) ;
165
+ if ( this . options && this . options . ngDone ) {
166
+ this . options . ngDone ( value , date , endDate ) ;
167
+ }
168
+ }
169
+ } )
170
+ } ) ;
113
171
return laydateInstance ;
114
172
} ) ;
115
173
} ) ;
116
174
}
117
175
118
- private async initChart ( ) {
176
+ private async initLaydate ( ) {
119
177
await this . onOptionsChange ( this . options ) ;
120
178
}
121
179
122
180
private async onOptionsChange ( opt : any ) {
123
- // if (!opt) {
124
- // return;
125
- // }
126
-
127
181
if ( this . ngLaydate ) {
128
182
this . setOption ( this . options ) ;
129
183
} else {
130
184
this . ngLaydate = await this . createLaydate ( ) ;
131
185
this . laydateInit . emit ( this . ngLaydate ) ;
132
- this . setOption ( this . options ) ;
186
+ if ( this . isNgModel ) {
187
+ this . ngLaydateCreated$ . next ( ) ;
188
+ } else {
189
+ this . setOption ( this . options ) ;
190
+ }
133
191
}
134
192
}
135
193
0 commit comments