Skip to content

Commit 44009dd

Browse files
committed
feat(forms): Enable reactive forms.
Add control[formControlName] selectors to value accessor directives.
1 parent a68649d commit 44009dd

9 files changed

+52
-14
lines changed

Diff for: nativescript-angular/value-accessors/base-value-accessor.ts

+17
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
import { ControlValueAccessor } from "@angular/forms";
22

3+
export function generateValueAccessorSelector(...tagNames: string[]): string {
4+
const tags: string[] = [];
5+
tagNames.forEach(tagName => {
6+
tags.push(tagName); // regular tag
7+
tags.push(tagName.charAt(0).toLowerCase() + tagName.slice(1)); // lowercase first char
8+
tags.push(tagName.split(/(?=[A-Z])/).join("-").toLowerCase()); // kebab case
9+
});
10+
11+
const selectors = [];
12+
for (const tag of tags) {
13+
for (const directive of ["ngModel", "formControlName"]) {
14+
selectors.push(`${tag}[${directive}]`);
15+
}
16+
}
17+
return selectors.join(", ");
18+
}
19+
320
export class BaseValueAccessor<TView> implements ControlValueAccessor {
421
constructor(public view: TView) { }
522

Diff for: nativescript-angular/value-accessors/checked-value-accessor.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Directive, ElementRef, forwardRef, HostListener } from "@angular/core";
22
import { NG_VALUE_ACCESSOR } from "@angular/forms";
33
import { isBlank } from "../lang-facade";
4-
import { BaseValueAccessor } from "./base-value-accessor";
4+
import { BaseValueAccessor, generateValueAccessorSelector } from "./base-value-accessor";
55
import { Switch } from "ui/switch";
66

77
const CHECKED_VALUE_ACCESSOR = {provide: NG_VALUE_ACCESSOR,
@@ -17,7 +17,7 @@ const CHECKED_VALUE_ACCESSOR = {provide: NG_VALUE_ACCESSOR,
1717
* ```
1818
*/
1919
@Directive({
20-
selector: "Switch[ngModel], switch[ngModel]", // tslint:disable-line:directive-selector
20+
selector: generateValueAccessorSelector("Switch"),
2121
providers: [CHECKED_VALUE_ACCESSOR]
2222
})
2323
export class CheckedValueAccessor extends BaseValueAccessor<Switch> { // tslint:disable-line:directive-class-suffix

Diff for: nativescript-angular/value-accessors/date-value-accessor.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Directive, ElementRef, forwardRef, HostListener } from "@angular/core";
22
import { NG_VALUE_ACCESSOR } from "@angular/forms";
33
import { isBlank, isDate } from "../lang-facade";
4-
import { BaseValueAccessor } from "./base-value-accessor";
4+
import { BaseValueAccessor, generateValueAccessorSelector } from "./base-value-accessor";
55
import { DatePicker } from "ui/date-picker";
66

77
const DATE_VALUE_ACCESSOR = {provide: NG_VALUE_ACCESSOR,
@@ -17,7 +17,7 @@ const DATE_VALUE_ACCESSOR = {provide: NG_VALUE_ACCESSOR,
1717
* ```
1818
*/
1919
@Directive({
20-
selector: "DatePicker[ngModel], datePicker[ngModel], date-picker[ngModel]", // tslint:disable-line:max-line-length directive-selector
20+
selector: generateValueAccessorSelector("DatePicker"),
2121
providers: [DATE_VALUE_ACCESSOR]
2222
})
2323
export class DateValueAccessor extends BaseValueAccessor<DatePicker> { // tslint:disable-line:directive-class-suffix

Diff for: nativescript-angular/value-accessors/number-value-accessor.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Directive, ElementRef, forwardRef, HostListener } from "@angular/core";
22
import { NG_VALUE_ACCESSOR } from "@angular/forms";
33
import { isBlank, isNumber } from "../lang-facade";
4-
import { BaseValueAccessor } from "./base-value-accessor";
4+
import { BaseValueAccessor, generateValueAccessorSelector } from "./base-value-accessor";
55
import { Slider } from "ui/slider";
66

77
const NUMBER_VALUE_ACCESSOR = {provide: NG_VALUE_ACCESSOR,
@@ -17,7 +17,7 @@ const NUMBER_VALUE_ACCESSOR = {provide: NG_VALUE_ACCESSOR,
1717
* ```
1818
*/
1919
@Directive({
20-
selector: "Slider[ngModel], slider[ngModel]", // tslint:disable-line:directive-selector
20+
selector: generateValueAccessorSelector("Slider"),
2121
providers: [NUMBER_VALUE_ACCESSOR]
2222
})
2323
export class NumberValueAccessor extends BaseValueAccessor<Slider> { // tslint:disable-line:directive-class-suffix

Diff for: nativescript-angular/value-accessors/selectedIndex-value-accessor.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Directive, ElementRef, forwardRef, AfterViewInit, HostListener } from "@angular/core";
22
import { NG_VALUE_ACCESSOR } from "@angular/forms";
3-
import { BaseValueAccessor } from "./base-value-accessor";
3+
import { BaseValueAccessor, generateValueAccessorSelector } from "./base-value-accessor";
44
import { View } from "ui/core/view";
55
import { convertToInt } from "../common/utils";
66

@@ -19,7 +19,7 @@ export type SelectableView = {selectedIndex: number} & View;
1919
* ```
2020
*/
2121
@Directive({
22-
selector: "SegmentedBar[ngModel], segmentedBar[ngModel], segmented-bar[ngModel], ListPicker[ngModel], listPicker[ngModel], list-picker[ngModel], TabView[ngModel], tabView[ngModel], tab-view[ngModel]", // tslint:disable-line:max-line-length directive-selector
22+
selector: generateValueAccessorSelector("SegmentedBar", "ListPicker", "TabView"),
2323
providers: [SELECTED_INDEX_VALUE_ACCESSOR]
2424
})
2525
export class SelectedIndexValueAccessor extends BaseValueAccessor<SelectableView> implements AfterViewInit { // tslint:disable-line:max-line-length directive-class-suffix

Diff for: nativescript-angular/value-accessors/text-value-accessor.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Directive, ElementRef, forwardRef, HostListener } from "@angular/core";
22
import { NG_VALUE_ACCESSOR } from "@angular/forms";
33
import { isBlank } from "../lang-facade";
4-
import { BaseValueAccessor } from "./base-value-accessor";
4+
import { BaseValueAccessor, generateValueAccessorSelector } from "./base-value-accessor";
55
import { View } from "ui/core/view";
66

77
const TEXT_VALUE_ACCESSOR = {provide: NG_VALUE_ACCESSOR,
@@ -19,7 +19,7 @@ export type TextView = {text: string} & View;
1919
* ```
2020
*/
2121
@Directive({
22-
selector: "TextField[ngModel], textField[ngModel], text-field[ngModel], TextView[ngModel], textView[ngModel], text-view[ngModel], SearchBar[ngModel], search-bar[ngModel], searchBar[ngModel]", // tslint:disable-line:max-line-length directive-selector
22+
selector: generateValueAccessorSelector("TextField", "TextView", "SearchBar"),
2323
providers: [TEXT_VALUE_ACCESSOR]
2424
})
2525
export class TextValueAccessor extends BaseValueAccessor<TextView> { // tslint:disable-line:directive-class-suffix

Diff for: nativescript-angular/value-accessors/time-value-accessor.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Directive, ElementRef, forwardRef, HostListener } from "@angular/core";
22
import { NG_VALUE_ACCESSOR } from "@angular/forms";
33
import { isBlank, isDate } from "../lang-facade";
4-
import { BaseValueAccessor } from "./base-value-accessor";
4+
import { BaseValueAccessor, generateValueAccessorSelector } from "./base-value-accessor";
55
import { TimePicker } from "ui/time-picker";
66

77
const TIME_VALUE_ACCESSOR = {provide: NG_VALUE_ACCESSOR,
@@ -17,7 +17,7 @@ const TIME_VALUE_ACCESSOR = {provide: NG_VALUE_ACCESSOR,
1717
* ```
1818
*/
1919
@Directive({
20-
selector: "TimePicker[ngModel], timePicker[ngModel], time-picker[ngModel]", // tslint:disable-line:max-line-length directive-selector
20+
selector: generateValueAccessorSelector("TimePicker"),
2121
providers: [TIME_VALUE_ACCESSOR]
2222
})
2323
export class TimeValueAccessor extends BaseValueAccessor<TimePicker> { // tslint:disable-line:directive-class-suffix

Diff for: tests/app/tests/value-accessor-tests.ts

+22-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {TimePicker} from "ui/time-picker";
88
import {ListPicker} from "ui/list-picker";
99
import {TextField} from "ui/text-field";
1010
import {
11+
generateValueAccessorSelector,
1112
NumberValueAccessor,
1213
CheckedValueAccessor,
1314
DateValueAccessor,
@@ -100,7 +101,7 @@ describe("two-way binding via ng-model", () => {
100101

101102
it("converts strings to int selection", () => {
102103
const accessor = new TestSelectedIndexValueAccessor()
103-
104+
104105
accessor.writeValue(null);
105106
accessor.ngAfterViewInit();
106107
assert.strictEqual(0, accessor.view.selectedIndex, "default to 0 on empty")
@@ -143,6 +144,26 @@ describe("two-way binding via ng-model", () => {
143144
});
144145
})
145146

147+
describe("target selector registration", () => {
148+
it("supports uppercase(unchanged) camel tags", () => {
149+
assert.include(generateValueAccessorSelector("TextField"), "TextField[ngModel]");
150+
});
151+
it("supports lowercase camel tags", () => {
152+
assert.include(generateValueAccessorSelector("TextField"), "textField[ngModel]");
153+
});
154+
it("supports kebab case tags", () => {
155+
assert.include(generateValueAccessorSelector("TextField"), "text-field[ngModel]");
156+
});
157+
it("supports formControlName", () => {
158+
assert.include(generateValueAccessorSelector("TextField"), "TextField[formControlName]");
159+
});
160+
it("supports multiple tags", () => {
161+
const selector = generateValueAccessorSelector("TextField", "TextView");
162+
assert.include(selector, "TextField[ngModel]");
163+
assert.include(selector, "TextField[formControlName]");
164+
});
165+
});
166+
146167
function formatDate(date: Date) {
147168
return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
148169
}

Diff for: tests/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"nativescript": {
33
"id": "org.nativescript.ngtests",
44
"tns-android": {
5-
"version": "2.4.0"
5+
"version": "2.4.1"
66
},
77
"tns-ios": {
88
"version": "2.4.0"

0 commit comments

Comments
 (0)