41
votes

I want to use template driven forms in Angular 2 and I need to access the current ngForm in my directive, as local property and I don't want to pass them as parameter.

my form looks like this:

<form #frm="ngForm" (ngSubmit)="save(frm)">
    <input [(ngModel)]="user.name" #name="ngForm" type="text">
    <a (click)="showFrm()" class="btn btn-default">Show Frm</a>
</form>

and in my component

@Component({
    selector: 'addUser',
    templateUrl: `Templates/AddUser`,
})

export class AddUserComponent implements CanDeactivate {
    public user: User;
    // how can I use this without defining the whole form 
    // in my component I only want to use ngModel
    public frm : ngForm | ControlGroup;

    public showFrm()  : void{
        //logs undefined on the console
        console.log(this.frm);
    }
}

Is this possible, because I need to check if the myFrm ist valide or was touched in a function where I can't pass the current form as parameter e.g. "routerCanDeactivate" and I don't want to use model driven forms its way too much to write in code and I love the old school ng1 model binding.

I've updated my Example and the frm is not known in the component.

2
I've created a feature request on github: github.com/angular/angular/issues/8538squadwuschel
Should the AddUserComponent be placed within the form as a child element? ` <form #frm="ngForm" (ngSubmit)="save(frm)"> ... <add-user-component..></add-user-component..> </form> `Felix

2 Answers

87
votes

You need the ngControl attribute on the inputs you want to check.

<form #frm="ngForm" (ngSubmit)="save(frm)">
   <input [(ngModel)]="user.name" #name="ngForm" ngControl="name"  type="text">
   <a (click)="showFrm()">Show Frm</a>
</form>

and in the component you can access the "frm" variable with

import {Component, ViewChild} from 'angular2/core';
...
@ViewChild('frm') public userFrm: NgForm;
...
public showFrm(): void{
    console.log(this.frm);
}

You can't access the frm in the constructor, it's not there at this moment, but in the ngAfterViewInit you can access it.

since Angular 8 or so they have updated the parameters for ViewChild. Currently I need to use this syntax:

@ViewChild('frm', { static: true })userFrm: NgForm;
-1
votes
<h1>Login</h1>
<hr />
<div class="col-md-4">
  <form autocomplete="off" #loginForm="ngForm" (ngSubmit)="login(loginForm.value)">
    <div class="form-group">
      <em *ngIf="loginForm.controls.userName?.invalid">required</em>
      <label for="userName">User Name:</label>
      <input
        id="userName"
        (ngModel)="(userName)"
        name="userName"
        type="text"
        class="form-control"
        placeholder="User Name..."
      />
    </div>
    <div class="form-group">
      <em *ngIf="loginForm.controls.password?.invalid">required</em>
      <label for="password">Password:</label>
      <input
        id="password"
        (ngModel)="(password)"
        name="password"
        type="password"
        class="form-control"
        placeholder="Password..."
      />
    </div>

    <button type="submit" [disabled="loginForm.invalid" ]class="btn btn-primary">Login</button>
    <button type="button" class="btn btn-default">Cancel</button>
  </form>
</div>
import { Component } from '@angular/core';
import { AuthService } from './auth.service';

@Component({
  selector: 'login',
  templateUrl: './app/login/login.component.html'
})
export class LoginComponent {
  constructor(private authService: AuthService) {}

  login(formValues) {
    this.authService.loginUser(formValues.userName, formValues.password);
  }
}