首页 文章

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

提问于
浏览
6

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

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

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

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

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

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

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

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

  • 用户组件使用user.firstName,user.lastName等呈现模板 .

  • 最初用户是否为空对象

  • 登录服务需要设置UserService.user

  • userComponent需要检测更改并更新DOM .

提前致谢!

2 回答

  • 4

    如果我'm not wrong, you are looking for a way to '听你的 UserService.user 中的更改,以便在 UserComponent 中进行适当的更新 . 使用 Subject (或 BehaviorSubject )可以很容易地做到这一点 .

    • UserService 中,使用 Subject<User> 类型声明属性 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 中,订阅 UserServiveuser$ observable 来更新视图 .
    this.userService.user$.subscribe((userData) => {this.user = userData;});
    
    • 在您看来,只需使用字符串插值:
    {{user?.firstName}} {{user?.lastName}}
    

    这是工作的plunker:http://plnkr.co/edit/qUR0spZL9hgZkBe8PHw4?p=preview

  • 8

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

    1. Share data via JavaScript reference types

    如果在UserService中创建对象

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

    然后,您可以通过它作为JavaScript引用类型来共享该对象 . 注入UserService的任何其他服务或组件都可以访问该 user 对象 . 只要您在服务中使用 only modify the original object (即,您没有指定新对象),

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

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

    这是一个例子plunker .

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

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

    2. "Push" data using RxJS

    @HarryNinh在他的回答中说得很清楚 . 另见Cookbook主题Parent and children communicate via a service . 它显示了如何使用主题来促进沟通"within a family" .

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


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

    方法2.也可能比1.更有效,但是因为Angular的默认变化检测策略是"check all components",你需要使用 OnPush 变化检测策略和markForCheck()(我不会在这里讨论如何使用它们)使其比方法1更有效 .

相关问题