Skip to content

Commit d6cb0d3

Browse files
committed
SVY-20819 use signals instead of @input in our components
Add an internal variable to manage the component’s value, and replace the existing model implementation with a signal and an input-based approach.
1 parent c9578a1 commit d6cb0d3

25 files changed

Lines changed: 141 additions & 112 deletions

File tree

components/projects/bootstrapcomponents/src/bts_basecomp.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ServoyBaseComponent } from '@servoy/public';
2-
import { Directive, Renderer2, SimpleChanges, ChangeDetectorRef, input, model } from '@angular/core';
2+
import { Directive, Renderer2, SimpleChanges, ChangeDetectorRef, input, signal } from '@angular/core';
33

44
@Directive()
55
// eslint-disable-next-line
@@ -10,7 +10,9 @@ export class ServoyBootstrapBaseComponent<T extends HTMLElement> extends ServoyB
1010
readonly variant = input<string[]>(undefined);
1111
readonly tabSeq = input<number>(undefined);
1212
readonly text = input<string>(undefined);
13-
toolTipText = model<string>(undefined);
13+
readonly toolTipText = input<string>(undefined);
14+
15+
protected _toolTipText = signal<string>(undefined);
1416

1517
timeoutID: number;
1618

@@ -20,6 +22,9 @@ export class ServoyBootstrapBaseComponent<T extends HTMLElement> extends ServoyB
2022

2123
svyOnChanges(changes: SimpleChanges) {
2224
if (changes) {
25+
if (changes.toolTipText) {
26+
this._toolTipText.set(this.toolTipText());
27+
}
2328
for (const property of Object.keys(changes)) {
2429
const change = changes[property];
2530
const styleClass = this.styleClass();

components/projects/bootstrapcomponents/src/bts_basefield.ts

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ServoyBootstrapBaseComponent } from './bts_basecomp';
2-
import { Directive, SimpleChanges, SimpleChange, Renderer2, ChangeDetectorRef, Inject, DOCUMENT, input, output, model } from '@angular/core';
2+
import { Directive, SimpleChanges, SimpleChange, Renderer2, ChangeDetectorRef, Inject, DOCUMENT, input, output, signal } from '@angular/core';
33
import { PropertyUtils } from '@servoy/public';
44

55

@@ -15,12 +15,15 @@ export class ServoyBootstrapBasefield<T extends HTMLElement> extends ServoyBoots
1515
readonly onFocusLostMethodID = input<(e: Event) => void>(undefined);
1616

1717
readonly dataProviderIDChange = output();
18-
dataProviderID = model<any>(undefined);
18+
readonly dataProviderID = input<any>(undefined);
1919
readonly readOnly = input<boolean>(undefined);
2020
readonly findmode = input<boolean>(undefined);
21-
editable = model<boolean>(undefined);
21+
readonly editable = input<boolean>(undefined);
2222
readonly placeholderText = input<string>(undefined);
2323
readonly selectOnEnter = input<boolean>(undefined);
24+
25+
protected _dataProviderID = signal<any>(undefined);
26+
protected _editable = signal<boolean>(undefined);
2427

2528
mustExecuteOnFocus = true;
2629

@@ -32,9 +35,11 @@ export class ServoyBootstrapBasefield<T extends HTMLElement> extends ServoyBoots
3235

3336
svyOnInit() {
3437
super.svyOnInit();
38+
this._dataProviderID.set(this.dataProviderID());
39+
this._editable.set(this.editable());
3540
this.attachFocusListeners(this.getFocusElement());
36-
if (this.dataProviderID() === undefined) {
37-
this.dataProviderID.set(null);
41+
if (this._dataProviderID() === undefined) {
42+
this._dataProviderID.set(null);
3843
}
3944
if (this.onActionMethodID()) {
4045
this.renderer.listen(this.getFocusElement(), 'keydown', e => {
@@ -52,6 +57,14 @@ export class ServoyBootstrapBasefield<T extends HTMLElement> extends ServoyBoots
5257

5358
svyOnChanges(changes: SimpleChanges) {
5459
if (changes) {
60+
/*if (changes.dataProviderID) {
61+
this._dataProviderID.set(this.dataProviderID());
62+
}
63+
64+
if (changes.editable) {
65+
this._editable.set(this.editable());
66+
}*/
67+
5568
for (const property of Object.keys(changes)) {
5669
const change = changes[property];
5770
switch (property) {
@@ -68,7 +81,7 @@ export class ServoyBootstrapBasefield<T extends HTMLElement> extends ServoyBoots
6881
const realFindmode = findmode === undefined? false: findmode; // default for find is false
6982
const readOnly = this.readOnly();
7083
const realReadonly = readOnly === undefined? false: readOnly; // default for readonly is false
71-
const editable = this.editable();
84+
const editable = this._editable();
7285
const realEditable = editable === undefined? true: editable; // default for editable is true
7386
if (realFindmode || (!realReadonly && realEditable)) {
7487
this.renderer.removeAttribute(this.getFocusElement(), 'readonly');
@@ -106,20 +119,20 @@ export class ServoyBootstrapBasefield<T extends HTMLElement> extends ServoyBoots
106119
this.renderer.addClass(this.getFocusElement(), 'ng-invalid');
107120
if (stringValue) {
108121
if (this.storedTooltip === false) {
109-
this.storedTooltip = this.toolTipText();
122+
this.storedTooltip = this._toolTipText();
110123
}
111-
this.toolTipText.set(returnval.toString());
124+
this._toolTipText.set(returnval.toString());
112125
}
113126
} else {
114127
this.renderer.removeClass(this.getFocusElement(), 'ng-invalid');
115128
this.renderer.addClass(this.getFocusElement(), 'ng-valid');
116-
if (this.storedTooltip !== false) this.toolTipText.set(this.storedTooltip);
129+
if (this.storedTooltip !== false) this._toolTipText.set(this.storedTooltip);
117130
this.storedTooltip = false;
118131
}
119132
}
120133

121134
pushUpdate() {
122-
this.dataProviderIDChange.emit(this.dataProviderID());
135+
this.dataProviderIDChange.emit(this._dataProviderID());
123136
}
124137

125138
protected setPlaceHolderText(change : SimpleChange ){
@@ -152,7 +165,7 @@ export class ServoyBootstrapBasefield<T extends HTMLElement> extends ServoyBoots
152165
}
153166

154167
public getAsPlainText(): string {
155-
const dataProviderID = this.dataProviderID();
168+
const dataProviderID = this._dataProviderID();
156169
if (dataProviderID) {
157170
return dataProviderID.replace(/<[^>]*>/g, '');
158171
}

components/projects/bootstrapcomponents/src/calendar/basecalendar.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Renderer2, ChangeDetectorRef, Inject, Directive, SimpleChanges, DOCUMENT, input, output, model } from '@angular/core';
1+
import { Renderer2, ChangeDetectorRef, Inject, Directive, SimpleChanges, DOCUMENT, input, output, signal } from '@angular/core';
22
import { ServoyBootstrapBasefield } from '../bts_basefield';
33

44
import { getFirstDayOfWeek, LoggerService, ServoyPublicService } from '@servoy/public';
@@ -17,7 +17,7 @@ export class ServoyBootstrapBaseCalendar extends ServoyBootstrapBasefield<HTMLDi
1717
readonly maxDateChange = output();
1818
readonly minDate = input<Date>(undefined);
1919
readonly minDateChange = output();
20-
keepInvalid = model<boolean>(undefined);
20+
readonly keepInvalid = signal<boolean>(undefined);
2121
readonly keepInvalidChange = output<boolean>();
2222

2323
readonly calendarWeeks = input<boolean>(undefined);
@@ -91,11 +91,11 @@ export class ServoyBootstrapBaseCalendar extends ServoyBootstrapBasefield<HTMLDi
9191
Object.assign(this.config, this.options());
9292
}
9393
if (changes.dataProviderID && this.picker && !this.findmode()) {
94-
const dataProviderID = this.dataProviderID();
94+
const dataProviderID = this._dataProviderID();
9595
const value = (dataProviderID instanceof Date) ? DateTime.convert(dataProviderID, null, this.config.localization) : null;
9696
this.picker.dates.setValue(value);
9797
}
98-
const dataProviderIDValue = this.dataProviderID();
98+
const dataProviderIDValue = this._dataProviderID();
9999
if (dataProviderIDValue) {
100100
const value = (dataProviderIDValue instanceof Date) ? DateTime.convert(dataProviderIDValue, null, this.config.localization) : null;
101101
if (value)
@@ -165,7 +165,7 @@ export class ServoyBootstrapBaseCalendar extends ServoyBootstrapBasefield<HTMLDi
165165

166166
public dateChanged(event: any) {
167167
if (event.type === 'change.td') {
168-
const dataProviderID = this.dataProviderID();
168+
const dataProviderID = this._dataProviderID();
169169
if ((event.date && dataProviderID && event.date.getTime() === dataProviderID.getTime()) ||
170170
(!event.date && !dataProviderID)) return;
171171

@@ -175,8 +175,8 @@ export class ServoyBootstrapBaseCalendar extends ServoyBootstrapBasefield<HTMLDi
175175
this.picker.dates.setValue(value);
176176
return;
177177
}
178-
this.dataProviderID.set(!event.date ? null : event.date);
179-
} else this.dataProviderID.set(null);
178+
this._dataProviderID.set(!event.date ? null : event.date);
179+
} else this._dataProviderID.set(null);
180180
super.pushUpdate();
181181
}
182182

components/projects/bootstrapcomponents/src/calendar/calendar.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,22 +126,22 @@ export class ServoyBootstrapCalendar extends ServoyBootstrapBaseCalendar {
126126
}
127127
if (changes.pickerOnly) {
128128
// pickerOnly maps on the readonly flag so just set that boolean of the parent class
129-
this.editable.set(!this.pickerOnly());
129+
this._editable.set(!this.pickerOnly());
130130
}
131131
super.svyOnChanges(changes);
132132
}
133133

134134
public modelChange(event: any) {
135135
if (this.findmode()) {
136-
this.dataProviderID.set(event);
136+
this._dataProviderID.set(event);
137137
super.pushUpdate();
138138
}
139139

140140
const minDate = this.minDate();
141141
const maxDate = this.maxDate();
142142
if (event !== '' && ((minDate && minDate > event) || (maxDate && maxDate < event) || !this.isValidDate(event))) {
143143
// revert to old value
144-
this.svyFormat().writeValue(this.dataProviderID());
144+
this.svyFormat().writeValue(this._dataProviderID());
145145
}
146146
}
147147

@@ -169,7 +169,7 @@ export class ServoyBootstrapCalendar extends ServoyBootstrapBaseCalendar {
169169
(this.inputElementRef().nativeElement as HTMLInputElement).value = currentValue;
170170
this.picker.dates.formatInput = (date: DateTime) => date?this.formattingService.format(date, this.format(), false):'';
171171
this.picker.dates.parseInput = (value: string) => {
172-
const parsed = this.formattingService.parse(value?value.trim():null, this.format(), true, this.dataProviderID(), true);
172+
const parsed = this.formattingService.parse(value?value.trim():null, this.format(), true, this._dataProviderID(), true);
173173
if (parsed instanceof Date && !isNaN(parsed.getTime())) return DateTime.convert(parsed, null, this.config.localization);
174174
return null;
175175
};

components/projects/bootstrapcomponents/src/calendarinline/calendarinline.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export class ServoyBootstrapCalendarinline extends ServoyBootstrapBaseCalendar {
2323

2424
public svyOnInit() {
2525
super.svyOnInit();
26-
const dataProviderID = this.dataProviderID();
26+
const dataProviderID = this._dataProviderID();
2727
if (dataProviderID)
2828
this.picker.dates.setFromInput(dataProviderID);
2929
}
@@ -39,7 +39,7 @@ export class ServoyBootstrapCalendarinline extends ServoyBootstrapBaseCalendar {
3939
this.picker.dispose();
4040
this.picker = null;
4141
this.initializePicker();
42-
const dataProviderID = this.dataProviderID();
42+
const dataProviderID = this._dataProviderID();
4343
const value = (dataProviderID instanceof Date) ? DateTime.convert(dataProviderID, null, this.config.localization) : null;
4444
this.picker.dates.setValue(value);
4545
}

components/projects/bootstrapcomponents/src/checkbox/checkbox.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,16 @@ export class ServoyBootstrapCheckbox extends ServoyBootstrapBasefield<HTMLDivEle
6565
this.selected = !this.selected;
6666
event.preventDefault();
6767
}
68-
const dataProviderID = this.dataProviderID();
68+
const dataProviderID = this._dataProviderID();
6969
const selectedValue = this.selectedValue();
7070
if (selectedValue) {
71-
this.dataProviderID.set(this.dataProviderID() == selectedValue ? null : selectedValue);
71+
this._dataProviderID.set(this._dataProviderID() == selectedValue ? null : selectedValue);
7272
}
7373
else
7474
if (typeof dataProviderID === 'string') {
75-
this.dataProviderID.set(dataProviderID === '1' ? '0' : '1');
75+
this._dataProviderID.set(dataProviderID === '1' ? '0' : '1');
7676
} else {
77-
this.dataProviderID.set(dataProviderID > 0 ? 0 : 1);
77+
this._dataProviderID.set(dataProviderID > 0 ? 0 : 1);
7878
}
7979
this.pushUpdate();
8080
}
@@ -84,7 +84,7 @@ export class ServoyBootstrapCheckbox extends ServoyBootstrapBasefield<HTMLDivEle
8484
}
8585

8686
getSelectionFromDataprovider() {
87-
const dataProviderID = this.dataProviderID();
87+
const dataProviderID = this._dataProviderID();
8888
if (!dataProviderID) {
8989
return false;
9090
}

components/projects/bootstrapcomponents/src/choicegroup/choicegroup.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
import { Component, OnInit, Renderer2, ElementRef, Directive, SimpleChanges, ChangeDetectorRef, ChangeDetectionStrategy, Inject, DOCUMENT, input, viewChild, model } from '@angular/core';
2+
import { Component, OnInit, Renderer2, ElementRef, Directive, SimpleChanges, ChangeDetectorRef, ChangeDetectionStrategy, Inject, DOCUMENT, input, viewChild, signal } from '@angular/core';
33
import { IValuelist } from '@servoy/public';
44
import { ServoyBootstrapBasefield } from '../bts_basefield';
55

@@ -13,11 +13,13 @@ export class ServoyBootstrapChoicegroup extends ServoyBootstrapBasefield<HTMLDiv
1313

1414
readonly inputType = input<string>(undefined);
1515
readonly findmode = input<boolean>(undefined);
16-
valuelistID = model<IValuelist>(undefined);
16+
readonly valuelistID = input<IValuelist>(undefined);
1717
readonly showAs = input<string>(undefined);
1818
readonly alignment = input<string>(undefined);
1919

20-
readonly input = viewChild<ElementRef<HTMLInputElement>>('input');
20+
readonly input = viewChild<ElementRef<HTMLInputElement>>('input');
21+
22+
protected _valueProviderID = signal<IValuelist>(undefined);
2123

2224
selection: any[] = [];
2325
allowNullinc = 0;
@@ -27,24 +29,25 @@ export class ServoyBootstrapChoicegroup extends ServoyBootstrapBasefield<HTMLDiv
2729
super(renderer, cdRef, doc);
2830
}
2931

30-
svyOnInit() {
32+
svyOnInit() {
33+
this._valueProviderID.set(this.valuelistID());
3134
super.svyOnInit();
3235
}
3336

3437
svyOnChanges(changes: SimpleChanges) {
3538
super.svyOnChanges(changes);
36-
const valuelistID = this.valuelistID();
39+
const valuelistID = this._valueProviderID();
3740
if (this.servoyApi.isInDesigner() && !valuelistID) {
3841
// this should only happen in preview
39-
this.valuelistID.set([{ realValue: 1, displayValue: 'Item1' }, { realValue: 2, displayValue: 'Item2' }, { realValue: 3, displayValue: 'Item3' }] as IValuelist);
42+
this._valueProviderID.set([{ realValue: 1, displayValue: 'Item1' }, { realValue: 2, displayValue: 'Item2' }, { realValue: 3, displayValue: 'Item3' }] as IValuelist);
4043
}
4144
for (const property of Object.keys(changes)) {
4245
const change = changes[property];
4346
switch (property) {
4447
case 'dataProviderID':
4548
this.setSelectionFromDataprovider();
4649
if (change.firstChange){
47-
this.allowMultiselect = Array.isArray(this.dataProviderID());
50+
this.allowMultiselect = Array.isArray(this._dataProviderID());
4851
}
4952
break;
5053
case 'valuelistID':
@@ -97,7 +100,7 @@ export class ServoyBootstrapChoicegroup extends ServoyBootstrapBasefield<HTMLDiv
97100

98101
setSelectionFromDataprovider() {
99102
this.selection = [];
100-
const dataProviderID = this.dataProviderID();
103+
const dataProviderID = this._dataProviderID();
101104
if (dataProviderID === null || dataProviderID === undefined || (Array.isArray(dataProviderID) && dataProviderID.length == 1 && dataProviderID[0] == null)) return;
102105
const arr = (Array.isArray(dataProviderID)) ? dataProviderID : [dataProviderID];
103106
if (this.inputType() === 'radio' && arr.length > 1) return;
@@ -114,7 +117,7 @@ export class ServoyBootstrapChoicegroup extends ServoyBootstrapBasefield<HTMLDiv
114117
itemClicked(event, index) {
115118
let changed = true;
116119
if (this.inputType() === 'radio') {
117-
this.dataProviderID.set(this.valuelistID()[index + this.allowNullinc].realValue);
120+
this._dataProviderID.set(this.valuelistID()[index + this.allowNullinc].realValue);
118121
} else {
119122
const prevValue = this.selection[index];
120123
const findmode = this.findmode();
@@ -133,7 +136,7 @@ export class ServoyBootstrapChoicegroup extends ServoyBootstrapBasefield<HTMLDiv
133136
}
134137
}
135138
changed = prevValue !== this.selection[index];
136-
this.dataProviderID.set(this.getDataproviderFromSelection());
139+
this._dataProviderID.set(this.getDataproviderFromSelection());
137140
}
138141
if (changed) this.pushUpdate();
139142
event.target.blur();

components/projects/bootstrapcomponents/src/combobox/combobox.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ export class ServoyBootstrapCombobox extends ServoyBootstrapBasefield<HTMLDivEle
211211
this.valueComparator = valuelistID && valuelistID.isRealValueDate() ? this.dateValueCompare : this.valueCompare;
212212
const valuelistIDValue = this.valuelistID();
213213
if (changes['dataProviderID'] && this.findmode()) {
214-
this.formattedValue = this.dataProviderID();
214+
this.formattedValue = this._dataProviderID();
215215
} else if ((changes['dataProviderID'] || changes['valuelistID']) && valuelistIDValue) {
216216
if (this.valuelistDisplayValueSubscription !== null) {
217217
this.valuelistDisplayValueSubscription.unsubscribe();
@@ -222,10 +222,10 @@ export class ServoyBootstrapCombobox extends ServoyBootstrapBasefield<HTMLDivEle
222222
if (valueListElem) this.formattedValue = this.formatService.format(valueListElem.displayValue, this.format(), false);
223223
else {
224224
if (!valuelistIDValue.hasRealValues())
225-
this.formattedValue = this.formatService.format(this.dataProviderID(), this.format(), false);
225+
this.formattedValue = this.formatService.format(this._dataProviderID(), this.format(), false);
226226
else {
227227
this.formattedValue = null;
228-
this.valuelistDisplayValueSubscription = valuelistIDValue.getDisplayValue(this.dataProviderID()).subscribe(val => {
228+
this.valuelistDisplayValueSubscription = valuelistIDValue.getDisplayValue(this._dataProviderID()).subscribe(val => {
229229
this.valuelistDisplayValueSubscription = null;
230230
this.formattedValue = val;
231231
this.cdRef.detectChanges();
@@ -270,8 +270,8 @@ export class ServoyBootstrapCombobox extends ServoyBootstrapBasefield<HTMLDivEle
270270
}
271271

272272
updateValue(realValue: any, event: Event) {
273-
this.dataProviderID.set(realValue);
274-
this.dataProviderIDChange.emit(this.dataProviderID());
273+
this._dataProviderID.set(realValue);
274+
this.dataProviderIDChange.emit(this._dataProviderID());
275275
this.placeholderClass = null;
276276
const onActionMethodID = this.onActionMethodID();
277277
if (onActionMethodID) {
@@ -323,10 +323,10 @@ export class ServoyBootstrapCombobox extends ServoyBootstrapBasefield<HTMLDivEle
323323
}
324324

325325
// eslint-disable-next-line eqeqeq
326-
private valueCompare = (valueListValue: { displayValue: any; realValue: any }): boolean => valueListValue.realValue == this.dataProviderID();
326+
private valueCompare = (valueListValue: { displayValue: any; realValue: any }): boolean => valueListValue.realValue == this._dataProviderID();
327327

328328
private dateValueCompare = (valueListValue: { displayValue: any; realValue: Date }): boolean => {
329-
const dataProviderID = this.dataProviderID();
329+
const dataProviderID = this._dataProviderID();
330330
if (dataProviderID && valueListValue.realValue) {
331331
return valueListValue.realValue.getTime() === dataProviderID.getTime();
332332
}

0 commit comments

Comments
 (0)