通过组件共享数据

Sharing Data through components

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

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

我试过使用服务共享数据。

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

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);
  }

}

我正在使用 angular 8.2.0

来自组件

    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 这样你就可以将值发送到不同的兄弟组件(不仅是父子组件)

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

  1. changeState 主题在 导航栏组件订阅它之前 发出数据。 据我所知,当你在登录页面时,导航栏组件不应该被加载。当你。在您的 LoginComponent 中,您 首先发出 数据,然后,当 NavbarComponent 加载时,您订阅刚刚发出的 observable。
    但是,因为您使用了 Subject,您将 不会获得 last emitted 值。 为了减轻这种情况,您可以使用 BehaviorSubject,它将 retain last emitted value for 新订阅者.

主题与行为主题

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 class 来修复它(这也将使服务可摇树)。

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 {}

如果在Angular8,你也可以这样做:

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

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

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

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

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

组成部分:

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

并像这样访问数据:

this.currentUser.BusinessDate