【问题标题】:Sharing Data through components通过组件共享数据
【发布时间】:2019-10-04 04:31:57
【问题描述】:

我想在登录我的登录组件时将数据传递给我的导航栏组件,但我的导航栏内容没有更新。

我的导航栏组件在应用程序模块中,而我的登录组件在另一个模块中。

我尝试使用服务来共享数据。

我的登录组件,这个组件在另一个模块中

export class LoginComponent {
  userCredentials;
  constructor(
    private readonly _authService: AuthService,
  ) {

  }

  login() {
    this._authService.auth(this.userCredentials)
      .subscribe(
        (response: any) => {

            const dataForm = {
              usuario: response.user,
              rol: this.response.role,
            };
            this._authService.setSession(response);
        },
        error => {
          console.log(error);
        }
      );
  }
}

我的 NavBarComponent,这个组件在 app-module 中

export class NavbarComponent  {

  isLogged = false;
  susbscription: Subscription;
  constructor(
    private readonly _authService: AuthService,
  ) {
    this.suscripcion = this._authService
      .changeState$
      .subscribe(
        (isLogged) => {
          this.isLogged = isLogged;

        },
        error => console.log(error)
      );
  }
}

我的导航栏 HTML

<mat-toolbar color="primary">
    <mat-toolbar-row>
      <span>SUPERMERCADO</span>
      <span class="spacer"></span>
      <div *ngIf="!isLogged">
        <button mat-button 
          Login
        </button>
      </div>
      <div *ngIf="isLogged">
        <p>Welcome</p>
      </div>
    </mat-toolbar-row>
  </mat-toolbar>

我的服务,这个服务不在app-module中

  @Injectable()
export class AuthService {
  protected url = environment.url;
  protected model = '/user';

  isLogged = false;
  private changeState = new Subject<boolean>();
  changeState$ = this.changeState.asObservable();

  constructor(
    private readonly _router: Router,
    protected readonly httpclient: HttpClient,
  ) {
  }

  setSession(data: any) {
    this.isLogged = true;
    this.changeState.next(this.isLogged);
  }

  auth(dataForm: any): Observable<any> {
    const url = `${this.url}${this.model}/login`;
    return this.httpclient.post(url, dataForm);
  }

}

我正在使用角度 8.2.0

【问题讨论】:

    标签: angular typescript angular8


    【解决方案1】:

    LoginComponent 是延迟加载模块的一部分吗?

    如果是这样,您需要将 providedIn: 'root' 属性添加到 AuthService:

    @Injectable({
      providedIn : 'root'
    })
    

    确保将其从模块的提供者属性中删除。

    如果您的 LoginComponent 不是延迟加载的,请确保您只在 AppModule 中导入一次 AuthService。否则你可能会得到多个 AuthService 实例。

    如果您希望 AuthService 成为模块的一部分,您可以使用 forRoot 模式来确保服务只导入一次:

    @NgModule({
      // declarations, imports and exports only
    })
    export class SharedModule {
    
      static forRoot(): ModuleWithProviders {
      return { 
        ngModule: SharedModule,
        providers: [// your services]
      }
    }
    
    @NgModule({
      imports: [SharedModule.forRoot()]
    })
    export class AppModule {}
    
    

    如果在 Angular 8 上,您也可以这样做:

    @Injectable({
      providedIn: SharedModule
    })
    export class AuthService
    

    您希望 AppModule 和 LoginComponent 所在的模块都可以使用同一个 AuthService 实例。

    最后,如果这不是问题,您可能会遇到 NavBarComponent 在发出后订阅 changeState$ observable 的问题。在这种情况下,您需要将 changeState 更改为 BehaviorSubject,因此当 NavBarComponent 订阅时,它会收到最后发出的值。

    【讨论】:

      【解决方案2】:

      您的代码无法按预期工作的原因可能有两个。

      1. changeState 主题在导航栏组件订阅它之前发出数据。 据我了解,当您在登录页面上时,导航栏组件不应该被加载。当你。在您的 LoginComponent 中,您首先发出数据,然后,当 NavbarComponent 加载时,您订阅刚刚发出的 observable。
        但是,由于您使用 Subject,您将不会获得 上次发出的 值。 为了缓解这种情况,您可以使用 BehaviorSubject,它将为新订阅者保留上次发出的值 >.

      主题与行为主题

      const s = new Subject();
      
      s.next('not seen...');
      s.next('not seen...');
      s.next('not seen...');
      
      s.subscribe(d => console.log('SUBSCRIBER 1: ', d))
      
      // You must first subscribe, as the `Subject` does not holds any values on itself
      
      s.subscribe(d => console.log('SUBSCRIBER 2: ', d))
      
      // `Subscriber 1` will also receive those
      s.next('value1 !!');
      s.next('value2 !!');
      
      /* 
      SUBSCRIBER 1: value1 !!
      SUBSCRIBER 2: value1 !!
      SUBSCRIBER 1: value2 !!
      SUBSCRIBER 2: value2 !!
      */
      
      
      const bs = new BehaviorSubject(null);
      
      bs.next('not seen');
      
      // It will retain only the last value for the new subscribers
      bs.next('hmmm!!')
      
      bs.subscribe(v => console.log('subscriber 1 of BS: ', v))
      
      bs.next('value1!')
      bs.subscribe(v => console.log('subscriber 2 of BS: ', v))
      
      /* 
      subscriber 1 of BS: hmmm!!
      subscriber 1 of BS: value1!
      subscriber 2 of BS: value1!
      */
      

      Here 是一个 StackBlitz 演示,如果您想探索的话。

      因此,如果您将 Subject 替换为 BehaviorSubject(null),它应该可以工作。

      1. 正如您所提到的,AuthService 不是AppModule 的一部分。有可能得不到单身
        我认为您可以通过将 Injectable({ providedIn: 'root' }) 装饰器添加到您的 AuthService 类来修复它(这也将使服务可摇树)。

      【讨论】:

        【解决方案3】:

        将数据存储在本地存储中,并在组件中的任何位置访问它,只需创建一个共享服务即可获取信息并使用它。 通过 {{}} 字符串插值 服务部分

        getUserInfo() {
           const savedCredentials = localStorage.getItem(credentialsKey);
            return JSON.parse(savedCredentials);
          }
        

        组件部分:

         this.currentUser = this.authService.getUserInfo();
        

        并像这样访问数据:

        this.currentUser.BusinessDate
        

        【讨论】:

          【解决方案4】:

          来自组件

              import { Component, OnInit, ViewChild} from '@angular/core';
              import { dataService } from "src/app/service/data.service";
              @Component( {
                  selector: 'app-sideWidget',
                  templateUrl: './sideWidget.html',
                  styleUrls: ['./linked-widget.component.css']
              } )
              export class sideWidget{
          
              constructor( private LWTableColumnNames: dataService ) { 
          
              }
          
              ngOnInit() {
               this.LWTableColumnNames.refLWTableColumnNames =  "patient"; //this line of code will pass the value through data service
          
              }    
              }
          

          数据服务

          import { Injectable } from '@angular/core';
          import { BehaviorSubject, Observable } from 'rxjs';
          
          @Injectable()
          export class dataService {
              refLWTableColumnNames: string;//creating an object for the data
          }
          

          到组件

          import { Component, OnInit } from '@angular/core';
          import { dataService } from "src/app/service/data.service";
          
          @Component( {
              selector: 'app-linked-widget',
              templateUrl: './linked-widget.component.html',
              styleUrls: ['./linked-widget.component.css']
          } )
          export class LinkedWidgetComponent implements OnInit {
          
              constructor(private LWTableColumnNames: dataService) { }
          
              ngOnInit() {
              console.log(this.LWTableColumnNames.refLWTableColumnNames); // out put will be string "patient"
              }
          
          }
          

          Stackbliz demo 这样你就可以将值发送到不同的兄弟组件(不仅仅是父子组件)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-08-27
            • 1970-01-01
            • 2021-07-28
            • 2021-03-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多