NativeScript TextField [(ngModel)] does not work
Asked 07 September, 2021
Viewed 2.7K times
  • 52
Votes

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 { }

2 Answer