无法以角度显示用户名

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了无法以角度显示用户名相关的知识,希望对你有一定的参考价值。

我已经使用jwt标记化实现了身份验证,登录后我想在导航栏上显示用户名,但它没有显示任何内容并在控制台上出错“错误类型错误:无法读取未定义的属性'用户名'但刷新页面后它是显示用户名并仍然在控制台上给出相同的错误。

这是我的代码

NavbarComponent.ts

import { Component, OnDestroy } from '@angular/core';
import { AuthService } from '../../services/auth.service';
import { Router } from '@angular/router';
import { User } from '../../shared/user';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { AdminAuthGuard } from '../../guards/admin.auth.guard';
import { Subscription } from 'rxjs/Subscription';

@Component({
  selector: 'app-navbar',
  templateUrl: './navbar.component.html',
  styleUrls: ['./navbar.component.css']
})
export class NavbarComponent {


  user$: any;

  constructor(private authService: AuthService, private router: Router, private adminGuard: AdminAuthGuard) {
    this.authService.getProfile().subscribe((user) => {
      console.log('fsdf' + user.user.email);
      this.user$ =  user.user;
    });
   }



  onLogoutClick() {
    // console.log('this.user' + this.user$.email);
    this.authService.logout();
    this.router.navigate(['/']);
  }

}

我正在打印用户名的html代码。

<nav class="navbar navbar-expand-md navbar-light bg-light fixed-top">
  
  <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 active">
        <a class="nav-link" routerLink="/home">Home <span class="sr-only">(current)</span></a>
      </li>
      <li class="nav-item">
        <a  class="nav-link" *ngIf="!authService.loggedIn()" [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}" routerLink="/login">Login</a>
      </li>
      <li class="nav-item">
        <a  class="nav-link" *ngIf="!authService.loggedIn()" [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}" routerLink="/register">Register</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" routerLink="/shopping-cart">Shopping Cart</a>
      </li>
      
      <li *ngIf="authService.loggedIn()" ngbDropdown class="nav-item dropdown">
        <a  ngbDropdownToggle class="nav-link dropdown-toggle"  id="dropdown01" data-toggle="dropdown" aria-haspopup="true"  aria-expanded="false">{{ user$.username }}</a>
        <div ngbDropdownMenu class="dropdown-menu " aria-labelledby="dropdown01">
          <a class="dropdown-item" routerLink="/my/orders">My Orders</a>
          <a class="dropdown-item" routerLink="/profile">Profile</a>
          
          <a class="dropdown-item" routerLink="/admin/orders">Manage Orders</a>
          <a class="dropdown-item" routerLink="/admin/products">Manage Products</a>
          <button class="dropdown-item" (click)="onLogoutClick()">Logout</button>
        </div>
      </li>
    </ul>
    
  </div>
</nav>

身份验证服务代码。专注于getProfile()方法

import { Injectable } from '@angular/core';
import 'rxjs/add/operator/map';
import { Http, Headers, RequestOptions } from '@angular/http';
// import { map } from "rxjs/operators";
// import { map } from 'rxjs/operators';

import { switchMap } from 'rxjs/operators';
import { tokenNotExpired } from 'angular2-jwt';
import { User } from '../shared/user';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import 'rxjs/add/observable/of';
@Injectable()
export class AuthService {
  private subject = new Subject<any>();
  domain = 'http://localhost:3000';
  authToken;
  user;
  options;

  constructor(private http: Http) { }

  registerUser(user) {
    return this.http.post(this.domain + '/authentication/register', user).map(res => res.json());
  }

  createAuthenticationHeaders() {
    this.loadToken();
    this.options = new RequestOptions({
      headers : new Headers({
        'Content-Type': 'application/json',
        'authorization': this.authToken
      })
    });

  }

  loadToken() {
    this.authToken = localStorage.getItem('token');
  }
  checkUsername(username) {
    return this.http.get(this.domain + '/authentication/checkUsername/' + username).map(res => res.json());
  }

  checkEmail(email) {
    return this.http.get(this.domain + '/authentication/checkEmail/' + email).map(res => res.json());
  }

  login(user) {
    return this.http.post(this.domain + '/authentication/login', user).map(res => res.json());
  }



  logout() {
    this.authToken = null;
    this.user = null;
    localStorage.clear();
  }
  storeUserData(token, user) {
    localStorage.setItem('token', token);
    localStorage.setItem('user', JSON.stringify(user));
    this.authToken = token;
    this.user = user;
  }

  getProfile() {
    this.createAuthenticationHeaders();
    return this.http.get(this.domain + '/authentication/profile', this.options).map(res => res.json());
  }



  loggedIn() {
    return tokenNotExpired();
  }

}

这是http路由API,它从Node.js编写的mongodb数据库中获取用户。专注于'/ profile'方法的get(),它返回一个Observable。

const User = require('../models/user'); // Import User Model Schema

const jwt = require('jsonwebtoken');
const config = require('../config/database');

module.exports = (router) => {
  /* ==============
     Register Route
  ============== */
  router.post('/register', (req, res) => {
    // Check if email was provided
    if (!req.body.email) {
      res.json({ success: false, message: 'You must provide an e-mail' }); // Return error
    } else {
      // Check if username was provided
      if (!req.body.username) {
        res.json({ success: false, message: 'You must provide a username' }); // Return error
      } else {
        // Check if password was provided
        if (!req.body.password) {
          res.json({ success: false, message: 'You must provide a password' }); // Return error
        } else {
          // Create new user object and apply user input
          let user = new User({
            email: req.body.email.toLowerCase(),
            username: req.body.username.toLowerCase(),
            password: req.body.password
          });
          // Save user to database
          user.save((err) => {
            // Check if error occured
            if (err) {
              // Check if error is an error indicating duplicate account
              if (err.code === 11000) {
                res.json({ success: false, message: 'Username or e-mail already exists' }); // Return error
              } else {
                // Check if error is a validation rror
                if (err.errors) {
                  // Check if validation error is in the email field
                  if (err.errors.email) {
                    res.json({ success: false, message: err.errors.email.message }); // Return error
                  } else {
                    // Check if validation error is in the username field
                    if (err.errors.username) {
                      res.json({ success: false, message: err.errors.username.message }); // Return error
                    } else {
                      // Check if validation error is in the password field
                      if (err.errors.password) {
                        res.json({ success: false, message: err.errors.password.message }); // Return error
                      } else {
                        res.json({ success: false, message: err }); // Return any other error not already covered
                      }
                    }
                  }
                } else {
                  res.json({ success: false, message: 'Could not save user. Error: ', err }); // Return error if not related to validation
                }
              }
            } else {
              res.json({ success: true, message: 'Acount registered!' }); // Return success
            }
          });
        }
      }
    }
  });

  router.get('/checkEmail/:email', (req, res) => {
    if (!req.params.email) {
      res.json({ success: false, message: 'email not provided'});
    } else {
      User.findOne({ email: req.params.email}, (err, user) => {
        if (err) {
          res.json({ success: false, message: err});
        } else {
          if (user) {
            res.json({ success: false, message: 'email taken'});
          } else {
            res.json({ success: true, message: 'email available'});
          }
        }
      });
    }
  });

  router.get('/checkUsername/:username', (req, res) => {
    if (!req.params.username) {
      res.json({ success: false, message: 'username not provided'});
    } else {
      User.findOne({ username: req.params.username}, (err, user) => {
        if (err) {
          res.json({ success: false, message: err});
        } else {
          if (user) {
            res.json({ success: false, message: 'username taken'});
          } else {
            res.json({ success: true, message: 'username available'});
          }
        }
      });
    }
  });

  router.post('/login', (req, res) => {
    if (!req.body.username) {
      res.json({ success: false, message: 'No username was provided'});
    } else {
      if (!req.body.password) {
        res.json({ success: false, message: 'No password was provided'});
      } else {
        User.findOne({ username: req.body.username.toLowerCase() }, (err, user) => {
          if (err) {
            res.json({ success: false, message: err});
          } else {
            if (!user) {
              res.json({ success: false, message: 'No user exist'});
            } else {
              const validPassword = user.comparePassword(req.body.password);
              if (!validPassword) {
                res.json({ success: false, message: 'password invalid'});
              } else {
                const token = jwt.sign({userId: user._id}, config.secret, {expiresIn: '24h'});
                res.json({ success: true, message: 'Success!', token: token, user: {username: user.username}});
              }
            }
          }
        });
      }
    }
  });

// MIDDLEWARE TO INTERCEPT HEADERS
// THIS MIDDLEWARE DECRYPTS THE TOKEN
  router.use((req, res, next) => {
    const token = req.headers['authorization']; // whenever a request coming from angular2 with headers attached it is going to search fot this header
    if (!token) {
      res.json({ success: false, message: 'No token provided'});
    } else {
      jwt.verify(token, config.secret, (err, decoded) => {
        if (err) {
          res.json({ success: false, message: 'invalid token' + err});
        } else {
          req.decoded = decoded;
          next();
        }
      });
    }
  })
// ANY ROUTES COMING AFTER THIS MIDDLEWARE WILL PASS THROUGH THE SAME

// BELOW METHOD TAKES THE DECRYPTED TOKEN FIND THE USER
  router.get('/profile', (req, res) => {
    User.findOne({ _id: req.decoded.userId }).select('username email isAdmin').exec((err, user) => {
      if (err) {
        res.json({ success: false, message: err});
      } else {
        if (!user) {
          res.json({ success: false, message: 'user not found'});
        } else {
          res.json({ success: true, user: user });
        }
      }
    });
  });

  return router; // Return router object to main index.js
}
答案

尝试使用safe navigation operator或* ngIf,因为您正在向API发出请求并异步获取数据。尝试如下,

   <a  ngbDropdownToggle class="nav-link dropdown-toggle"  id="dropdown01" data-toggle="dropdown" aria-haspopup="true"  aria-expanded="false">{{ user$?.username }}</a>
另一答案

我很确定会发生这种情况,因为当用户名属性不存在时,您尝试访问用户$ .username。为了避免该错误,您可以使用已定义的类型然后进行初始化,例如。

public $user: UserInterface = {
    username: ''
}

或者您是否不想使用已定义的类型,只需使用ngIf为html块添加额外的验证,例如。

<a  *ngIf="user$.username" ngbDropdownToggle class="nav-link dropdown-toggle"  id="dropdown01" data-toggle="dropdown" aria-haspopup="true"  aria-expanded="false">{{ user$.username }}</a>

顺便说一句,作为一个良好的编码实践,使用公共方法声明代码和视图之间共享的方法,aot build将感谢你。

以上是关于无法以角度显示用户名的主要内容,如果未能解决你的问题,请参考以下文章

maxlength 属性的角度验证消息

两个片段之间的 onItemClickListener

无法从Javascript设置角度模型

无法单击列表元素

无法以角度反应形式添加验证器

这些角度电子邮件指令代码片段如何连接