Why Angular child component ( navbar ) stops updating view after route change? - javascript

this is my first question on the platform, hope i do it right.
So, i'm working on a social network using MEAN stack and socket.io, and i'm trying to show the number of unviewed notifications and messages next to the icons. All the data is updated in the component by the sockets and i can see that all works fine in the console, data arrives in real time and updates the array which length i'm using to show the numbers on the navbar. Everything works fine and it updates the numbers in the view with no problem, BUT when i change the route (even if i come back to the same url) it stops updating the view, no matter the data still receiving and updating in console.
I've been days stuck with this, doing research, trying but i can't make it work. I've tried:
Using ChangeDetectionStrategy.OnPush combined with ChangeDetectionRef and its methods like markForCheck, detectChanges with async pipe.
Trying to re-render the component on route change without success.
ngZone but honestly i couldnt understand it so well.
So, i'm looking for some short explanation of what is happening and an idea of how can i could fix it. I know there's some very similar questions like this made before, and i'd checked them but couldn't apply them succesfully to my project. I hope someone can help me with this.
This is the navbar component:
import { Component, OnDestroy, OnInit} from '#angular/core';
import { Router, ActivatedRoute, Params } from '#angular/router';
import { UserService } from '../../services/user.service';
import { NotificationService } from '../../services/notification.service';
import { MessageService } from '../../services/message.service';
import { GLOBAL } from '../../services/global';
import { io } from 'socket.io-client';
import { Observable } from 'rxjs';
import { Message } from 'src/app/models/message';
#Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.scss'],
providers: [ MessageService ]
})
export class NavbarComponent implements OnInit{
private socket = io("ws://localhost:3000");
public identity;
public token;
public url:string;
public newNotifications$: Observable<boolean>;
public myNotifications;
public unviewedMessages: Message[];
constructor( public user: UserService,
private _notificationService: NotificationService,
private _messageService: MessageService,
private _route: ActivatedRoute,
private _router: Router
) {
this.identity = user.identity;
this.unviewedMessages = [];
this.token = user.getToken();
this.url = GLOBAL.url;
this.checkIfNewNotifications();
this.checkUnviewedMessages();
}
ngOnInit(): void {
this.sockets()
}
sockets(){
this.socket.emit("addUser", this.identity._id);
this.socket.on("newNotification", newNotification =>{
this.checkIfNewNotifications();
console.log("nueva notificacion")
});
this.socket.on("getMessage", msg =>{
this.checkUnviewedMessages();
console.log("nuevo mensaje")
})
}
logout(){
localStorage.clear();
this.identity = null;
console.log();
this._router.navigate(['/register']);
}
toTop(event){
window.scroll(0,0);
}
seeNotifications(){
this.newNotifications$ = new Observable(observer=>observer.next(false));
this.setViewedNotifications(this.token, this.identity._id);
}
checkIfNewNotifications(){
this._notificationService.getNotifications(this.token).subscribe(
response => {
this.myNotifications = response.notifications.filter(notification => notification.viewed == false).length;
console.log(this.myNotifications)
if(this.myNotifications > 0){
this.newNotifications$ = new Observable(observer=>observer.next(true));
}
},
error => {
console.log(<any>error);
}
)
}
setViewedNotifications(token, id){
this._notificationService.setViewedNotifications(token, id).subscribe(
response =>{
console.log(response);
},
error =>{
console.log(<any>error);
}
)
}
checkUnviewedMessages(){
this._messageService.getUnviewedMessages(this.token).subscribe(
response => {
this.unviewedMessages = response.unviewed;
},
error => {
console.log(<any>error);
}
)
}
}
This is the navbar component template:
<div class="navigation col-lg-12">
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<div class="navbar-header mx-xl-5 mx-lg-5">
<a [routerLink]="['/timeline']" (click)="toTop($event)" class="navbar-brand">V a p o r b o x</a>
</div>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<div class="d-flex">
<li class="nav-item mx-xl-3 mx-lg-3 mobile-avatar">
<!--Imagen de usuario-->
<a [routerLink]="['/profile', identity._id]"><img src="{{ url + 'get-image-user/' + identity.image }}"
alt="Avatar de usuario logueado" *ngIf="identity && identity.image">
<img src="../../../assets/img/default-user.jpg" class="default-img" alt="Imagen de usuario"
*ngIf="!identity.image || identity.image == null">
</a>
</li>
</div>
<li class="nav-item mx-xl-3 mx-lg-3">
<a [routerLink]="['/timeline']" (click)="toTop($event)" class="nav-link">
<i class="fa fa-home fa-lg mx-lg-2"></i>
Inicio
</a>
</li>
<li class="nav-item mx-xl-3 mx-lg-3">
<a [routerLink]="['/users/']" class="nav-link">
<i class="fa fa-users mx-lg-2"></i>
Usuarios
</a>
</li>
<li class="nav-item mx-xl-3 mx-lg-3">
<a [routerLink]="['/chat']" class="nav-link" *ngIf="unviewedMessages">
<i class="fa fa-comments fa-lg mx-lg-2" *ngIf="unviewedMessages.length < 1"></i>
<i class="fa fa-comments fa-lg mx-lg-2 new-unviewed" *ngIf="unviewedMessages.length >= 1">
<small>{{unviewedMessages.length}}</small>
</i>
Chat
</a>
</li>
<li id="log-out" class="nav-item mx-xl-3 mx-lg-3">
<a href="#" (click)="logout()" class="nav-link">
<i class="fa fa-times fa-lg"></i>
Cerrar Sesión
</a>
</li>
</ul>
<ul class="nav navbar navbar-right mx-lg-5" *ngIf="identity">
<li class="avatar">
<!--Imagen de usuario-->
<a [routerLink]="['/profile', identity._id]"><img src="{{ url + 'get-image-user/' + identity.image }}"
alt="Avatar de usuario logueado" *ngIf="identity && identity.image">
<img src="../../../assets/img/default-user.jpg" class="default-img" alt="Imagen de usuario"
*ngIf="!identity.image || identity.image == null"></a>
</li>
<li class="dropdown">
<a class="dropdown-toggle" data-bs-toggle="dropdown" href="#">
{{identity.name}} <span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li>
<a [routerLink]="['/profile/'+identity._id]"><i class="fa fa-user mx-2"></i>Perfil</a>
</li>
<li>
<a [routerLink]="['/user-edit']"><i class="fa fa-cog mx-2"></i>Configuración</a>
</li>
<li>
<i class="fa fa-times mx-2"></i>Cerrar Sesión
</li>
</ul>
</li>
<li class="nav-item">
<a (click)="seeNotifications($event)" [routerLink]="['/notifications']" class="nav-link">
<i class="fa fa-bell fa-lg" *ngIf="!newNotifications$"></i>
<i class="fa fa-bell fa-lg new-unviewed" *ngIf="newNotifications$"><small>{{myNotifications}}</small></i>
</a>
</li>
</ul>
</div>
</div>
</nav>
</div>

Try unsubscribing the api calls made in components, in ngOnDestroy method.

Related

Invoking JS Interop Function for DOM element located in submenu in Blazor

I am trying to invoke a JS function that creates a modal on user click through JS Interop in Blazor. The thing is, the function is using a onclick event for a DOM element that is inside a Blazor submenu. When that DOM Element is outside the submenu in the side navbar, it works fine. When I put that element inside the submenu, Blazor complains that it cannot set property 'onclick' of null
Here is my navbar HTML and JS Interop code
#inject IJSRuntime JS;
<div class="top-row pl-4 navbar navbar-dark">
<a class="navbar-brand" href="">Test</a>
<button class="navbar-toggler" #onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
</button>
</div>
<div class="#NavMenuCssClass" #onclick="ToggleNavMenu">
<ul class="nav flex-column">
<li class="nav-item px-3">
<NavLink class="nav-link" href="/" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" #onclick="()=>expandSubNav = !expandSubNav">
<span class="oi oi-fork" aria-hidden="true"></span> AccountPage
</NavLink>
#if (expandSubNav)
{
<ul class="nav flex-column" id="submenu">
<li class="nav-item px-3">
<a class="expand-menu" href="page">
<span>element1</span>
</a>
</li>
<li class="nav-item px-3">
<a class="expand-menu" href="page">
<span>element2</span>
</a>
</li>
<li class="nav-item px-3">
<a class="expand-menu" href="page">
<span>element3</span>
</a>
</li>
<li class="nav-item px-3">
<a class="expand-menu">
<div id="addBtn" ><span class="oi oi-plus" aria-hidden="true"></span> Add Element</div>
</a>
</li>
</ul>
}
</li>
</ul>
</div>
<div id="myModal" class="modal">
<!-- Modal content -->
<div class="modal-content">
<h1 class="modal-title">
<b>Add Element Here</b>
</h1>
<input id="addelementtext" type="text" />
<button id="add">Add</button>
<button type="button" class="btn btn-defaultcloseissue" id="closebtn" data-dismiss="modal" onclick="">Close</button>
</div>
</div>
</div>
</div>
#code { private bool collapseNavMenu = true;
private bool expandSubNav;
private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
private void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await JS.InvokeVoidAsync("createModal");
}
}
}
I am trying to use onclick with this id element
<li class="nav-item px-3">
<a class="expand-menu">
<div id="addBtn" ><span class="oi oi-plus" aria-hidden="true"></span> Add Element</div>
</a>
</li>
It is inside the submenu it created. When I put it outside the submenu into the main nav menu, the JS function does not complain and it works fine.
I have also tried doing this
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
if (expandSubNav)
{
await JS.InvokeVoidAsync("createModal");
}
}
}
This stops the error but clicking the element does nothing. How can I go about fixing this? I am trying to research about the Blazor LifeCycle as I feel this is a rendering issue but I am having a hard time understanding what I can do.
Here is also the JS function that I am trying to call
window.createModal = function createModal() {
var modal = document.getElementById("myModal");
// Get the button that opens the modal
var btn = document.getElementById("addBtn");
var closebtn = document.getElementById("closebtn");
// When the user clicks the button, open the modal
btn.onclick = function () {
modal.style.display = "block";
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function (event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
closebtn.onclick = function (event) {
modal.style.display = "none";
}
}
Your first error, cannot set property 'onclick' of null, happens because the subnav portion is not expanded when the navbar is first rendered, so the addBtn element isn't found in the DOM yet when you call var btn = document.getElementById("addBtn");
The second issue is because your if() statement only runs once, on first render, while expandSubnav is false. So your await JS.InvokeVoidAsync("createModal"); line will never get executed.
If you notice in the #code block there's a method for toggling the collapseNavMenu:
private void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
}
If you did something similar, but for expandSubnav, you could use that as an opportunity to hook in your createModal code. You only want to do it once, so you'd probably want to keep track of that too. Something like:
private bool modalCreated = false;
private void ToggleSubNav()
{
expandSubnav = !expandSubnav;
if(!modalCreated)
{
await JS.InvokeVoidAsync("createModal");
modalCreated = true;
}
}
And then hook that into your NavLink:
<NavLink class="nav-link" #onclick="ToggleSubNav">
<span class="oi oi-fork" aria-hidden="true"></span> AccountPage
</NavLink>

ReactJS - valid function not working when called in componentDidMount() and componentDidUpdate()

******** EDITED TO SIMPLIFY EXAMPLE AND CLARIFY REQUIREMENT AND PROBLEM **********
I'm stumped with this one, I hope someone can help.
I have a nav bar that I need to run a function on to add .active classes to li elements if they have descendants of a.active.
The menu system is a React component: -
import React, {Component} from "react";
import { Link, NavLink } from 'react-router-dom'
import {activateMenu} from './ActivateMenu'
class SidebarMenu extends React.Component {
componentDidMount() {
activateMenu()
}
componentDidUpdate() {
activateMenu()
}
render() {
const renderNavLink = (to, text, icon, renderArrow = false) => {
return(
<NavLink to={to}>
<i className="bullet">{icon}</i>
<span>{text}</span>
{renderArrow ? <span className="pull-right-container">
<i className="angle-left"><FaAngleLeft /></i>
</span> : null}
</NavLink>
)
}
return (
<ul className="sidebar-menu" data-widget="tree">
<li className="">
{renderNavLink('/','Home',<FaHome />)}
</li>
<li className="treeview">
{renderNavLink("#",'Users',<FaGroup />, true)}
<ul className="treeview-menu">
<li>
{renderNavLink(userSearchSlug,'Search',<FaSearch />)}
</li>
</ul>
</li>
<button onClick={activateMenu}>Press Me</button>
</ul>
)
}
}
export default SidebarMenu
This will give me an HTML structure like this: -
<ul class="sidebar-menu tree" data-widget="tree">
<li class="treeview">
<a href="#">
<i class="fa fa-dashboard"></i> <span>Links</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li>
<i class="fa fa-circle-o"></i> Link1
</li>
<li>
<i class="fa fa-circle-o"></i> Link2
</li>
</ul>
</li>
</ul>
After React has rendered the HTML, I need to trigger a click event on the the .treeview > a node if any a.active nodes are found under .treeview-menu. So: -
<li class="treeview">
<a href="#" *****TRIGGER CLICK EVENT*****>
<i class="fa fa-dashboard"></i> <span>Links</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li>
<i class="fa fa-circle-o *****.ACTIVE CLASS HERE****"></i> Link1
</li>
<li>
<i class="fa fa-circle-o"></i> Link2
</li>
</ul>
</li>
activeMenu() looks like this: -
$('ul.sidebar-menu li.treeview:not(.menu-open)').has('a.active').find('a').trigger( "click" );
This function works when called from onClick() from a button on the page but it is not working in componentDidMount() and componentDidUpdate(). The function will run (tested with console.log() but not affect the HTML as it should. However, if I run it from a Button, it works perfectly. It also works perfectly when HMR runs.
I've no idea why this is happening. Does anyone have any ideas?
This is probably happening because you're selecting the element directly rather than using refs, although it's hard to say because we have no idea what $('ul.sidebar-menu .treeview a').parent().has('a.active').parent().find('.treeview a') is selecting, which is why this kind of code is an antipattern.
React may be in some state where it's not prepared to handle click events at those points. Try using something like the following:
import React, {Component} from "react";
import { Link, NavLink } from 'react-router-dom'
class SidebarMenu extends React.Component {
constructor(props) {
super(props);
this.menuRefs = [];
}
componentDidUpdate() {
if (this.menuRefs.length) {
this.menuRefs[0].click();
}
}
render() {
const renderNavLink = (to, text, icon, renderArrow = false) => {
return(
<NavLink to={to} innerRef={ref => this.menuRefs.push(ref)}>
<i className="bullet">{icon}</i>
<span>{text}</span>
{renderArrow ? <span className="pull-right-container">
<i className="angle-left"><FaAngleLeft /></i>
</span> : null}
</NavLink>
)
}
return (
<ul className="sidebar-menu" data-widget="tree">
<li className="">
{renderNavLink('/','Home',<FaHome />)}
</li>
<li className="treeview">
{renderNavLink("#",'Users',<FaGroup />, true)}
<ul className="treeview-menu">
<li>
{renderNavLink(userSearchSlug,'Search',<FaSearch />)}
</li>
</ul>
</li>
<button onClick={() => this.menuRefs[0] && this.menuRefs[0].click()}>Press Me</button>
</ul>
)
}
}
export default SidebarMenu
Notice
Now there's an array of "menuRefs" and you just use them like normal DOM elements.
We push to the menuRefs in the NavLink innerRef prop (found here)
Note however that you may want to keep a map to ensure that no duplicates get pushed into menuRefs.
To learn more about refs, visit the docs: https://reactjs.org/docs/refs-and-the-dom.html

Reloading Angular navigation directive after login

I'm just learning angularjs and working on my first "real" project. I've spent a couple hours searching online for an answer, but can't seem to find anything relevant in simple enough terms for me to understand.
I have a directive that just loads a navigation header:
app.directive('navDirective', function() {
return {
templateUrl: '../../views/nav.html'
};
});
And in my index.html file I have simply
<nav-directive> </nav-directive>
Initially I was working with Auth0 and got that working, and then added an ng-show to the nav items so that only login shows when there's no user, and all the others appear when there is a user.
Now, I am trying to get local authentication working, instead of using Auth0. It works, but I have to hit the brower's reload button after logging in before I see the navigation template update.
I think I've figured out that when using Auth0, I actually leave my website to go to Auth0, and then the callback causes my page to reload - so I see my nav items.
When I login locally using passport's local strategy, how can I force the navigation template to reload? Or become aware there is now a user, so change the ng-show's on the list items in the template?
Reading tonight, it seems like I can use $watch to do this, but I can't find a "$watch-for-dummies" page and am confused as to how that works exactly, what I would put in the link function and how I would trigger it.
My nav.html template is
<nav class="navbar navbar-expand-lg navbar-dark bg-dark" ng-controller="NavCtrl">
<a class="navbar-brand" href="#" ng-show="currentUser">User: {{ currentUser.username }}</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse navbarCollapse justify-content-end" id="navbarNavDropdown">
<ul class="nav navbar-nav ">
<li class="nav-item" ng-show="currentUser">
<a class="nav-link nav-item-colapse" ui-sref="home">Home </a>
</li>
<li class="nav-item" ng-show="currentUser">
<a class="nav-link nav-item-colapse" ui-sref="view2">View 2</a>
</li>
<li class="nav-item" ng-show="currentUser">
<a class="nav-link nav-item-colapse" ui-sref="view3">View 3</a>
</li>
<li class="nav-item" ng-show="currentUser">
<a class="nav-link nav-item-colapse" ui-sref="reports">Reports</a>
</li>
<li class="nav-item dropdown" ng-show="currentUser">
<a class="nav-link dropdown-toggle" href="http://example.com" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Admin
</a>
<div class="dropdown-menu" style="right: 0; left: auto;" aria-labelledby="navbarDropdownMenuLink">
<a class="dropdown-item nav-item-colapse" ui-sref="sub1">Sub Task1</a>
<a class="dropdown-item nav-item-colapse" ui-sref="sub2">Sub Task2</a>
<a class="dropdown-item nav-item-colapse" href="http://www.google.com">Do Something Else</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link active" ui-sref="login" ng-show="!currentUser">Login</a>
</li>
<li class="nav-item">
<a class="nav-link" ng-click="logout()" ng-show="currentUser">Logout</a>
</li>
</ul>
</div>
</nav>
and navCtrl is:
app.controller("navCtrl", function($scope, mainSrvc) {
mainSrvc.getUser().then(function(user){
$scope.user = (user.data);
console.log('nav ctrl ran') //except it doesn't when logging in locally
console.log(($scope.user));
});
});
And this point I'm not sure if I'm going about this completely wrong or what.
Any suggestions or pointers?
You can use ng-if="vm.isLoggedIn()" to know if a user is present or not.
<nav ng-controller="LoginController as vm" ng-if="vm.isLoggedIn()"
class="navbar navbar-inverse navbar-static-top" ng-init="vm.init()">
In your login controller return wheather a user is logged in or not after authentication
function LoginController($http, $location, $window, AuthFactory, jwtHelper) {
var vm = this;
vm.isLoggedIn = function () {
if (AuthFactory.isLoggedIn) {
return true;
}
else {
return false;
}
};
vm.login = function () {
if (vm.username && vm.password) {
var user = {
username: vm.username,
password: vm.password
};
$http.post('/api/users/login', user).then(function (response) {
if (response.data.success) {
$window.sessionStorage.token = response.data.token;
AuthFactory.isLoggedIn = true;
var token =$window.sessionStorage.token;
var decodedToken = jwtHelper.decodeToken(token);
vm.loggedInUser = decodedToken.username;
}
}).catch(function (error) {
console.log(error);
})
}
}

Angular 1.5 component ...ng-link Issue

I have nav bar
Home Accounts Services Orders Tickets on click of Accounts there is drop-down with fields new Customer and Search Customer On click of new Customer it should navigate to home component.
view of root component:
<div class="dropdown">
<a class="dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<span class="tab_ico fa fa-user"></span>
<span class="tab_name">ACCOUNTS</span>
<span class="caret_holder"><span class="caret"></span></span>
</a>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li><span class="tab_ico fa fa-search"></span> Search customer</li>
<li><a ng-link="['Home']"><span class="tab_ico fa fa-user"></span> New customer</a></li>
</ul>
</div>
As you can see ng-link="['Home']"
routeConfig:
$routeConfig: [
{ path: "/dashboard", component: "dashboard",name:"Dashboard",useAsDefault: true },
{ path: "/home", component: "home", name:"Home" },
{ path: "/account", component: "account", name:"Account" },
{ path: "/**", redirectTo: ["Home"] }
],
Home Component
angular.module('app.home').component("home", {
templateUrl: "app/components/home/homeview.html",
controllerAs: "model",
controller: function($scope, dataservice) {
var vm = this;
console.log("entered into home component");
}
})
Home component view
<div>
<ul>
<li><span class="tab_ico fa fa-search"></span> SEARCH CUSTOMER <span class="closetab">x</span></li>
<li class="k-state-active"><span class="tab_ico fa fa-user"></span> Identification <span class="closetab">x</span></span></li>
</ul>
</div>
On click of new Customer it should display home component view, But it is not displaying home component view ?, no errors also.!!
You can use ngLink with an <a> element without href.
Instead of
<span class="tab_ico fa fa-user"></span> New customer
Use this
<a ng-link="['Home']"><span class="tab_ico fa fa-user"></span> New customer</a>
I think that href can be the problem here.
Source: Angular Router docs

How to hide elements based on user in FireBase and Angular

I'm starting to use Firebase with AngularJS.
Coming from a php/serverside rendered pages.
I dont't get how we're supposed to hide parts of an app to some users.
I have basically 3 levels of users (guests / members / admins)
I could hide with a ng-show based on user, but this only hides client-side.
Data is still sent to the user
Real life example:
The menu items are different based on user level.
I was thinking about using ngshow and check for the uuid , but then again, is exposing the admins uuid a good idea? sounds terrible to me.
Then I thought about putting the menu inside a database and requesting the elements.
Not all users would access all items, but this means a lot of 'unauthorised access attempts on purpose'
What is the correct way of handling this? I feel like I've missed something important about client-only apps relying on Firebase services.
Look at userStatus method in service layer and it usage in other layers.
Service layer :
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs/Observable';
import { AngularFireAuthModule, AngularFireAuth } from 'angularfire2/auth';
import * as firebase from 'firebase/app';
#Injectable()
export class AuthService {
user: Observable<firebase.User>;
constructor(private fireAuth: AngularFireAuth) {
}
loginGoogle() {
this.fireAuth.auth.signInWithPopup(new firebase.auth.EmailAuthProvider())
.catch(function (error) {
alert('Please try again');
});
}
logout() {
this.fireAuth.auth.signOut();
}
userStatus() {
return this.fireAuth.authState;
}
}
Navbar Component :
import { Component, OnInit } from '#angular/core';
import { AuthService } from '../../services/auth.service';
import { Observable } from 'rxjs/Observable';
import * as firebase from 'firebase/app';
#Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.css']
})
export class NavbarComponent implements OnInit {
user: Observable<firebase.User>;
constructor(private authservice: AuthService) {
this.user = this.authservice.userStatus();
}
ngOnInit() {
}
login() {
this.authservice.loginGoogle();
}
logout() {
this.authservice.logout();
}
}
And here is Navbar view, where you want to hide or show the elements based on if user is authenticated :
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
<a class="navbar-brand" routerLink="/">Firebase</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item ">
<a class="nav-link" routerLink="/">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" *ngIf="(user | async)?.uid" routerLink="/listings">Listings</a>
</li>
<li class="nav-item">
<a class="nav-link" *ngIf="(user | async)?.uid" routerLink="/add-listing">Add Listing</a>
</li>
</ul>
<ul class="navbar-nav navbar-right">
<li class="nav-item">
<a class="nav-link" *ngIf="!(user | async)?.uid" (click)="login()">Login</a>
<a class="nav-link" *ngIf="(user | async)?.uid" (click)="logout()">Logout</a>
</li>
</ul>
<div *ngIf="(user | async)?.uid">
<img src="{{(user | async)?.photoURL}}" style="width:30px;height:30px;">
<br> Email: {{(user | async)?.email}}
<br> Name: {{(user | async)?.displayName}}
</div>
</div>
</nav>

Categories