ionic-team / ionic-framework

A powerful cross-platform UI toolkit for building native-quality iOS, Android, and Progressive Web Apps with HTML, CSS, and JavaScript.
https://ionicframework.com
MIT License
51.02k stars 13.51k forks source link

bug: #18997

Closed wardloockx closed 5 years ago

wardloockx commented 5 years ago

Bug Report

Ionic version:

[x] 4.x

Current behavior: My registration form does not trigger error messages based on *ngIf and also doesn't change the invalid class to valid based on [class.invalid]=.

This only happens when I go to the root page of the app (/ => redirects to /user/login) and click on the registration form link.

When the form is loaded directly through /user/register in the browser, everything works perfectly.

Expected behavior: Showing error messages and validation logic should be the same regardless of how the form is loaded (directly or through a link click).

When I run the code and I am typing in the screenName input the test() function is triggered with a console.log, logging if the control is valid. And this logic does seem to work. So I think it's a UI related problem.

Related code:

user.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { RouterModule } from '@angular/router';
import { ReactiveFormsModule} from '@angular/forms';

import { LoginComponent } from './login/login.component';
import { RegisterComponent } from './register/register.component';
import { LogoutComponent } from './logout/logout.component';

@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    IonicModule,
    ReactiveFormsModule,
    RouterModule.forChild([
      {
        path: 'login',
        component: LoginComponent
      },
      {
        path: 'logout',
        component: LogoutComponent
      },
      {
        path: 'register',
        component: RegisterComponent
      }
    ])
  ],
  declarations: [LoginComponent, RegisterComponent, LogoutComponent]
})

export class UserModule {

  onSubmit() {
  }

}

register.component.html

<ion-content color="primary">
    <ion-grid style="height: 100%;">
        <ion-row>
            <ion-col size="12">
                <ion-card color="light">
                    <ion-card-header text-center="">
                        <img style="display:inline-block;width:25%" src="../../../assets/logo_transparant_cropped.png" />
                    </ion-card-header>

                    <ion-card-content>
                            <form [formGroup]="registrationForm">
                                <ion-item>
                                    <ion-label position="stacked">Screen name</ion-label>
                                    <ion-input formControlName="screenName"
                                               type="string"
                                               placeholder="Your super cool internet name"
                                               name="screenName"
                                               (keydown)="test()"
                                               [class.invalid]="!registrationForm.controls['screenName'].valid &&
                                                registrationForm.controls['screenName'].touched"
                                               >
                                    </ion-input>
                                </ion-item>

                                <ion-item class="error-message" *ngIf="!registrationForm.controls['screenName'].valid &&
                                        registrationForm.controls['screenName'].touched">
                                    <ion-label>Your screen name can only contains characters and numbers.</ion-label>
                                </ion-item>

                                <ion-item>
                                    <ion-label position="stacked">Email</ion-label>
                                    <ion-input formControlName="email" type="email" placeholder="Your email address" [class.invalid]="!registrationForm.controls['email'].valid && registrationForm.controls['email'].touched">
                                    </ion-input>
                                </ion-item>

                                <ion-item class="error-message" *ngIf="!registrationForm.controls['email'].valid&& registrationForm.controls['email'].touched">
                                    <ion-label>Please enter a valid email.</ion-label>
                                </ion-item>

                                <ion-item>
                                    <ion-label position="stacked">Password</ion-label>
                                    <ion-input formControlName="password" type="password" placeholder="Your password" [class.invalid]="!registrationForm.controls['password'].valid && registrationForm.controls['password'].touched">
                                    </ion-input>
                                </ion-item>

                                <ion-item class="error-message" *ngIf="!registrationForm.controls['password'].valid  && registrationForm.controls['password'].touched">
                                    <ion-label>Your password needs more than 6 characters.</ion-label>
                                </ion-item>

                                <ion-button (click)="signupUser(registrationForm)" color="warning" expand="block" >
                                    Create an Account
                                </ion-button>
                            </form>

                            <ion-button text-capitalize="no" size="small" color="light" expand="full" routerLink="/user/login">
                                Already registered? Log in
                            </ion-button>
                    </ion-card-content>
                </ion-card>
            </ion-col>
        </ion-row>
    </ion-grid>
</ion-content>

register.component.ts

import { Component, OnInit } from '@angular/core';
import { AuthService } from '../../services/auth.service';
import { LoadingController, AlertController } from '@ionic/angular';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';

@Component({
  selector: 'app-register',
  templateUrl: 'register.component.html',
  styleUrls: ['register.component.scss'],
})
export class RegisterComponent {

  public registrationForm: FormGroup;
  public loading: any;

  constructor(
      private authService: AuthService,
      private loadingCtrl: LoadingController,
      private alertCtrl: AlertController,
      private formBuilder: FormBuilder,
      private router: Router
  ) {
  }

  test() {
    console.log(this.registrationForm.controls['screenName'].valid);
  }

  async signupUser(signupForm: FormGroup): Promise<void> {
    if (!signupForm.valid) {
      console.log('Need to complete the form, current value: ', signupForm.value);
    } else {

      const screenName: string = signupForm.value.screenName;
      const email: string = signupForm.value.email;
      const password: string = signupForm.value.password;

      this.authService.signupUser(screenName, email, password).then(() => {
              this.loading.dismiss().then(() => {
                this.router.navigateByUrl('home');
            });
          },
          error => {
            this.loading.dismiss().then(async () => {
              const alert = await this.alertCtrl.create({
                message: error.message,
                buttons: [{ text: 'Ok', role: 'cancel' }],
              });
              await alert.present();
            });
          }
      );
      this.loading = await this.loadingCtrl.create();
      await this.loading.present();
    }
  }

  ngOnInit() {
      this.registrationForm = this.formBuilder.group({
        email: ['', Validators.compose([Validators.required, Validators.email])],
        password: ['', Validators.compose([Validators.minLength(6), Validators.required])],
        screenName: ['', Validators.compose([Validators.minLength(4), Validators.required, Validators.maxLength(15), Validators.pattern('^[A-Za-z0-9]+$')])],
      });

      this.registrationForm.reset();
  }
}

login.component.ts

`import {Component, OnInit} from '@angular/core';
import { FormGroup, Validators, FormBuilder } from '@angular/forms';
import { LoadingController, AlertController } from '@ionic/angular';
import { AuthService } from '../../services/auth.service';
import { Router } from '@angular/router';

@Component({
  selector: 'app-login',
  templateUrl: 'login.component.html',
  styleUrls: ['login.component.scss'],
})

export class LoginComponent {

  public loginForm: FormGroup;
  public loading: HTMLIonLoadingElement;

  constructor(
      public loadingCtrl: LoadingController,
      public alertCtrl: AlertController,
      private authService: AuthService,
      private router: Router,
      private formBuilder: FormBuilder
  ) {
    this.loginForm = this.formBuilder.group({
      email: ['', Validators.compose([Validators.required, Validators.email])],
      password: ['', Validators.compose([Validators.required, Validators.minLength(6)])],
    });
  }

  async loginUser(loginForm: FormGroup): Promise<void> {
    if (!loginForm.valid) {
      console.log('Form is not valid yet, current value:', loginForm.value);
    } else {
      this.loading = await this.loadingCtrl.create();
      await this.loading.present();

      const email = loginForm.value.email;
      const password = loginForm.value.password;

      this.authService.loginUser(email, password).then(
          () => {
            this.loading.dismiss().then(() => {
              this.router.navigateByUrl('home');
            });
          },
          error => {
            this.loading.dismiss().then(async () => {
              const alert = await this.alertCtrl.create({
                message: error.message,
                buttons: [{ text: 'Ok', role: 'cancel' }],
              });
              await alert.present();
            });
          }
      );
    }
  }

}

login.component.html

<ion-content color="primary">
<ion-grid style="height: 100%;">
    <ion-row>
        <ion-col size="12">
            <ion-card color="light">
                <ion-card-header>
                    <ion-card-title text-center="">
                        <img style="display:inline-block;width:25%" src="../../../assets/logo_transparant_cropped.png" />
                    </ion-card-title>
                </ion-card-header>

                <ion-card-content>
                    <form [formGroup]="loginForm">
                        <ion-item>
                            <ion-label position="stacked">Email</ion-label>
                            <ion-input
                                    formControlName="email"
                                    type="email"
                                    placeholder="Your email address"
                                    [class.invalid]="!loginForm.controls['email'].valid &&
                                    loginForm.controls['email'].touched"
                            >
                            </ion-input>
                        </ion-item>
                        <ion-item
                                class="error-message"
                                *ngIf="!loginForm.controls['email'].valid &&
                                loginForm.controls['email'].touched"
                                >
                            <ion-label>Please enter a valid email address.</ion-label>
                        </ion-item>

                        <ion-item>
                            <ion-label position="stacked">Password</ion-label>
                            <ion-input
                                    formControlName="password"
                                    type="password"
                                    placeholder="Your password"
                                    [class.invalid]="!loginForm.controls['password'].valid&& loginForm.controls['password'].touched"
                            >
                            </ion-input>
                        </ion-item>
                        <ion-item
                                class="error-message"
                                *ngIf="!loginForm.controls['password'].valid
                                        && loginForm.controls['password'].touched"
                        >
                            <ion-label>Your password needs more than 6 characters.</ion-label>
                        </ion-item>

                        <ion-button (click)="loginUser(loginForm)" expand="block" color="warning">
                            Blimp me in
                        </ion-button>
                    </form>

                    <ion-button text-capitalize="no" size="small" color="light" expand="full" routerLink="/user/register">
                        Register
                    </ion-button>

                    <ion-button text-capitalize="no" size="small" color="light" expand="full" routerLink="/user/reset-password">
                        Forgot password?
                    </ion-button>

                </ion-card-content>
            </ion-card>
        </ion-col>
    </ion-row>
</ion-grid>
</ion-content>

Other information:

Ionic info:


insert the output from ionic info here
`Ionic:

   Ionic CLI                     : 5.2.3 (/usr/local/lib/node_modules/ionic)
   Ionic Framework               : @ionic/angular 4.7.1
   @angular-devkit/build-angular : 0.801.2
   @angular-devkit/schematics    : 8.1.2
   @angular/cli                  : 8.1.2
   @ionic/angular-toolkit        : 2.0.0

Cordova:

   Cordova CLI       : 9.0.0 (cordova-lib@9.0.1)
   Cordova Platforms : ios 5.0.1
   Cordova Plugins   : cordova-plugin-ionic-keyboard 2.1.3, cordova-plugin-ionic-webview 4.1.1, (and 9 other plugins)

Utility:

   cordova-res : 0.6.0 
   native-run  : 0.2.8 

System:

   Android SDK Tools : 26.1.1 (/home/ward/Android/Sdk)
   NodeJS            : v12.7.0 (/usr/bin/node)
   npm               : 6.10.0
   OS                : Linux 4.15
``
brandyscarney commented 5 years ago

Thanks for the issue! Could you please put together a sample app with a minimal amount of code to reproduce, using GitHub or this Stackblitz as a base: https://stackblitz.com/edit/ionic-v4-angular-tabs

ionitron-bot[bot] commented 5 years ago

Thanks for the issue! This issue is being closed due to the lack of a reply. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.

Thank you for using Ionic!