Ionic v4 form ngSubmit not triggering

#1

Hello guys, I am having difficulties trying to implement a simple login form.

@Component({
  selector: "app-login",
  templateUrl: "./login.page.html",
  styleUrls: ["./login.page.scss"]
})
export class LoginPage implements OnInit {
  constructor(private service: AuthenticationService) {}
  user = {};

  login() {
    this.service.login();
  }

  onSubmit() {
    console.log(this.user);
  }
}
<form (ngSubmit)="onSubmit()">
    <ion-item>
      <ion-label position="floating">Username</ion-label>
      <ion-input
        type="text"
        [(ngModel)]="user.username"
        name="username"
      ></ion-input>
    </ion-item>
    <ion-item>
      <ion-label position="floating">Password</ion-label>
      <ion-input
        type="text"
        [(ngModel)]="user.password"
        name="password"
      ></ion-input>
    </ion-item>
    <ion-button type="submit" expand="block">Sign up</ion-button>
  </form>

When I click the sign up button I don’t see anything in the console. What am I missing here?

#2

Ok just in case someone else encounters the same issue, I restarted the server and it worked just fine after relaunching the app again, weird.

#3

Even if the problem is solved, I think the better way to do it is like that:

<form #user="ngForm" (ngSubmit)="onSubmit(user)">

And in your onSubmit function you can access the fields like this:
user.username or user.password.

#4

Why is this a better way? Also with this way do I need to import an Angular component in my app.module.ts?

#5

Hello there, following your advice I decided to use Reactive Forms instead but I am getting the following error in the console:

Can’t bind to ‘formGroup’ since it isn’t a known property of ‘form’

Here’s my code:

import { Component, OnInit } from "@angular/core";
import { FormGroup, FormControl } from "@angular/forms";
import { AuthenticationService } from "../../services/authentication.service";

@Component({
  selector: "app-login",
  templateUrl: "./login.page.html",
  styleUrls: ["./login.page.scss"]
})
export class LoginPage implements OnInit {
  constructor(private service: AuthenticationService) {}
  loginForm = new FormGroup({
    username: new FormControl(),
    password: new FormControl()
  });
  user = {};

  onSubmit() {
    console.log("submitted");
  }

  ngOnInit() {
    //console.log("Checking");
  }
}

I also imported the ReactiveFormsModule to my app.module.ts

import { ReactiveFormsModule } from "@angular/forms";
...
imports: [
    BrowserModule,
    IonicModule.forRoot(),
    AppRoutingModule,
    IonicStorageModule.forRoot(),
    HttpClientModule,
    ReactiveFormsModule
  ],
<form [formGroup]="loginForm">
    <ion-item>
      <ion-label position="floating">Username</ion-label>
      <ion-input type="text" formControlName="username"></ion-input>
    </ion-item>
    <ion-item>
      <ion-label position="floating">Password</ion-label>
      <ion-input type="text" formControlName="password"></ion-input>
    </ion-item>
    <ion-button type="submit" expand="block">Sign up</ion-button>
    <ion-button expand="block" color="primary" [routerLink]="['/register']"
      >Register</ion-button
    >
  </form>

What am I doing wrong?

edit: NVM, I just had to add ReactiveFormsModule to my login.module.ts file imports instead of my app.module.ts

#6

you don’t need to do it that way. that what you had was already correct. Just change your form to this:

<form #user="ngForm" (ngSubmit)="onSubmit(user)">

and in the .ts file

onSubmit(loginData) {
    console.log(loginData.username);
    console.log(loginData.password);
  }

For simple forms like this, you don’t need neccesserly formGroups

#user=“ngForm” gives you a variable for that view and makes it easer to handle the data

#7

I see, how would you add validation this way? i.e, showing div right below the input showing the error if there is an error.

#8

you can add this

<ion-button type="submit" [disabled]="!user.form.valid">Login</ion-button>

to check if the input fields are valid and in the same way you can use ngIF to show a div or a message or something else.

#9

I did it like this:

<form #form="ngForm" (ngSubmit)="onSubmit(form)">
    <ion-item>
      <ion-label position="floating">Username</ion-label>
      <ion-input
        type="text"
        name="username"
        #username="ngModel"
        ngModel
        required
        minlength="5"
        maxlength="50"
      ></ion-input>
    </ion-item>
    <div *ngIf="username.touched && !username.valid">
      <div *ngIf="username.errors.required">Username is required</div>
      <div *ngIf="username.errors.minlength">
        Username should be minimum
        {{ username.errors.minlength.requiredLength }} characters
      </div>
    </div>
    <ion-item>
      <ion-label position="floating">Password</ion-label>
      <ion-input
        type="text"
        name="password"
        #password="ngModel"
        ngModel
        required
        minlength="5"
        maxlength="50"
      ></ion-input>
    </ion-item>
    <div *ngIf="password.touched && !password.valid">
      <div *ngIf="password.errors.required">password is required</div>
      <div *ngIf="password.errors.minlength">
        password should be minimum
        {{ password.errors.minlength.requiredLength }} characters
      </div>
    </div>
    <ion-button type="submit" expand="block">Sign up</ion-button>
    <ion-button expand="block" color="primary" [routerLink]="['/register']"
      >Register</ion-button
    >
  </form>

Would you say this is a good way to implement a login form validation?

Also do you think I should use ReactiveForms for the registration form, I ask this because I’d probably need to check asynchronously if the user exist in the database or not and display a loader while checking, although this may be unnecessary.

#10

I didn’t run your code but seems to be ok.
And if I remember it right, you can solve the asynchronous check with (ngModelChange) in your username input field without using ReativeForm.

#11

Would you be able to provide an example of that? Thanks for the help BTW.

#12

I’ll be at my desc in few hours and will get back to you.
meanwhile you can have a look on (ngModelChange). uncle google will help you :slight_smile:

1 Like
#13

.html

<ion-input (ngModelChange)="checkUsername(form)"
				type="text"
				name="username"
				#username="ngModel"
				ngModel
				required
				minlength="5"
				maxlength="50"
		></ion-input>

and .ts file:

checkUsername(formData) {
        let username = formData.controls.username.value;
        if (username.length > 5) {
            console.log('Do Something with: ' + username);
        }
    }

cheers

#14

So basically in this function is where I would call the server to check if the username already exists. Then I think I have to use the pending property of the formControl to show the loader image.

Thanks, appreciate it.