Home > front end >  I get undefined property when I share boolean data between Angular components using @ViewChild
I get undefined property when I share boolean data between Angular components using @ViewChild

Time:10-13

I have a component named RedirectUserToMobileAppComponent , I want to share a boolean property from it named enableLoginForm with app.component. When I execute, I get this error :

enableLoginForm is undefined property on ngAfterViewInit in app.component

this is RedirectUserToMobileAppComponent component:

    import {
        Component,
        ComponentFactoryResolver,
        ComponentRef,
        Inject,
        Input,
        OnInit,
        Output,
        ViewChild,
        ViewContainerRef,
    } from '@angular/core';
    import { Observable, Subscription } from 'rxjs';
    import { filter, map, pluck, tap } from 'rxjs/operators';
    import { ActivatedRoute, Router } from '@angular/router';
    import { MAT_DIALOG_SCROLL_STRATEGY_FACTORY } from '@angular/material/dialog';

    @Component({
        selector: 'redirect-user-to-mobile-app',
        templateUrl: './redirect-user-to-mobile-app.component.html',
        styleUrls: ['./redirect-user-to-mobile-app.component.sass'],
    })
    export class RedirectUserToMobileAppComponent implements OnInit {
        constructor(
        ) {}
        enableLoginForm = false;
        ngOnInit(): void {}
    
        OnLogin(): void {
            this.enableLoginForm = true;
            this.router.navigate(['../login']);
        }
        
    }

and this is app.component:

    import {
    Component,
    HostListener,
    OnDestroy,
    OnInit,
    ViewChild,
    AfterViewInit,
} from '@angular/core';
import { MatIconRegistry } from '@angular/material/icon';
import { DomSanitizer } from '@angular/platform-browser';
import { FirebaseService } from './services/firebase/firebase.service';
import {
    SnakeMessage,
    SnakeMessageService,
} from './services/snakeMessage/snakeMessage.service';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Subscription } from 'rxjs';
import { StorageService } from './services/storage/storage.service';
import { AuthService } from './services/auth/auth.service';
import { RedirectUserToMobileAppComponent } from './redirect-user-to-mobile-app/redirect-user-to-mobile-app.component';

@Component({
    selector: 'app-component',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit, OnDestroy, AfterViewInit {
    favIcon: HTMLLinkElement = document.querySelector('#appIcon');
    private snakeMessageSub: Subscription;
    isLoading = true;
    isLogged: boolean;

    @ViewChild(RedirectUserToMobileAppComponent)
    redirectComponent!: RedirectUserToMobileAppComponent;

    constructor(
        private matIconRegistry: MatIconRegistry,
        private firebaseService: FirebaseService,
        private snakeMessageService: SnakeMessageService,
        private _snackBar: MatSnackBar,
        private storageService: StorageService,
        private domSanitizer: DomSanitizer,
        private authService: AuthService
    ) {
        this.registerCustomIcons();
        this.storageService.initDB();
        this.storageService.onLoaded$.subscribe((loaded) => {
            if (loaded) {
                this.isLoading = false;
            }
        });
        this.isLogged = this.authService.isLoggedIn;
    }

    ngAfterViewInit() {
        if (this.redirectComponent.enableLoginForm) {
            this._is = this.redirectComponent.enableLoginForm;
        }
    }

    ngOnInit(): void {
        this.snakeMessageSub = this.snakeMessageService.messageSub.subscribe(
            (snakeMessage: SnakeMessage) => {
                this._snackBar.open(snakeMessage.message, snakeMessage.action, {
                    duration: 3000,
                    horizontalPosition: 'center',
                    verticalPosition: 'top',
                });
            }
        );
    }

this is my app.component.html

<ng-container *ngIf="!isLoading">
<ng-container *ngIf="isMobileDevice() && !isLogged">
    <redirect-user-to-mobile-app> </redirect-user-to-mobile-app>
    <router-outlet
        *ngIf="enableLoginForm"
    ></router-outlet>
</ng-container>

<router-outlet *ngIf="!isMobileDevice()"></router-outlet>

CodePudding user response:

This is how you use ViewChild:

@ViewChild('templateId', { static: false }) redirectComponent: RedirectUserToMobileAppComponent;

You should have the templateId set in the template part :

<redirect-user-to-mobile-app #templateId> ... </redirect-user-to-mobile-app>

EDIT: Though I agree with skyBlue, you should use a service to shared data between components

CodePudding user response:

ViewChild returns a reference to the HTML element.

I will quote from angular.io:

Property decorator that configures a view query. The change detector looks for the first element or the directive matching the selector in the view DOM. If the view DOM changes, and a new child matches the selector, the property is updated.

So you cant access it's controller variables with ViewChild.

My suggestion for you is to use a service for passing data.

  • Related