diff --git a/README.md b/README.md index 1405aa7..05f435e 100644 --- a/README.md +++ b/README.md @@ -106,23 +106,48 @@ export function dropDownSelectedIndexChanged(args: SelectedIndexChangedEventData } ``` -## Angular 2 Example +## Angular +##### Migration to 3.0+ + +- Remove: +```typescript +registerElement("DropDown", () => require("nativescript-drop-down/drop-down").DropDown);` +``` +- Import `DropDownModule` in `NgModule`: +```typescript +import { DropDownModule } from “nativescript-drop-down/angular”; +… +@NgModule({ + … + imports: [ + … + DropDownModule, + … + ], + … +}) +``` + +##### Example Usage ```TypeScript // main.ts -import { platformNativeScriptDynamic, NativeScriptModule } from "nativescript-angular/platform"; import { NgModule } from "@angular/core"; +import { NativeScriptModule } from "nativescript-angular/nativescript.module"; +import { platformNativeScriptDynamic } from "nativescript-angular/platform"; +import { DropDownModule } from "nativescript-drop-down/angular"; import { AppComponent } from "./app.component"; -import { registerElement } from "nativescript-angular/element-registry"; - -registerElement("DropDown", () => require("nativescript-drop-down/drop-down").DropDown); @NgModule({ - declarations: [AppComponent], - bootstrap: [AppComponent], - imports: [NativeScriptModule], + declarations: [ AppComponent ], + bootstrap: [ AppComponent ], + imports: [ + NativeScriptModule, + DropDownModule, + ], }) -class AppComponentModule {} +class AppComponentModule { +} platformNativeScriptDynamic().bootstrapModule(AppComponentModule); ``` @@ -130,13 +155,24 @@ platformNativeScriptDynamic().bootstrapModule(AppComponentModule); ```HTML - - - - - + + + + ``` diff --git a/angular/index.ts b/angular/index.ts new file mode 100644 index 0000000..ad0c070 --- /dev/null +++ b/angular/index.ts @@ -0,0 +1,78 @@ +import { AfterViewInit, Directive, ElementRef, HostListener, Inject, NgModule, forwardRef } from "@angular/core"; +import { FormsModule, NG_VALUE_ACCESSOR } from "@angular/forms"; +import { BaseValueAccessor, registerElement } from "nativescript-angular"; +import { convertToInt } from "nativescript-angular/common/utils"; +import { View } from "tns-core-modules/ui/core/view"; + +registerElement("DropDown", () => require("../drop-down").DropDown); + +const SELECTED_INDEX_VALUE_ACCESSOR = {provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => SelectedIndexValueAccessor), multi: true}; + +export type SelectableView = {selectedIndex: number} & View; + +/** + * The accessor for setting a selectedIndex and listening to changes that is used by the + * {@link NgModel} directives. + * + * ### Example + * ``` + * + * ``` + */ +@Directive({ + // tslint:disable-next-line:max-line-length directive-selector + selector: "DropDown[ngModel], DropDown[formControlName], dropDown[ngModel], dropDown[formControlName], drop-down[ngModel], drop-down[formControlName]", + providers: [SELECTED_INDEX_VALUE_ACCESSOR] +}) +export class SelectedIndexValueAccessor extends BaseValueAccessor implements AfterViewInit { // tslint:disable-line:max-line-length directive-class-suffix + + private _normalizedValue: number; + private viewInitialized: boolean; + + constructor(@Inject(ElementRef) elementRef: ElementRef) { + super(elementRef.nativeElement); + } + + @HostListener("selectedIndexChange", ["$event"]) + public selectedIndexChangeListener(event: any) { + this.onChange(event.value); + } + + // tslint:disable-next-line:no-empty + public onTouched = () => { }; + + public writeValue(value: any): void { + if (value === undefined || value === null || value === "") { + this._normalizedValue = null; + } + else { + this._normalizedValue = convertToInt(value); + } + + if (this.viewInitialized) { + this.view.selectedIndex = this._normalizedValue; + } + } + + public ngAfterViewInit() { + this.viewInitialized = true; + this.view.selectedIndex = this._normalizedValue; + } + + public registerOnTouched(fn: () => void): void { this.onTouched = fn; } +} + +@NgModule({ + declarations: [ SelectedIndexValueAccessor ], + providers: [], + imports: [ + FormsModule + ], + exports: [ + FormsModule, + SelectedIndexValueAccessor + ] +}) +export class DropDownModule { +} diff --git a/demo-ng/app/app.module.ts b/demo-ng/app/app.module.ts index 565ad54..f43976a 100644 --- a/demo-ng/app/app.module.ts +++ b/demo-ng/app/app.module.ts @@ -4,6 +4,7 @@ import { AppRoutingModule } from "./app.routing"; import { AppComponent } from "./app.component"; import { DropDownComponent } from "./dropdown/dropdown.component"; +import { DropDownModule } from 'nativescript-drop-down/angular'; @NgModule({ bootstrap: [ @@ -11,6 +12,7 @@ import { DropDownComponent } from "./dropdown/dropdown.component"; ], imports: [ NativeScriptModule, + DropDownModule, AppRoutingModule ], declarations: [ diff --git a/demo-ng/app/dropdown/dropdown.component.html b/demo-ng/app/dropdown/dropdown.component.html index 35489d7..3c395c7 100644 --- a/demo-ng/app/dropdown/dropdown.component.html +++ b/demo-ng/app/dropdown/dropdown.component.html @@ -1,13 +1,29 @@ - - + - - - - - - + + + + + diff --git a/demo-ng/app/dropdown/dropdown.component.ts b/demo-ng/app/dropdown/dropdown.component.ts index 16520c5..bb6bb57 100644 --- a/demo-ng/app/dropdown/dropdown.component.ts +++ b/demo-ng/app/dropdown/dropdown.component.ts @@ -8,27 +8,30 @@ import { SelectedIndexChangedEventData, ValueList } from "nativescript-drop-down }) export class DropDownComponent implements OnInit { public selectedIndex: number = null; - public hint = "My Hint"; + public hint = "My Hint"; public items: ValueList; - public cssClass: string = "default"; + public cssClass: string = "default"; public ngOnInit() { this.items = new ValueList(); - for (let loop = 0; loop < 200; loop++) { - this.items.push({ value: `I${loop}`, display: `Item ${loop}`}); + for ( let loop = 0; loop < 200; loop++ ) { + this.items.push({ + value: `I${loop}`, + display: `Item ${loop}`, + }); } } public onchange(args: SelectedIndexChangedEventData) { - console.log(`Drop Down selected index changed from ${args.oldIndex} to ${args.newIndex}. New value is '${this.items.getValue(args.newIndex)}'`); - this.selectedIndex = args.newIndex; + console.log(`Drop Down selected index changed from ${args.oldIndex} to ${args.newIndex}. New value is "${this.items.getValue( + args.newIndex)}"`); } public onopen() { console.log("Drop Down opened."); } - + public changeStyles() { this.cssClass = "changed-styles"; - } + } } diff --git a/demo-ng/app/main.ts b/demo-ng/app/main.ts index 22f21ea..1057aef 100644 --- a/demo-ng/app/main.ts +++ b/demo-ng/app/main.ts @@ -1,10 +1,6 @@ // this import should be first in order to load some required settings (like globals and reflect-metadata) import { platformNativeScriptDynamic } from "nativescript-angular/platform"; -import { registerElement } from "nativescript-angular/element-registry"; - import { AppModule } from "./app.module"; -registerElement("DropDown", () => require("nativescript-drop-down/drop-down").DropDown); - platformNativeScriptDynamic().bootstrapModule(AppModule); diff --git a/demo-ng/package.json b/demo-ng/package.json index b1fab86..63cc3c1 100644 --- a/demo-ng/package.json +++ b/demo-ng/package.json @@ -15,15 +15,15 @@ "debug-ios": "npm uninstall nativescript-drop-down && tns debug ios --emulator" }, "dependencies": { - "@angular/animations": "4.0.0", - "@angular/common": "4.0.0", - "@angular/compiler": "4.0.0", - "@angular/core": "4.0.0", - "@angular/forms": "4.0.0", - "@angular/http": "4.0.0", - "@angular/platform-browser": "4.0.0", - "@angular/platform-browser-dynamic": "4.0.0", - "@angular/router": "4.0.0", + "@angular/animations": "^4.0.3", + "@angular/common": "^4.0.3", + "@angular/compiler": "^4.0.3", + "@angular/core": "^4.0.3", + "@angular/forms": "^4.0.3", + "@angular/http": "^4.0.3", + "@angular/platform-browser": "^4.0.3", + "@angular/platform-browser-dynamic": "^4.0.3", + "@angular/router": "^4.0.3", "nativescript-angular": "rc", "nativescript-drop-down": "file:../bin/dist", "reflect-metadata": "~0.1.8", diff --git a/drop-down.android.ts b/drop-down.android.ts index 3045df2..7bccc7e 100644 --- a/drop-down.android.ts +++ b/drop-down.android.ts @@ -73,12 +73,6 @@ export class DropDown extends DropDownBase { spinner.setOnTouchListener(touchListener); (spinner as any).touchListener = touchListener; - // When used in templates the selectedIndex changed event is fired before the native widget is init. - // So here we must set the inital value (if any) - if (!types.isNullOrUndefined(this.selectedIndex)) { - this.android.setSelection(this.selectedIndex + 1); // +1 for the hint first element - } - return spinner; } @@ -89,6 +83,12 @@ export class DropDown extends DropDownBase { nativeView.adapter.owner = new WeakRef(this); nativeView.itemSelectedListener.owner = new WeakRef(this); nativeView.touchListener.owner = new WeakRef(this); + + // When used in templates the selectedIndex changed event is fired before the native widget is init. + // So here we must set the inital value (if any) + if (!types.isNullOrUndefined(this.selectedIndex)) { + this.android.setSelection(this.selectedIndex + 1); // +1 for the hint first element + } } public disposeNativeView() { diff --git a/gruntfile.js b/gruntfile.js index f058a2b..f626cee 100644 --- a/gruntfile.js +++ b/gruntfile.js @@ -47,6 +47,9 @@ tsCompile: { cmd: "node ./node_modules/typescript/bin/tsc --project tsconfig.json --outDir " + localConfig.outDir }, + ngCompile: { + cmd: "node ./node_modules/.bin/ngc --project tsconfig.aot.json --outDir " + localConfig.outDir + }, tslint: { cmd: "node ./node_modules/tslint/bin/tslint --project tsconfig.json" }, @@ -65,6 +68,7 @@ "exec:tslint", "clean:build", "exec:tsCompile", + "exec:ngCompile", "copy" ]); grunt.registerTask("publish", [ diff --git a/package.json b/package.json index 86bbc75..e8d2aa0 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,10 @@ }, "devDependencies": { + "@angular/compiler-cli": "^4.0.3", + "@angular/core": "^4.0.3", + "@angular/forms": "^4.0.3", + "nativescript-angular": "rc", "typescript": "~2.2.2", "tslint": "^4.5.1", "tns-core-modules": "rc", diff --git a/tsconfig.aot.json b/tsconfig.aot.json new file mode 100644 index 0000000..db6f6c6 --- /dev/null +++ b/tsconfig.aot.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "noEmitOnError": true, + "noEmitHelpers": true, + "sourceMap": false, + "removeComments": true, + "declaration": true, + "experimentalDecorators": true, + "target": "es5", + "module": "commonjs", + "outDir": "bin/dist", + "lib": ["es6", "dom", "es2015.iterable"], + "rootDir": ".", + "baseUrl": ".", + "paths": { + "*": [ + "./node_modules/tns-core-modules/*", + "./node_modules/*" + ] + }, + "emitDecoratorMetadata": true, + "moduleResolution": "node" + }, + "files": [ + "angular/index.ts" + ], + "angularCompilerOptions": { + "skipTemplateCodegen": true + } +} \ No newline at end of file