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

时间:2016-10-26 14:15:58

标签: events angular angular2-routing eventemitter

我的组件结构看起来大致如此。我的应用程序组件有一个导航栏和路由器插座。导航栏包含徽标,一些通用链接以及一些仅在用户登录和身份验证时显示的特定链接。路由器插座根据路由URL加载主组件或墙组件。主组件包含登录组件,其中包含常规用户标识,密码和提交按钮。在提交时,登录成功后,登录组件将发出一个事件。现在,我如何在home组件(父组件)中捕获该事件?

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

我不知道如何捕获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>
&#13;
&#13;
&#13;

谢谢, 希尔帕

3 个答案:

答案 0 :(得分:0)

我想出了这个问题,虽然我还没有解决方案。 原来在地图上调用的方法无法访问类级对象。如果我通过身份验证调用发出事件,它就可以正常工作。 我尝试将事件发射器对象传递给映射方法,但这也没有帮助。如何将对象传递给映射的方法范围?

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

public boolean onTouch(View v, MotionEvent event) {
    gestureDetector.onTouchEvent(event);
    return v.onTouchEvent(event);
}

答案 1 :(得分:0)

对不起延迟,我就是这样做的:

<强> 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>  

显然,为简洁起见,很多这些类都被截断了。

如果您对如何在标题中发送令牌感到好奇,这里是我创建的HttpClient类的一个简单示例(为简洁而截断):

<强> 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类并使用它来自动将标记放在标题中,I.E。

<强> some.component.ts

export class SomeComponent {

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

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

答案 2 :(得分:0)

了解这个解决方案 - &gt; http://plnkr.co/edit/KfcdDi?p=info

&#13;
&#13;
//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();
    }
}
&#13;
&#13;
&#13;

&#13;
&#13;
//login.component

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

&#13;
&#13;
//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;
            }
        }
    }
&#13;
&#13;
&#13;

&#13;
&#13;
<!-- 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>
&#13;
&#13;
&#13;

这里的提醒服务完全符合我的要求。