简体   繁体   English

如何在 angular 的服务和组件之间共享数据?

[英]How to share data between angular's services and components?

How to bind data between services and components in real time way.如何实时绑定服务和组件之间的数据。

let's suppose isAuthenticated a public variable for Authentication service that is affecting some view in a component.让我们假设isAuthenticated是身份验证服务的公共变量,该变量影响组件中的某些视图。 My question is how to subscribe to isAuthenticated variable?我的问题是如何订阅isAuthenticated变量?

Service:服务:

import { Injectable } from '@angular/core';

@Injectable()
export class Authentication {

  isAuthenticated:boolean = false;

  login() {
    localStorage.setItem('access_token', 'true');
    this.isAuthenticated = true;
  }
}

Component:成分:

...
@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
private isAuthenticated:boolean = false;
  constructor(public authService: Authentication) { 
   this.isAuthenticated = this.authService.isAuthenticated'
  }
}

home.html主页.html

...
<div *ngIf="isAuthenticated">Authentication view</div>
<div *ngIf="!isAuthenticated">Unauthentication view</div>
...

By the current flow above, the binding is working well but isn't real time.根据上面的当前流程,绑定运行良好,但不是实时的。

So what is the best approach:那么最好的方法是什么:

1- Create an observable inside the Authentication service in order to subscribe to it inside the component. 1- 在 Authentication 服务中创建一个 observable 以便在组件内部订阅它。

2- Binding using the following way: 2- 使用以下方式绑定:

...
<div *ngIf="authService.isAuthenticated">Authentication view</div>
<div *ngIf="!authService.isAuthenticated">Unauthentication view</div>
...

The second approach is working well but I don't know if it is the best practice.第二种方法效果很好,但我不知道这是否是最佳实践。

Thanks.谢谢。

I would recommend using BehaviorSubject .我建议使用BehaviorSubject It's an Observable , so you can subscribe to it, but you can also control when it emits new values by calling behaviorSubject.next(newValue) .它是一个Observable ,所以你可以订阅它,但你也可以通过调用behaviorSubject.next(newValue)来控制它何时发出新值。 When creating BehaviorSubject you must pass inital value to it.创建 BehaviorSubject 时,您必须将初始值传递给它。 In your case it's false .在你的情况下,它是false

@Injectable()
export class Authentication {

  isAuthenticated = new BehaviorSubject<boolean>(false);

  login() {
    localStorage.setItem('access_token', 'true');
    this.isAuthenticated.next(true);
  }

}

- ——

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {

  private isAuthenticated:boolean;

  constructor(public authService: Authentication) { 
   this.authService.isAuthenticated
    .subscribe(isAuthenticated => this.isAuthenticated = isAuthenticated)
  }

}

or you can subscribe in html with Async Pipe或者您可以使用 Async Pipe 在 html 中订阅

export class HomePage {

  private isAuthenticated: BehaviorSubject<boolean>;

  constructor(public authService: Authentication) { 
   this.isAuthenticated = this.authService.isAuthenticated;
  }

}

- ——

<div *ngIf="isAuthenticated | async">Authentication view</div>
<div *ngIf="!(isAuthenticated | async)">Unauthentication view</div>

Unlike regular Observable, when you call subscribe on BehaviorSubject, the function you passed as an argument to subscribe will be immediately executed.与常规的 Observable 不同,当您在 BehaviorSubject 上调用 subscribe 时,您作为参数传递给 subscribe 的函数将立即执行。 This is because BehaviorSubject always has a value.这是因为 BehaviorSubject 总是有一个值。 You can access it with this.authService.isAuthenticated.value but it's not very useful here.您可以使用this.authService.isAuthenticated.value访问它,但它在这里不是很有用。

I assume from your tag you are using Ionic framework?我从你的标签中假设你正在使用 Ionic 框架? Could this maybe be done using events?这可以使用事件来完成吗?

    // first page (publish an event when a user is created)
constructor(public events: Events) {}
createUser(user) {
  console.log('User created!')
  this.events.publish('user:created', user, Date.now());
}


// second page (listen for the user created event after function is called)
constructor(public events: Events) {
  events.subscribe('user:created', (user, time) => {
    // user and time are the same arguments passed in `events.publish(user, time)`
    console.log('Welcome', user, 'at', time);
  });
}

Example code taken from: https://ionicframework.com/docs/v3/api/util/Events/示例代码取自: https : //ionicframework.com/docs/v3/api/util/Events/

Make use of RXJS.使用 RXJS。 Using BehaviourSubjects allows you to push state and subscribe to state changes throughout multiple components that inject the service and have an initial state.使用 BehaviourSubjects,您可以在注入服务并具有初始状态的多个组件中推送状态并订阅状态更改。 When defining a BehaviourSubject you must also define a starting value which here is false.在定义 BehaviourSubject 时,您还必须定义一个起始值,此处为 false。 All you have to do is call .next(true) on the BehaviourSubject to push state as shown below:你所要做的就是在 BehaviourSubject 上调用.next(true)来推送状态,如下所示:

...
@Injectable()
export class Authentication {

  private _isAuthenticated: BehaviourSubject<boolean> = new BehaviourSubject(false);

  public get isAuthenticated(): Observable<boolean> {
    return this._isAuthenticated.asObservable();
  }

  login() {
    localStorage.setItem('access_token', 'true');
    this._isAuthenticated.next(true);
  }
}

Using a get method on your service allows you to return an observable without publically exposing the methods on the BehaviourSubject.在您的服务上使用 get 方法允许您返回一个可观察对象,而无需公开暴露 BehaviourSubject 上的方法。

Then in your component:然后在您的组件中:

...
@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage implements OnInit {
  private isAuthenticated:boolean = false;
  private readonly _authService: Authentication;
  constructor(authService: Authentication) {
    this._authService = authService;
  }

  public ngOnInit(): void {
   this._authService.isAuthenticated
     .subscribe((isAuthenticated) => this.isAuthenticated = isAuthenticated)
  }
}

At the moment I'm using this solution:目前我正在使用这个解决方案:

import { DoCheck } from '@angular/core';

//...

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  private isAuthenticated:boolean = false;
  constructor(public authService: Authentication) { }

  ngDoCheck() {
      if (this.authService.isAuthenticated)) {
        //..if authenticated do this
      } else {
        //..if not do this
      }
  }
}

Even if I'm not sure this is a nice way.即使我不确定这是一个很好的方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM