Skip to content

Commit 309ea14

Browse files
author
Hristo Hristov
authored
Fix setting text property to number. (#3449)
Fix setting JS property from native.
1 parent e3acdcb commit 309ea14

23 files changed

Lines changed: 156 additions & 153 deletions

‎tns-core-modules/data/observable/observable.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,4 +275,4 @@ export function fromObjectRecursive(source: any): Observable {
275275
let observable = new Observable();
276276
addPropertiesFromObject(observable, source, true);
277277
return observable;
278-
}
278+
}

‎tns-core-modules/ui/core/properties.ts‎

Lines changed: 68 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { unsetValue } from "ui/core/dependency-observable";
22
import { WrappedValue } from "data/observable";
33
import { ViewBase } from "./view-base";
44
import { Style } from "ui/styling/style";
5+
import * as definitions from "ui/core/view-base";
56

67
export { unsetValue, Style };
78

@@ -31,44 +32,21 @@ const enum ValueSource {
3132
Local = 3
3233
}
3334

34-
export interface PropertyOptions<T, U> {
35-
name: string;
36-
defaultValue?: U;
37-
affectsLayout?: boolean;
38-
equalityComparer?(this: void, x: U, y: U): boolean;
39-
valueChanged?(this: void, target: T, oldValue: U, newValue: U): void;
40-
valueConverter?(this: void, value: string): U;
41-
}
42-
43-
export interface CoerciblePropertyOptions<T, U> extends PropertyOptions<T, U> {
44-
readonly coerceValue: (t: T, u: U) => U;
45-
}
46-
47-
export interface ShorthandPropertyOptions<P> {
48-
name: string;
49-
cssName: string;
50-
converter(this: void, value: string | P): [CssProperty<any, any>, any][];
51-
getter(this: Style): string | P;
52-
}
53-
54-
export interface CssPropertyOptions<T extends Style, U> extends PropertyOptions<T, U> {
55-
cssName: string;
56-
}
57-
58-
export class Property<T extends ViewBase, U> implements PropertyDescriptor {
35+
export class Property<T extends ViewBase, U> implements PropertyDescriptor, definitions.Property<T, U> {
5936
private registered: boolean;
6037
private readonly name: string;
6138
public readonly key: symbol;
6239
public readonly native: symbol;
6340
public readonly defaultValueKey: symbol;
6441
public readonly defaultValue: U;
42+
public readonly nativeValueChange: (owner: T, value: U) => void;
6543

6644
public get: () => U;
6745
public set: (value: U) => void;
6846
public enumerable: boolean = true;
6947
public configurable: boolean = true;
7048

71-
constructor(options: PropertyOptions<T, U>) {
49+
constructor(options: definitions.PropertyOptions<T, U>) {
7250
const name = options.name;
7351
this.name = name;
7452

@@ -85,12 +63,12 @@ export class Property<T extends ViewBase, U> implements PropertyDescriptor {
8563
this.defaultValue = defaultValue;
8664

8765
const eventName = name + "Change";
88-
const affectsLayout: boolean = options.affectsLayout;
8966
const equalityComparer = options.equalityComparer;
67+
const affectsLayout: boolean = options.affectsLayout;
9068
const valueChanged = options.valueChanged;
9169
const valueConverter = options.valueConverter;
9270

93-
this.set = function (this: T, value: any): void {
71+
this.set = function (this: T, value: U): void {
9472
const reset = value === unsetValue;
9573
let unboxedValue: U;
9674
let wrapped: boolean;
@@ -146,10 +124,34 @@ export class Property<T extends ViewBase, U> implements PropertyDescriptor {
146124
}
147125
}
148126

149-
this.get = function (): U {
127+
this.get = function (this: T): U {
150128
return key in this ? this[key] : defaultValue;
151129
}
152130

131+
this.nativeValueChange = function (owner: T, value: U): void {
132+
const currentValue = key in owner ? owner[key] : defaultValue;
133+
const changed = equalityComparer ? !equalityComparer(currentValue, value) : currentValue !== value;
134+
if (changed) {
135+
owner[key] = value;
136+
if (valueChanged) {
137+
valueChanged(owner, currentValue, value);
138+
}
139+
140+
if (owner.hasListeners(eventName)) {
141+
owner.notify({
142+
eventName: eventName,
143+
propertyName: name,
144+
object: owner,
145+
value: value
146+
});
147+
}
148+
149+
if (affectsLayout) {
150+
owner.requestLayout();
151+
}
152+
}
153+
}
154+
153155
symbolPropertyMap[key] = this;
154156
}
155157

@@ -162,13 +164,14 @@ export class Property<T extends ViewBase, U> implements PropertyDescriptor {
162164
}
163165
}
164166

165-
export class CoercibleProperty<T extends ViewBase, U> implements PropertyDescriptor {
167+
export class CoercibleProperty<T extends ViewBase, U> implements PropertyDescriptor, definitions.CoercibleProperty<T, U> {
166168
private registered: boolean;
167169
private readonly name: string;
168170
public readonly key: symbol;
169171
public readonly native: symbol;
170172
public readonly defaultValueKey: symbol;
171173
public readonly defaultValue: U;
174+
public readonly nativeValueChange: (owner: T, value: U) => void;
172175

173176
public readonly get: () => U;
174177
public readonly set: (value: U) => void;
@@ -177,7 +180,7 @@ export class CoercibleProperty<T extends ViewBase, U> implements PropertyDescrip
177180

178181
public readonly coerce: (target: T) => void;
179182

180-
constructor(options: CoerciblePropertyOptions<T, U>) {
183+
constructor(options: definitions.CoerciblePropertyOptions<T, U>) {
181184
const name = options.name;
182185
this.name = name;
183186

@@ -272,6 +275,31 @@ export class CoercibleProperty<T extends ViewBase, U> implements PropertyDescrip
272275
return key in this ? this[key] : defaultValue;
273276
}
274277

278+
this.nativeValueChange = function (owner: T, value: U): void {
279+
const currentValue = key in owner ? owner[key] : defaultValue;
280+
const changed = equalityComparer ? !equalityComparer(currentValue, value) : currentValue !== value;
281+
if (changed) {
282+
owner[key] = value;
283+
owner[coerceKey] = value;
284+
if (valueChanged) {
285+
valueChanged(owner, currentValue, value);
286+
}
287+
288+
if (owner.hasListeners(eventName)) {
289+
owner.notify({
290+
eventName: eventName,
291+
propertyName: name,
292+
object: owner,
293+
value: value
294+
});
295+
}
296+
297+
if (affectsLayout) {
298+
owner.requestLayout();
299+
}
300+
}
301+
}
302+
275303
symbolPropertyMap[key] = this;
276304
}
277305

@@ -284,11 +312,11 @@ export class CoercibleProperty<T extends ViewBase, U> implements PropertyDescrip
284312
}
285313
}
286314

287-
export class InheritedProperty<T extends ViewBase, U> extends Property<T, U> {
315+
export class InheritedProperty<T extends ViewBase, U> extends Property<T, U> implements definitions.InheritedProperty<T, U> {
288316
public readonly sourceKey: symbol;
289317
public readonly setInheritedValue: (value: U) => void;
290318

291-
constructor(options: PropertyOptions<T, U>) {
319+
constructor(options: definitions.PropertyOptions<T, U>) {
292320
super(options);
293321
const name = options.name;
294322
const key = this.key;
@@ -369,7 +397,7 @@ export class InheritedProperty<T extends ViewBase, U> extends Property<T, U> {
369397
}
370398
}
371399

372-
export class CssProperty<T extends Style, U> {
400+
export class CssProperty<T extends Style, U> implements definitions.CssProperty<T, U> {
373401
private registered: boolean;
374402

375403
public readonly name: string;
@@ -384,7 +412,7 @@ export class CssProperty<T extends Style, U> {
384412
public readonly defaultValueKey: symbol;
385413
public readonly defaultValue: U;
386414

387-
constructor(options: CssPropertyOptions<T, U>) {
415+
constructor(options: definitions.CssPropertyOptions<T, U>) {
388416
const name = options.name;
389417
this.name = name;
390418

@@ -559,10 +587,10 @@ export class CssProperty<T extends Style, U> {
559587
}
560588
}
561589

562-
export class InheritedCssProperty<T extends Style, U> extends CssProperty<T, U> {
590+
export class InheritedCssProperty<T extends Style, U> extends CssProperty<T, U> implements definitions.InheritedCssProperty<T,U> {
563591
public setInheritedValue: (value: U) => void;
564592

565-
constructor(options: CssPropertyOptions<T, U>) {
593+
constructor(options: definitions.CssPropertyOptions<T, U>) {
566594
super(options);
567595
const name = options.name;
568596

@@ -684,7 +712,7 @@ export class InheritedCssProperty<T extends Style, U> extends CssProperty<T, U>
684712
}
685713
}
686714

687-
export class ShorthandProperty<T extends Style, P> {
715+
export class ShorthandProperty<T extends Style, P> implements definitions.ShorthandProperty<T, P> {
688716
private registered: boolean;
689717

690718
public readonly key: symbol;
@@ -697,7 +725,7 @@ export class ShorthandProperty<T extends Style, P> {
697725
public readonly native: symbol;
698726
public readonly sourceKey: symbol;
699727

700-
constructor(options: ShorthandPropertyOptions<P>) {
728+
constructor(options: definitions.ShorthandPropertyOptions<P>) {
701729
const name = options.name;
702730
this.name = name;
703731

@@ -712,7 +740,7 @@ export class ShorthandProperty<T extends Style, P> {
712740

713741
const converter = options.converter;
714742

715-
function setLocalValue(this: T, value: string| P): void {
743+
function setLocalValue(this: T, value: string | P): void {
716744
this[sourceKey] = ValueSource.Local;
717745
if (this[key] !== value) {
718746
this[key] = value;

‎tns-core-modules/ui/core/view-base.ts‎

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -374,20 +374,6 @@ export class ViewBase extends Observable implements ViewBaseDefinition {
374374
}
375375
}
376376

377-
// public _setCore(data: PropertyChangeData) {
378-
// super._setCore(data);
379-
// this._updateTwoWayBinding(data.propertyName, data.value);
380-
// }
381-
382-
public nativePropertyChanged(property: Property<ViewBase, any>, newValue: any): void {
383-
if (this._updatingJSPropertiesDict[property.native]) {
384-
return;
385-
}
386-
this._updatingJSPropertiesDict[property.native] = true;
387-
property.set.call(this, newValue);
388-
delete this._updatingJSPropertiesDict[property.native];
389-
}
390-
391377
public requestLayout(): void {
392378
//
393379
}

‎tns-core-modules/ui/core/view.d.ts‎

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -543,14 +543,8 @@ declare module "ui/core/view" {
543543
public eachChildView(callback: (view: View) => boolean): void;
544544

545545
//@private
546-
/**
547-
* A property has changed on the native side directly - e.g. the user types in a TextField.
548-
*/
549-
public nativePropertyChanged(property: Property<any, any>, newValue: any): void;
550-
551546
isLayoutRequired: boolean;
552547
_gestureObservers: any;
553-
// _isInheritedChange(): boolean;
554548

555549
_updateLayout(): void;
556550

‎tns-core-modules/ui/date-picker/date-picker.android.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,22 @@ class DateChangedListener extends java.lang.Object implements android.widget.Dat
2020

2121
let dateIsChanged = false;
2222
if (year !== owner.year) {
23-
owner.nativePropertyChanged(yearProperty, year);
23+
yearProperty.nativeValueChange(owner, year);
2424
dateIsChanged = true;
2525
}
2626

2727
if ((month + 1) !== owner.month) {
28-
owner.nativePropertyChanged(monthProperty, month + 1);
28+
monthProperty.nativeValueChange(owner, month + 1);
2929
dateIsChanged = true;
3030
}
3131

3232
if (day !== owner.day) {
33-
owner.nativePropertyChanged(dayProperty, day);
33+
dayProperty.nativeValueChange(owner, day);
3434
dateIsChanged = true;
3535
}
3636

3737
if (dateIsChanged) {
38-
owner.nativePropertyChanged(dateProperty, new Date(year, month, day));
38+
dateProperty.nativeValueChange(owner, new Date(year, month, day));
3939
}
4040
}
4141
}

‎tns-core-modules/ui/date-picker/date-picker.ios.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,22 +115,22 @@ class UIDatePickerChangeHandlerImpl extends NSObject {
115115

116116
let dateChanged = false;
117117
if (comps.year !== owner.year) {
118-
owner.nativePropertyChanged(yearProperty, comps.year);
118+
yearProperty.nativeValueChange(owner, comps.year);
119119
dateChanged = true;
120120
}
121121

122122
if (comps.month !== owner.month) {
123-
owner.nativePropertyChanged(monthProperty, comps.month);
123+
monthProperty.nativeValueChange(owner, comps.month);
124124
dateChanged = true;
125125
}
126126

127127
if (comps.day !== owner.day) {
128-
owner.nativePropertyChanged(dayProperty, comps.day);
128+
dayProperty.nativeValueChange(owner, comps.day);
129129
dateChanged = true;
130130
}
131131

132132
if (dateChanged) {
133-
owner.nativePropertyChanged(dateProperty, new Date(comps.year, comps.month - 1, comps.day));
133+
dateProperty.nativeValueChange(owner, new Date(comps.year, comps.month - 1, comps.day));
134134
}
135135
}
136136

‎tns-core-modules/ui/definitions.d.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ declare module "ui/core/properties" {
209209
public readonly native: symbol;
210210
public readonly defaultValue: U;
211211
public register(cls: { prototype: T }): void;
212+
public nativeValueChange(T, U): void;
212213
}
213214

214215
export class CoercibleProperty<T extends ViewBase, U> implements TypedPropertyDescriptor<U> {
@@ -218,6 +219,7 @@ declare module "ui/core/properties" {
218219
public readonly defaultValue: U;
219220
public readonly coerce: (target: T) => void;
220221
public register(cls: { prototype: T }): void;
222+
public nativeValueChange(T, U): void;
221223
}
222224

223225
export class InheritedProperty<T extends ViewBase, U> extends Property<T, U> {

‎tns-core-modules/ui/editable-text-base/editable-text-base.android.ts‎

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class TextWatcher extends java.lang.Object implements android.text.TextWatcher {
4747
owner._dirtyTextAccumulator = editable.toString();
4848
break;
4949
case "textChanged":
50-
owner.nativePropertyChanged(textProperty, editable.toString());
50+
textProperty.nativeValueChange(owner, editable.toString());
5151
break;
5252
default:
5353
throw new Error("Invalid updateTextTrigger: " + owner.updateTextTrigger);
@@ -81,7 +81,7 @@ class FocusChangeListener extends java.lang.Object implements android.view.View.
8181
}
8282
else {
8383
if (owner._dirtyTextAccumulator) {
84-
owner.nativePropertyChanged(textProperty, owner._dirtyTextAccumulator);
84+
textProperty.nativeValueChange(owner, owner._dirtyTextAccumulator);
8585
owner._dirtyTextAccumulator = undefined;
8686
}
8787

@@ -220,13 +220,8 @@ export abstract class EditableTextBase extends EditableTextBaseCommon {
220220
return this._android.getText();
221221
}
222222
set [textProperty.native](value: string) {
223-
let newValue;
224-
if (value === null || value === void 0) {
225-
newValue = "";
226-
} else {
227-
newValue = value + "";
228-
}
229-
this._android.setText(newValue, android.widget.TextView.BufferType.EDITABLE);
223+
const text = (value === null || value === undefined) ? '' : value.toString();
224+
this._android.setText(text, android.widget.TextView.BufferType.EDITABLE);
230225
}
231226

232227
get [keyboardTypeProperty.native](): "datetime" | "phone" | "number" | "url" | "email" | string {

‎tns-core-modules/ui/list-picker/list-picker.android.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ class ValueChangeListener extends java.lang.Object implements android.widget.Num
2727
return global.__native(this);
2828
}
2929

30-
onValueChange(picker: android.widget.NumberPicker, oldVal: number, newVal: number): void {
30+
onValueChange(picker: android.widget.NumberPicker, oldValue: number, newValue: number): void {
3131
let owner = this.owner.get();
3232
if (owner) {
33-
owner.nativePropertyChanged(selectedIndexProperty, newVal);
33+
selectedIndexProperty.nativeValueChange(owner, newValue);
3434
}
3535
}
3636
}

0 commit comments

Comments
 (0)