在Angular 2服务中绑定到数据对象的正确方法是什么?

时间:2016-08-13 02:17:47

标签: javascript angularjs angular

我正在构建一个角度2应用程序。自发布以来,文档发生了很大的变化,引起了混乱。我能做的最好的事情就是解释我想要做的事情(在Angular 1中这很容易)并希望有人可以帮助我。

我使用JWT创建了一个登录服务。 登录成功后,我返回一个用户对象。

我有一个loginComponent(将数据绑定到模板)和loginService(处理https调用)

我有一个维护用户对象的userService。

我有一个userComponent,用于呈现用户数据。

问题是,一旦用户登录,我不清楚让userService在名为" user"的对象中检索新数据的最佳方法,然后userComponent更新其用户对象模板。只需将观察者放在userService.user对象上,就可以轻松实现角度1。

我尝试输入和输出无效,eventEmitters,Observables和getter and setter。 getter和setter工作,但强迫我将所有内容存储在" val()"

有人可以告诉我实现这个目标的最佳途径吗?

  1. 用户组件使用user.firstName,user.lastName等呈现模板。
  2. 最初用户是否为空对象
  3. 登录服务需要设置UserService.user
  4. userComponent需要检测更改并更新DOM。
  5. 先谢谢!

2 个答案:

答案 0 :(得分:8)

如果我没有错,那么你正在寻找一种方法来聆听'要更改UserService.user,以便在UserComponent中进行适当的更新。使用Subject(或BehaviorSubject)很容易做到这一点。

- 在UserService中,声明属性user,其类型为Subject<User>

user: Subject<User> = new Subject();

- 将其暴露在外面作为可观察的:

user$: Observable<User>
...
this.user$ = this.user.asObservable();

-Login函数将更新私人user主题。

login(userName: string, password: string) {
  //...
  this.user.next(new User("First name", "Last name"));
}

- 在UserComponent,订阅UserServive user$ observable以更新视图。

this.userService.user$.subscribe((userData) => {this.user = userData;});

- 在您看来,只需使用字符串插值:

{{user?.firstName}} {{user?.lastName}}

以下是工作人员:http://plnkr.co/edit/qUR0spZL9hgZkBe8PHw4?p=preview

答案 1 :(得分:4)

您可以采取两种不同的方法:

<强> 1。通过JavaScript引用类型共享数据

如果您在UserService中创建对象

@Injectable()
export class UserService {
   public user = new User();

然后,您可以通过它作为JavaScript引用类型来共享该对象。注入UserService的任何其他服务或组件都可以访问该user对象。只要您仅修改原始对象(即,您没有为服务分配新对象),

   updateUser(user:User) {
       this.user.firstName = user.firstName;
       this.user.lastName  = user.lastName;
   }

所有视图都会在更改后自动更新并显示新数据(因为Angular更改检测的工作方式)。有no need for any Angular 1-like watchers

以下是plunker的示例。

在plunker中,它有一个共享的user对象,而不是共享的data对象。您可以单击更改数据按钮,该按钮将在服务上调用changeData()方法。您可以看到,当服务更改其data属性时,AppComponent的视图会自动更新。您不必编写任何代码来使其工作 - 不需要getter,setter,Input,Output / EventEmitter或Observable。

视图更新自动发生,因为(默认情况下)角度更改检测会在每次启动猴子修补的异步事件(例如按钮单击)时检查所有模板绑定(如{{data.prop1}})。

<强> 2。 “Push”数据使用RxJS

@HarryNinh在他的回答中说得很清楚。另见Cookbook主题Parent and children communicate via a service。它显示了如何使用主题来促进“在一个家庭中”的沟通。

我建议使用BehaviorSubject而不是Subject,因为BehaviorSubject具有“当前值”的概念,这可能适用于此处。考虑一下,如果使用路由和(基于某些用户操作)移动到新路由并创建新组件,您可能希望新组件能够检查用户的“当前值”。你需要一个BehaviorSubject来完成这项工作。如果使用常规Subject,则新组件将无法检索当前值,因为Subject的订阅者只能获取新发出的值。

那么,我们应该使用方法1还是2.?像往常一样,“它取决于”。方法1.代码少得多,您不需要了解RxJS(但您需要了解JavaScript引用类型)。方法2.这些日子风靡一时。

方法2.也可能比1.更有效,但由于Angular的默认变更检测策略是“检查所有组件”,您需要使用OnPush更改检测策略和markForCheck() (我不会在这里讨论如何使用它们)使其比方法1更有效。