Реактивная форма перестает работать после добавления Observable в ngOnInit в app.component.ts - PullRequest
0 голосов
/ 25 мая 2020

Хорошо, вот и моя странная ситуация. Я создал проект Ioni c с боковой навигацией. Затем я создал простой компонент входа в систему для использования с Firebase. Форма работает как чудо, она срабатывает при изменении поля и отображает ошибки проверки. Теперь мой следующий шаг - отключить боковое меню, когда пользователь вошел в систему. По какой-то причине, когда я добрался до app.component.ts, где обрабатывается боковое меню logi c, я добавляю наблюдаемое в функцию ngOnInit , отключение меню работает, но реактивная форма перестает работать.

Вот мой компонент входа в систему:

login.module.ts:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

import { IonicModule } from '@ionic/angular';

import { LoginPageRoutingModule } from './login-routing.module';

import { LoginPage } from './login.page';
import { ComponentsModule } from '../../../components/components.module'

@NgModule({
  imports: [
    CommonModule,
    ReactiveFormsModule,
    IonicModule,
    LoginPageRoutingModule,
    ComponentsModule
  ],
  declarations: [LoginPage]
})
export class LoginPageModule {}

login.page. html

  <form [formGroup]="loginForm" (ngSubmit)="login(loginForm.value)" novalidate>
    <ion-list>
    <ion-item>
      <ion-label position="floating" color="primary">Email</ion-label>
      <ion-input type="email" formControlName="email"></ion-input>
    </ion-item>

    <div class="validation-errors">
      <ng-container *ngFor="let v of validation_messages.email">
        <ion-text color="danger" *ngIf="email.hasError(v.type) && (email.dirty || email.touched)">
          <p class="ion-padding-start">
            {{ v.message }}
          </p>
        </ion-text>
      </ng-container>
    </div>

    <ion-item>
      <ion-label position="floating" color="primary">Password</ion-label>
      <ion-input type="password" formControlName="password"></ion-input>
    </ion-item>

    <div class="validation-errors">
      <ng-container *ngFor="let v of validation_messages.password">
        <ion-text color="danger" *ngIf="password.hasError(v.type) && (password.dirty || password.touched)">
          <p class="ion-padding-start">
            {{ v.message }}
          </p>
        </ion-text>
      </ng-container>
    </div>
  </ion-list>

    <ion-button class="submit-btn" type="submit" expand="block" [disabled]="!loginForm.valid">Login</ion-button>

    <ion-text color="danger">
      <p class="ion-padding-start">
        {{ errorMessage }}
      </p>
    </ion-text>

    <ion-text color="success">
      <p class="ion-padding-start">
        {{ successMessage }}
      </p>
    </ion-text>

    <p class="go-to-register">No account yet? <a [routerLink]="['/register']">Create an account.</a></p>

    {{loginForm.value | json}}
  </form>

вход. page.ts:

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

@Component({
  selector: 'app-login',
  templateUrl: './login.page.html',
  styleUrls: ['./login.page.scss'],
})
export class LoginPage implements OnInit {

  loginForm: FormGroup;
  testForm: FormGroup;
  errorMessage: string = "";
  successMessage: string = "";
  errorMessageFB: string = "";

  validation_messages = {
    'email': [
      { type: 'required', message: 'Email is required.' },
      { type: 'email', message: 'Enter a valid email.' }
    ],
    'password': [
      { type: 'required', message: 'Password is required.' },
      { type: 'minlength', message: 'Password need to be at least 6 characters long.' }
    ]
  }

  constructor(
    private formBuilder: FormBuilder,
    private authService: AuthService,
    private router: Router,
    private ngZone: NgZone
  ) { }

  ngOnInit() {
    this.loginForm = this.formBuilder.group({
      email: new FormControl('', Validators.compose([
        Validators.required,
        Validators.email
      ])),
      password: new FormControl('', Validators.compose([
        Validators.required,
        Validators.minLength(6)
      ]))
    });
  }

  login(value: any){
  }

  loginWithFB(){
  }

  get email() { return this.loginForm.get('email'); }

  get password() { return this.loginForm.get('password'); }

}

Пока все хорошо, это работает:

Working form..

Теперь у меня есть служба для входа в систему и зарегистрируйте пользователя, который работает до сих пор:

auth.service.ts

import { Injectable } from '@angular/core';
import { AngularFireAuth } from '@angular/fire/auth';
import { Facebook, FacebookLoginResponse } from '@ionic-native/facebook/ngx';
import { Platform } from '@ionic/angular';
import { auth } from 'firebase/app';
import { resolve } from 'url';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class AuthService {

  user$: Observable<firebase.User>;
  isLoggedIn$: Observable<boolean>;
  isLoggedOut$: Observable<boolean>;

  constructor(
    private afAuth: AngularFireAuth,
    private fb: Facebook,
    private platform: Platform
  ) { }

  init(){
    this.user$ = this.afAuth.user;
    this.isLoggedIn$ = this.afAuth.authState.pipe(map(user => !!user));
    this.isLoggedOut$ = this.isLoggedIn$.pipe(map(loggedIn => !loggedIn));
  }

  loginWithFB(): Promise<auth.UserCredential>{
    if (this.platform.is("capacitor")) {
      return this.loginNativeFB();
    } else {
      return this.loginBrowserFB();
    }
  }

  loginBrowserFB(){
    return new Promise<auth.UserCredential>((resolve, reject) => {
      const provider = new auth.FacebookAuthProvider();

      this.afAuth.signInWithPopup(provider).then((res) => {
        resolve(res);
      }, (err) => {
        reject(err);
      })
    });
  }

  loginNativeFB(){
    return new Promise<auth.UserCredential>((resolve, reject) => {
      this.fb.login(['email', 'public_profile']).then((response: FacebookLoginResponse) => {
        if (response.authResponse) {
          const credential = auth.FacebookAuthProvider.credential(
            response.authResponse.accessToken
          );

          this.afAuth.signInWithCredential(credential).then((res) => {
            resolve(res);
          }, (rej) => {
            reject(rej);
          })
        }
      }, (err) => {
        console.log(err);
        reject(err);
      })
    });
  }

  doRegister(value: any){
    return new Promise<any>((resolve, reject) => {
      this.afAuth.createUserWithEmailAndPassword(value.email, value.password).then(
        res => resolve(res),
        err => reject(err)
      )
    })
  }

  doLogin(value: any){
    return new Promise<any>((resolve, reject) => {
      this.afAuth.signInWithEmailAndPassword(value.email, value.password).then(
        res => resolve(res),
        err => reject(err)
      )
    })
  }

  doLogout(){
    return new Promise<any>((resolve, reject) => {
      this.afAuth.signOut().then(() => {
        resolve();
      }).catch((error) => {
        console.log(error);
        reject();
      })
    })
  }
}

Теперь вот проблема: я хочу скрыть боковое меню с помощью наблюдаемого. Итак, я go отправляю: app.component.ts и делаю следующее:

import { Component, OnInit } from '@angular/core';

import { Platform } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';

import { AuthService } from './services/auth.service'

@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.scss']
})
export class AppComponent implements OnInit {
  public selectedIndex = 0;
  public appPages = [
    {
      title: 'Inbox',
      url: '/folder/Inbox',
      icon: 'mail'
    },
    {
      title: 'Outbox',
      url: '/folder/Outbox',
      icon: 'paper-plane'
    },
    {
      title: 'Favorites',
      url: '/folder/Favorites',
      icon: 'heart'
    },
    {
      title: 'Archived',
      url: '/folder/Archived',
      icon: 'archive'
    },
    {
      title: 'Trash',
      url: '/folder/Trash',
      icon: 'trash'
    },
    {
      title: 'Spam',
      url: '/folder/Spam',
      icon: 'warning'
    }
  ];
  public labels = ['Family', 'Friends', 'Notes', 'Work', 'Travel', 'Reminders'];

  disableMenu: boolean;
  user: firebase.User;

  constructor(
    private platform: Platform,
    private splashScreen: SplashScreen,
    private statusBar: StatusBar,
    private authService: AuthService
  ) {
    this.initializeApp();
  }

  initializeApp() {
    this.authService.init();

    this.platform.ready().then(() => {
      this.statusBar.styleDefault();
      this.splashScreen.hide();
    });
  }

  ngOnInit() {
    !!!!!!!!!! HERE I ADD THIS SUBSBRIBE AND THIs BREAK THE FORM !!!!!!!!!!
    this.authService.isLoggedOut$.subscribe((loggedOut) => {
      this.disableMenu = loggedOut;
    });

    this.authService.user$.subscribe((user) => {
      this.user = user;
    });
    !!!!!!!!!! IF I REMOVE THIS IT START WORKING AGAIN !!!!!!!!!!!!!!!!!!!!

    const path = window.location.pathname.split('folder/')[1];
    if (path !== undefined) {
      this.selectedIndex = this.appPages.findIndex(page => page.title.toLowerCase() === path.toLowerCase());
    }
  }
}

Добавляя эти наблюдаемые в код в ngOnInit, моя форма перестает работать. В консоли не отображаются ошибки.

Form stop working after observable

Я что-то упустил? Спасибо

Мне удалось это исправить, добавив ngIf в форму, например:

<form *ngIf="loginForm" [formGroup]="loginForm" (ngSubmit)="login(loginForm.value)" novalidate>

Но я хотел бы еще и объяснение, почему это происходит.

Модуль приложения:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';

import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';

import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';

import { AngularFireModule } from '@angular/fire';
import { AngularFireAuthModule } from '@angular/fire/auth';
import { AngularFirestoreModule } from '@angular/fire/firestore';
import { AngularFireAuthGuard } from '@angular/fire/auth-guard';

import { environment } from '../environments/environment';

import { Facebook } from "@ionic-native/facebook/ngx";
import { Geolocation } from '@ionic-native/geolocation/ngx';
import { GoogleMaps } from '@ionic-native/google-maps/ngx'

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [
    BrowserModule,
    IonicModule.forRoot(),
    AppRoutingModule,
    AngularFireModule.initializeApp(environment.firebase),
    AngularFireAuthModule,
    AngularFirestoreModule
  ],
  providers: [
    StatusBar,
    SplashScreen,
    Facebook,
    Geolocation,
    GoogleMaps,
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
    AngularFireAuthGuard
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...