NativeScript / nativescript-angular

Integrating NativeScript with Angular
http://docs.nativescript.org/angular/tutorial/ng-chapter-0
Apache License 2.0
1.22k stars 241 forks source link

FormBuilder to nativescript #526

Closed AyWa closed 7 years ago

AyWa commented 8 years ago

Hello everyone,

I used FormBuilder to my webapps, and now I am trying to use it to nativescript but I thinks it’s not possible because FormBuilder need an input. Is it possible to make it works?

thanks

VladimirAmiorkov commented 8 years ago

Hi @AyWa ,

Can you share with us which FormBuilder application or service you are referring to so that we can take a closer look at the specifics of it. We do have a dedicated RadDataForm that is coming to {N} + Angular in the next official release (1.5.0) of nativescript-telerik-ui-pro plugin which has been designed and developed to work and feel as all {N} components on both iOS and Android. You can take a look at our non Angular online documentation for more information regarding the RadDataForm component, the Angular 2 support as stated above is coming in a couple of days.

Keep in mind that NativeScript + Angular uses the well know web technology that we love but there is a difference in what is the end result, in web or hybrid technology the end result will be a WebView + HTML elements, in NativeScript you get truly native components which is the power of {N}. Having this in mind using a pure web HTML tools for creation of UI is not possible without embedding them inside the {N} application via WebViewer which has poor performance and does not create native components.

NathanWalker commented 8 years ago

@VladimirAmiorkov pretty sure @AyWa is referring to ReactiveFormsModule FormBuilder: https://github.com/angular/angular/blob/2.1.2/modules/%40angular/forms/src/form_providers.ts#L26-L38 http://blog.thoughtram.io/angular/2016/06/22/model-driven-forms-in-angular-2.html

I have been wanting to submit a PR to make that API work with nativescript-angular. Should be doable and I've heard many people desiring same thing.

AyWa commented 8 years ago

@VladimirAmiorkov @NathanWalker Yeah exactly, I am talking about ReactiveFormsModule FormBuilder

clarenceh commented 8 years ago

Hi everyone,

I have developed Angular2 for web for some time, and starts to explore NativeScript with Angular2.

I found this feature (NativeScript to support Angular2 Reactive Forms Module) is of great potential and really can help to simplify the development of form-base input page that requires more sophisticate data model processing and validation.

Base on my understanding, the key thing to do to integrate with Reactive Forms Module is to implement Angular Form module's ControlValueAccessor interface. Which I found in nativescript-angular, the class base-value-accessor.ts already is doing this (it's also needed to support the [(ngModel)] binding).

From the text-value-accessor.ts class, I found it has the following line: selector: "TextField[ngModel], textField[ngModel], text-field[ngModel], TextView[ngModel], textView[ngModel],

So it only support the NativeScript UI fields with the ngModel directive.

The ideal way is also to have it support the binding of a FromControl in the component. For example, instead of the following NS currently support: <TextField #usernameContainer id="username" class="mek-input" autocorrect="false" autocapitalizationType="none" [(ngModel)]="login.username" updateTextTrigger="focusLost" returnKeyType="next"> </TextField>

I can write something like the following (just like the web version): <TextField #usernameContainer id="username" class="mek-input" autocorrect="false" autocapitalizationType="none" formControlName="username" returnKeyType="next"> </TextField>

Note that the directive formControlName is used instead of the [(ngModel)] binding

And then in the component code, I can use Angular's FormBuilder to create the control programmatically: this.username = new FormControl(this.login.username, [Validators.required, Validators.minLength(3), Validators.maxLength(40)]);

Afterwards, the TextField will then "binded" to the FormControl, and Angular will take care of the data binding, validation, update the control's states (i.e. dirty, touched, valid, etc.), and others.

This way can make the experience much more align with the web development flow and have the following benefits:

I think this feature can definitely help developers who is already adopting this Data Model Driven Form approach in developing web applications.

I am very happy to help contribute to this feature. But as I am not that familiar with nativescript-angular and the in-depth details of Angular2, I may need some hint and guidance from your team.

Any other comments are much welcome and I really want to see this feature available in NativeScript.

Cheers Clarence

hdeshev commented 8 years ago

@clarenceh This looks great! Can you point me to an article describing what's needed for value accessors in order to support formControlName?

clarenceh commented 8 years ago

Hi @hdeshev,

The following is an excellent article which describes how to implement a custom Angular2 form control: http://blog.thoughtram.io/angular/2016/07/27/custom-form-controls-in-angular-2.html

As currently the text-value-accessor.ts and others were implemented as an Angular Directive, which has the selector hard-coded to TextField[ngModel]..., etc. I believe can simply change the selector text to the following and test it out: selector: "TextField[ngModel],TextField[formControlName]...

To test whether it works, can simply test with the following:

Then test to run the application to see if it works or not.

Currently, when I run the above code, I got the following error:

CONSOLE ERROR file:///app/tns_modules/trace/trace.js:160:30: ns-renderer: Error in app.component.html:4:15 caused by: Cannot find control with name: 'usernameControl'

I believe as currently the text field value accessor doesn't pick up the attribute "formControlName", so the binding not work and Angular doesn't found any property with ControlValueAccessor implemented.

Hope this helps. Clarence

dave-calleja commented 8 years ago

πŸ‘ on this, definitely a great addition to the codebase

hdeshev commented 7 years ago

I tried it out, and really the formControlName selector does the trick - my FormGroup got populated correctly. Pushed a PR with that.

clarenceh commented 7 years ago

Really glad to hear that and look forward for the NS 2.5 release so that we can start using it. Thanks a lot for the help.

derekdon commented 7 years ago

Is there a way to test this ahead of the release? I thought using the next tag as described here https://docs.nativescript.org/releases/running-latest might give me this functionality or npm linking to a master clone of the nativescript-angular repo but neither seemed to work.

coltcook commented 7 years ago

@derekdon I also have the same problem--was hoping to use this for a new feature. Now I have to choose between not using it or not implementing it and waiting for 2.5. πŸ‘Ž

Serge-SDL commented 7 years ago

Hello !

I have been unsuccessfully trying for 2 days to implement reactive form in Nativescript.

I have just written a simple component :

    export class HeroDetailComponent {
      name = new FormControl();
    }

with a simple template :

    <Label text="Hero Detail"></Label>
    <TextField [formControl]="name"></TextField>
    <Label text="{{ name.value | json }}"></Label>
    <Label text="{{ name.status | json }}"></Label>

-> I have the error "Error: No value accessor for form control with unspecified name attribute"

if I change the textfield row to add ngDefaultControl : <TextField [formControl]="name" ngDefaultControl></TextField>

it works BUT there is no synchronisation, if I fill the form on app, {{ name.value }} still displays null

Did I miss something ?? Do you have some working code ?

Thanks ! serge

coltcook commented 7 years ago

I've been using it since 2.5--but only with FormBuilder. Your class would be like:

export class HeroDetailComponent {
    public heroForm: FormGroup;

    constructor(private fb: FormBuilder){
        this.heroForm = this.fb.group({
            "name": ["", [Validators.required]]
        });
    }
}

Then your template would be:

<StackLayout [formGroup]="heroForm">
    <TextField formControlName="name"></TextField>
</StackLayout>

Edit to fix formatting.

coltcook commented 7 years ago

Looks identical to the versions that I use. Like I said, I've never tried with just a form control, I've always done a FormGroup (obviously with the [formGroup]= attribute set), and I haven't had any issues.

And you used the exact code I posted?

Serge-SDL commented 7 years ago

Hi,

I restarted from scratch to be sure not to have missed anything ! Start by lauching commands:

tns create form-test --template nativescript-template-ng-tutorial
cd form-test
tns run android

-> lauch app, everything fine

create file app/hero-detail.component.ts with code:

import { Component } from "@angular/core";
import { FormGroup, FormBuilder, Validators } from '@angular/forms';

@Component({
  selector: "hero-detail",
  template: `
    <StackLayout [formGroup]="heroForm">
        <TextField formControlName="name"></TextField>
    </StackLayout>
  `
})
export class HeroDetailComponent {
    public heroForm: FormGroup;

    constructor(private fb: FormBuilder){
        this.heroForm = this.fb.group({
            "name": ["", [Validators.required]]
        });
    }
}

change my app.module.ts (add ReactiveFormsModule and HeroDetailComponent) to:

import { NgModule, NO_ERRORS_SCHEMA } from "@angular/core";
import { NativeScriptModule } from "nativescript-angular/nativescript.module";
import { ReactiveFormsModule } from '@angular/forms'; 

import { AppComponent } from "./app.component";
import { HeroDetailComponent } from './hero-detail.component';

@NgModule({
  declarations: [AppComponent, HeroDetailComponent],
  bootstrap: [AppComponent],
  imports: [NativeScriptModule, ReactiveFormsModule],

  schemas: [NO_ERRORS_SCHEMA],
})
export class AppModule {}

and my app.component.ts to:

import { Component } from "@angular/core";

@Component({
  selector: "my-app",
  template: `
    <ActionBar title="My App"></ActionBar>
    <hero-detail></hero-detail>
  `
})
export class AppComponent {
  // Your TypeScript logic goes here
}

my package.json file look like :

 "nativescript": {
    "id": "org.nativescript.formtest",
    "tns-android": {
      "version": "2.5.0"
    }
  },
  "dependencies": {
    "@angular/common": "2.4.3",
    "@angular/compiler": "2.4.3",
    "@angular/core": "2.4.3",
    "@angular/forms": "2.4.3",
    "@angular/http": "2.4.3",
    "@angular/platform-browser": "2.4.3",
    "@angular/platform-browser-dynamic": "2.4.3",
    "@angular/router": "3.4.3",
    "nativescript-angular": "1.4.0",
    "nativescript-theme-core": "~1.0.2",
    "reflect-metadata": "~0.1.8",
    "rxjs": "~5.0.1",
    "tns-core-modules": "2.5.0"
  },

still have the error: Error: No value accessor for form control with name: 'name'

danielgek commented 7 years ago

@SD-Lab missing import of NativeScriptFormsModule

Serge-SDL commented 7 years ago

Thanks !!!! works now ... πŸ‘ very hard to find this basic error with debug message ...

chrillewoodz commented 7 years ago

I've done all of the above steps but it's still not working.. I get no errors but the value of the form doesn't change when the input value does. I've described this over on the forums: https://discourse.nativescript.org/t/unable-to-get-reactive-forms-working/929

clarenceh commented 7 years ago

@chrillewoodz I have created a simple demo on this. You can find it in Github below: https://github.com/skywidesoft/ns-formcontrol-demo Hope this help Clarence

chrillewoodz commented 7 years ago

@clarenceh I don't see how that is any different from what I've got: https://github.com/andresfleat/native-app/tree/sprint1

clarenceh commented 7 years ago

@chrillewoodz You are using the versions:

chrillewoodz commented 7 years ago

@clarenceh Is it the nativescript-cli that I have to update to get the latest?

coltcook commented 7 years ago

@chrillewoodz I'm not on a dev machine so I can't confirm, but if your issue is FormBuilder, at the very least you'll want to upgrade nativescript-angular.

I thought the change @clarenceh POC'ed went in with 1.5, but I might be mistaken?

clarenceh commented 7 years ago

@chrillewoodz Yes, it's the first steps. The high level steps are as follows:

  1. Update Nativescript CLI npm install -g nativescript
  2. Update tns-core-modules in your project In your project root folder:
    • Run tns info to check what update is available
    • Run tns update to update NS packages
  3. Update nativescript-angular npm package in package.json In your project root folder:
    • Update nativescript-angular to version 1.5.1
    • Run npm install to update the npm packages
chrillewoodz commented 7 years ago

@clarenceh No luck after updating everything. The values are still not updating :( Have you managed to get it to work for you with the same project I linked?

chrillewoodz commented 7 years ago

@clarenceh I also tried the exact same code which you use and that doesn't work as well. With the same versions on everything.

chrillewoodz commented 7 years ago

@clarenceh I tried moving your code in your repo to inside a lazy loaded module and guess what, it broke. I've filed an issue about this here: https://github.com/NativeScript/nativescript-angular/issues/735 Something behind the scenes must be happening causing it to break.

clarenceh commented 7 years ago

@chrillewoodz I see. I personally will not try to use lazy loading in NativeScript with Angular and lazy loading. Cause although NS supports Angular, it's actually mapping the transpiled JS code to underlying native component in iOS and Android. So I wonder whether it will works with lazy loading module. In addition, not sure if there will be any performance gain even though I can use lazy loading.

codeback commented 7 years ago

It works fine except the control state 'touched', it is always false.

The states dirty, pristine and valid are working well.

Somebody has the same problem?

danielgek commented 7 years ago

@codeback focus and blur event are being implemented on core-modules so after that i think touched state can be implemented ref: #3889

manojdcoder commented 7 years ago

Looks like #3889 is closed with all required events implemented.

But still with NativeScript 3.0 and Angular 4.1, touched remains false always. Never turns to true or ng-touched class is never added to the element nor ng-untouched is removed.

danielgek commented 7 years ago

@sis0k0 can you take a look at this ?

sis0k0 commented 7 years ago

Discussion moved to #804