NativeScript TextField [(ngModel)] does not work
Asked Answered
S

2

15

I have a problem with data binding in TextField via ngModel

I have model class

export class Product {
    name: string
    description: string
    imageUrl: string
}

View:

<GridLayout backgroundColor="red">
    <!--
    This part is for logged users
    -->
    <StackLayout
        [id]="container"
        [visibility]="isLogged ? 'visible' : 'collapse'">
            <Label text="Add product" textWrap="true"></Label>
            <TextField
                hint="product name"
                [(ngModel)]="product.name">
            </TextField>
            <TextField
                hint="product desc"
                [(ngModel)]="product.description">
            </TextField>
            <Button text="Zrób zdjęcie produktu" (tap)="didTapTakePhoto()">
            </Button>
            <Button text="Wyślij na serwer" (tap)="didTapSendProduct()">
            </Button>
            <Image #photo></Image>
    </StackLayout>

    <!--
    This part is for not logged users
    -->
    <StackLayout [visibility]="isLogged ? 'collapse' : 'visible'">
        <Label text="Musisz się zalogować!" textWrap="true"></Label>
    </StackLayout>

</GridLayout>

and Controller:

import { Component, OnInit, OnDestroy, ViewChild, ElementRef } from "@angular/core"
import * as Firebase from "nativescript-plugin-firebase"
import * as camera from "nativescript-camera";
import { Image } from "ui/image";
import { ImageAsset } from "image-asset"
import { ImageSource } from "image-source"
import { Product } from "../../shared"

@Component({
    selector: "AddProductComponent",
    templateUrl: "tabs/addProduct/addProduct.html"
})
export class AddProductComponent implements OnInit, OnDestroy {

    @ViewChild("photo") photoRef: ElementRef
    filePath: string
    isLogged: boolean = true

    product: Product

    listener = {
        onAuthStateChanged: function(data) {
            this.isLogged = data.loggedIn
        },
        thisArg: this
    }

    constructor() {
        this.product = new Product()
        this.product.name = "Name"
        this.product.description = "Desc"
    }

    ngOnInit(): void {
        Firebase.addAuthStateListener(this.listener)
        camera.requestPermissions()
    }

    ngOnDestroy(): void {
        Firebase.removeAuthStateListener(this.listener)
    }

    didTapTakePhoto() {
        // init the file-system module
        var fs = require("file-system");
        // grab a reference to the app folder
        var appPath = fs.knownFolders.currentApp().path;
        // determine the path to a file in the app/res folder
        this.filePath = appPath + "/cached_product_photo.png";

        camera.takePicture()
            .then((imageAsset) => {
                let photo = <Image>this.photoRef.nativeElement
                photo.src = imageAsset
                let photoSrc = new ImageSource()
                photoSrc.fromAsset(imageAsset).then(image => {
                    console.log("Result: " + image)
                    image.saveToFile(this.filePath, "png")
                })
            })
            .catch((err) => {
                console.log("Error -> " + err.message)
            });
    }

    didTapSendProduct() {
        console.log(this.product.name)
        console.log(this.product.description)
    }

    focusDescription() {
        console.log(this.product.name)
    }

    //TODO: move to separate file/import some more professional uuid generator?/
    // find any other way to distinguish betweeen photos
    getUUID() {
        function s4() {
            return Math.floor((1 + Math.random()) * 0x10000)
                .toString(16)
                .substring(1)
        }
        return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4()
            + s4() + s4()
    }
}

When I run my app on iOS device

  • textfields are empty (it shouldn't because of my implementation in constructor())
  • when I tap on send button a function didTapSendProduct() prints:

    CONSOLE LOG file:///app/tabs/addProduct/addProduct.component.js:51:20: Name

    CONSOLE LOG file:///app/tabs/addProduct/addProduct.component.js:52:20: Desc

    no matter what is set in textfields

Note that I have set NativeScriptFormsModule in my imports:

import { NgModule, NgModuleFactoryLoader } from "@angular/core";
import { NativeScriptFormsModule } from "nativescript-angular/forms";
import { NativeScriptModule } from "nativescript-angular/nativescript.module";
import { NSModuleFactoryLoader } from "nativescript-angular/router";

import { AppComponent } from "./app.component";
import { AppRoutingModule } from "./app-routing.module";

@NgModule({
    bootstrap: [
        AppComponent
    ],
    imports: [
        NativeScriptModule,
        AppRoutingModule,
        NativeScriptFormsModule
    ],
    declarations: [
        AppComponent
    ],
    providers: [
        { provide: NgModuleFactoryLoader, useClass: NSModuleFactoryLoader }
    ]
})
export class AppModule { }
Sarraute answered 16/9, 2017 at 12:23 Comment(1)
Do you have others modules than AppModule? if your component belong to another module make sure NativeScriptFormsModule is imported in that module!Korten
K
40

Make sure you import NativeScriptFormsModule on the module that declare AddProductComponent Component not only in AppModule.

Example:

componentName.module.ts

import { NativeScriptCommonModule, NativeScriptFormsModule } from "nativescript-angular";
import { ComponentName } from "./componentName.component";

@NgModule({
  imports: [
    NativeScriptFormsModule
  ],
  declarations: [
    ComponentName
  ],
  schemas: [
    NO_ERRORS_SCHEMA
  ]
})
export class ComponentModule { }
Korten answered 18/9, 2017 at 8:51 Comment(4)
You are welcome. You are not the first that ask this question! I passed hours to find out why the two way databinding not working!Korten
Could you recommend a good source to read about Modules and Components conception? Blog or book?Sarraute
You can read about angular fundamentals from the official site angular.io/guide/architecture and the nativescript ng-tutorial docs.nativescript.org/tutorial/ng-chapter-0Korten
I've adjusted this answer to include an example and fixed a grammar error.Prague
P
0

you can do this

view

<TextField [(ngModel)]="your_binding"></TextField>

module

import { NativeScriptCommonModule, NativeScriptFormsModule } from '@nativescript/angular';
import { YourComponent } from "../foo"
@NgModule({
  imports: [
    NativeScriptCommonModule,
    NativeScriptFormsModule
 ],
  exports: [],
  declarations: [
     YourComponent
  ],
  providers: [],
  schemas: [
    NO_ERRORS_SCHEMA
  ]
})

its works for me

Playlet answered 5/1, 2021 at 8:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.