Angular 2:验证时在导航栏中显示图标

Angular 2: Displaying icons in navbar on authentication

我的组件结构大致如下所示。我的应用程序组件有一个导航栏和路由器出口。导航栏有徽标、一些通用链接和一些仅在用户登录和身份验证时显示的特定链接。 router插座根据路由加载home组件或wall组件url。主页组件包含登录组件,其中包含常用的用户 ID、密码和提交按钮。提交并成功登录后,登录组件会发出一个事件。现在,如何在主组件(父组件)中捕获该事件?

如果我直接在应用程序下使用主页选择器,我可以捕获事件,将其冒泡到应用程序,然后使导航栏中的隐藏链接可见。

我不知道如何捕获 home 组件中登录组件发出的事件,因为它已加载到路由器输出中。

<!-- app.html -->
<div>
  <nav>
    <!-- Product logo -->
    <!-- Some generic links -->
    <!-- some hidden icons to be shown on authentication -->
  </nav>
  <router-outlet></router-outlet>
</div>

<!-- home.html -->
<div>
  <login></login>
</div>

<!-- login.html -->
<div>
  <!-- user name and password -->
  <!-- submit button - the associated ts file raises an event on successful login -->
</div>

<!-- wall.html -->
<div>
  <!-- Content to be displayed on authentication -->
</div>

谢谢, 希尔帕

我想通了这个问题,虽然我仍然没有解决方案。 结果是在地图上调用的方法无法访问 class 级别的对象。如果我在身份验证时调用发出事件,它工作得很好。 我尝试将事件发射器对象传递给映射方法,但这也无济于事。如何将对象传递到映射的方法范围?

我服务中的代码如下所示:

authenticate(authRequest: login): Observable<user> {
        let url: string = this.apiUrl + AppSettings.LOGIN_SERVICE;
        let headers = new Headers({
            'Content-Type': AppSettings.CONTENT_TYPE_HEADER
        });

        let options = new RequestOptions({ headers: headers });

        return this._http.post(url, authRequest, options) // ...using post request
            .map(this.authenticated)
            .catch(this.handleError);

        //.catch(this.handleError);
    }

    private authenticated(res: Response) {
        let body = res.json();
        if (body.StatusCode === 200) {
            localStorage.setItem('auth_token', res.headers.get("access-token"));
          //This is the event declared at the class level.
          //The following line of code is the one giving the error - cannot execute emit on  undefined
            this.authEvent.emit(true);
            return body.Data || {};
        }
        else {
            return {};
        }
    }

抱歉耽搁了,我是这样做的:

auth.service.ts

export class AuthService {

    authChanged: EventEmitter<any> = new EventEmitter();

    postLogin(f: ILoginForm) {
      return this.http.post('/login', f)
      .map(res => res.json())
      .subscribe(data => this._checkLoginResponse(data));
    }

    /**
     * Check Login Result
     * @param data
     */
    private _checkLoginResponse(data: any) {
      // If Successful Login
      if (data.data && data.meta && data.meta.token) {

        // Set User & Token
        localStorage.setItem('inctoken', data.meta.token);
        localStorage.setItem('incuser', JSON.stringify(data.data));

        // Emit Auth & User Events
        this.authChanged.emit(this.getUser());

        // Show OK Login Flash Message
        this.flash.success('You have been logged in successfully.');

        // Navigate Home
        this.injector.get(Router).navigate(['/']);
      }
    }

    /**
     * Logout of Interface
     * @returns boolean
     */
    logout(withMsg = false): boolean {
      // # Remove Token & User from LS
      localStorage.removeItem('inctoken');
      localStorage.removeItem('incuser');

      // Emit Auth Events
      this.authChanged.emit(false);

      // Show Flash Message
      if (withMsg)
        this.flash.info('You have been logged out.', 'OK.');

      // Redirect to Login Page
      this.injector.get(Router).navigate(['/login']);
      return true;
    }
}

然后任何组件都可以注入 AuthService 并知道 authedUser 何时更改、注销等。以我的 Navbar 为例:

navbar.component.ts

export class NavbarComponent {

  /**
   * Authed User
   */
  authedUser: IUser;


  constructor(private authService: AuthService) {
    this.authService.authChanged
      .subscribe((user?: IUser) => {
        // user will be false if logged out
        // or user object if logged in. 
        this.authedUser = user;
      });
    }
}

然后在我的导航栏模板中,我可以选择根据身份验证状态显示内容:

<nav class="navbar">

  <!-- Truncated -->
  <ul class="menu-item"
      *ngIf="authedUser">
      <li><img [src]="authedUser.avatar"></li>
      <!-- Whatever -->
  </ul>

  <ul class="menu-item"
      *ngIf="!authedUser">
      <li><a [routerLink]="['/login']">Login</a></li>
      <!-- Whatever -->
  </ul>

</nav>  

显然,为了简洁起见,其中很多 class 都被截断了。

如果您对令牌如何在 header 中发送感到好奇,这里是我创建的 HttpClient class 的简单示例(为简洁起见被截断):

http.service.ts

export class HttpClient {

  constructor(private http: Http) {
    // ...
  }

  /**
   * Get
   * @param url
   * @returns {Observable<any>}
   */
  get(url): Observable<any> {

    // Create New Headers
    let headers = new Headers();

    // Set Authorization Header
    this._createAuthorizationHeader(headers);

    // Create Observable to Return to Calling Service.
    // We Dont Just Return the HTTP Observable Because
    // We Need to Subscribe Here to Catch The Errors That
    // May Be Thrown, Otherwise, Every Service Would Need
    // To Call The Handle Errors Method
    return Observable.create((observer) => {

      // Fire Http GET Request, Subscribe & Catch Errors
      return this.http.get(this.baseUrl + url, {
        headers: headers
      }).subscribe(
        data => observer.next(data),    // Emit Data Returned
        err => this.handleError(err),   // Catch Errors
        () => observer.complete()       // Emit Completed
      );
    });
  }

  /**
   * Create Authorization Header
   * @param {Headers} headers
   */
  private _createAuthorizationHeader(headers: Headers) {

    // If We Have A Token, Append It.  The
    // API Server Will Determine Its Validity
    if (localStorage.getItem('inctoken')) {
      headers.append('Authorization', 'Bearer: ' + localStorage.getItem('inctoken'));
    }
  }
}

然后在我的其他组件中,我可以注入我的 HttpClient class 并使用它自动将令牌放入 headers,即

some.component.ts

export class SomeComponent {

  constructor(private http: HttpClient) {
    // ...
  }

  private _getSomeData() {
    return this.get('/someurl')
      .map(res => res.json();
  }
}

偶然发现这个解决方案 --> http://plnkr.co/edit/KfcdDi?p=info

//alert.service.ts

import { Injectable } from '@angular/core';
import { Router, NavigationStart } from '@angular/router';
import { Observable } from 'rxjs';
import { Subject } from 'rxjs/Subject';

@Injectable()
export class AlertService {
    private subject = new Subject<any>();
    private keepAfterNavigationChange = false;

    constructor(private router: Router) {
        // clear alert message on route change
        router.events.subscribe(event => {
            if (event instanceof NavigationStart) {
                if (this.keepAfterNavigationChange) {
                    // only keep for a single location change
                    this.keepAfterNavigationChange = false;
                } else {
                    // clear alert
                    this.subject.next();
                }
            }
        });
    }

    success(message: string, keepAfterNavigationChange = false) {
        this.keepAfterNavigationChange = keepAfterNavigationChange;
        this.subject.next({ type: 'success', text: message });
    }

    error(message: string, keepAfterNavigationChange = false) {
        this.keepAfterNavigationChange = keepAfterNavigationChange;
        this.subject.next({ type: 'error', text: message });
    }

    getMessage(): Observable<any> {
        return this.subject.asObservable();
    }
}

//login.component

private loggedIn(user1: user) {
        this.currentUser = user1;
        this._alertService.alert("login", true);
     
    }

//app.component

ngOnInit(): void {
        this.authenticated = this._authService.isLoggedIn();
        this._alertService.getMessage().subscribe(data => this.setData(data));
    }

private setData(data: any) {
        if (!this.authenticated) {
            if (data && (data.type === 'login') && data.success === true) {
                this.authenticated = true;
            }
            else {
                this.authenticated = false;
            }
        }
    }

<!-- app.html -->
    <nav class="navbar navbar-color">
        <div class="container-fluid" id="nav_center">
            <!-- Brand and toggle get grouped for better mobile display -->
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed nav-expand-button" 
                        data-toggle="collapse" data-target="#navbar-collapse1" aria-expanded="false"
                        *ngIf="authenticated">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <button type="button" class="nav-features nav-expand-button"
                        (click)="isCollapsed = !isCollapsed" *ngIf="authenticated">
                    <span class="sr-only">Navigate features</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="#">Outili</a>
            </div>
            <!-- Collect the nav links, forms, and other content for toggling -->
            <div class="collapse navbar-collapse" id="navbar-collapse1" *ngIf="authenticated">
                <!--*ngIf="showNotification">-->
                <ul class="nav navbar-nav navbar-right">
                    <li class="navbar-icons">
                        <a href="#" class="navbar-a">
                            <span class="glyphicon glyphicon-inbox navbar-icons"></span>
                        </a>
                    </li>
                    <li class="dropdown navbar-icons">
                        <a href="#" class="dropdown-toggle navbar-a" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
                            <span class="glyphicon glyphicon-user navbar-icons"></span>
                            <span class="caret navbar-icons"></span>
                        </a>
                        <ul class="dropdown-menu">
                            <li><a href="#">Profile</a></li>
                            <li><a href="#">Settings</a></li>
                            <li role="separator" class="divider"></li>
                            <li (click)="logout()"><button type="button" class="btn">Logout</button></li>
                        </ul>
                    </li>
                </ul>
            </div><!-- /.navbar-collapse -->
        </div><!-- /.container-fluid -->
    </nav>

这里的警报服务正是我要找的。