Angular 5 项服务数据未更新
Angular 5 service data not updating
我从 AngularJS 迁移到 Angular(2+) 的速度变慢了,只是偶然发现了一些东西。
在 AngularJS 中,我使用了很多工厂和服务来跨指令、控制器和其他服务共享数据。很容易在一个地方更新服务,然后在其他地方自动更新。
但是,当我更改服务变量时,我试图以类似的方式在 Angular 5 和 "nothing is happening" 中使用服务。
我看到一些解决方案涉及创建 "pull" 新数据的函数或更新 "Angular change service" 以将事件绑定到变量的建议。
但是,我的应用程序在很多地方使用了很多变量。我必须在使用它们的每个组件中分别订阅每个变量,并更改服务以对每个变量发出更改,这似乎不正确。
我是不是漏掉了什么?
谢谢!!!
韦恩
例如:
主页组件。
import { Component, OnInit } from '@angular/core';
import { HomeButtonDirective } from '../home-button.directive';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
主页重复使用的按钮指令:
import { Directive, Input, OnInit, HostListener } from '@angular/core';
import { InfoService } from './info.service';
@Directive({
selector: '[appHomeButton]',
providers: [InfoService]
})
export class HomeButtonDirective {
@HostListener('click', ['$event']) onclick($event) {
this.info.showHome = false;
}
constructor(private info: InfoService) { }
ngOnInit() {
}
}
应用组件。如果 showHome===true:
将显示主页
import { Component } from '@angular/core';
import { InfoService } from './info.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
providers: [InfoService]
})
export class AppComponent {
title = 'Testing a service';
showHome = true;
constructor(private info: InfoService) {
this.showHome = this.info.showHome; // this works...showHome becomes false per the service (see below)
}
}
最后,服务:
import { getTestBed } from '@angular/core/testing';
import { Injectable } from '@angular/core';
@Injectable()
export class InfoService {
showHome = false;
}
以我的经验,你说的变量可能是一个对象,你改变它的值属性而是它本身
你应该改变对象本身而不是改变他的属性。
所以,如果你想改变一个复杂的服务对象,你最好这样写代码:
this.oldObject = anotherObject
如有必要,将旧对象复制到新对象。
希望对您有所帮助。
It is easy to update the service in one place and have it update
everywhere else automatically.?
使用 Angular 模块而不是组件注册服务。
from Angular
docs
Angular module providers (@NgModule.providers)
are registered with the
application's root injector. Angular can inject the corresponding
services in any class it creates. Once created, a service instance
lives for the life of the app and Angular injects this one service
instance in every class that needs it.
总结
如果我们希望全局共享依赖项的实例并在整个应用程序中共享 state
我们在 NgModule.
上配置它
如果我们希望在组件的每个实例及其子实例之间共享依赖项的单独实例,我们在组件上配置它 providers
属性.
从 AngularJS 迁移到 Angular 时,我有相同的观察结果。
问题
我将使用一些示例代码来描述问题。假设我们正在构建一个 CommentComponent
来显示评论,并且数据来自名为 CommentService
的服务。然后我们会按照以下方式写一些东西:
this.comments: Array<Comment> = this.commentsService.commments;
这在初始化期间工作得很好。但是,当服务中的数据发生变化时(例如,将新评论推送到数组时),我们不会看到这些变化反映到我们的组件中。这是因为上面的代码只是构造函数内部的直接 (one-time) 赋值,意味着没有 two-way 绑定。
可能的解决方案
有多种解决方案可以解决上述问题。我会分享我知道的那些,但请随时扩展答案。
使用 Observables
在这种情况下,我更喜欢使用 BehaviorSubject,因为它会立即 return 订阅时的初始值或当前值。
private comments$: BehaviorSubject<Comment> = new BehaviorSubject([]);
...并在您的组件或您需要反映更改的任何地方订阅可观察对象:
this.commentsService.subscribe(comments => this.comments = comments);
从模板引用
另一种解决方案(或解决方法)是直接从模板引用服务 属性,这允许 two-way 绑定:
<div *ngFor="let comment of commentsService.comments">
{{ comment | json }}
</div>
更改检测策略
另一个解决方案可能是调整 Change Detection Strategy。
我从 AngularJS 迁移到 Angular(2+) 的速度变慢了,只是偶然发现了一些东西。
在 AngularJS 中,我使用了很多工厂和服务来跨指令、控制器和其他服务共享数据。很容易在一个地方更新服务,然后在其他地方自动更新。
但是,当我更改服务变量时,我试图以类似的方式在 Angular 5 和 "nothing is happening" 中使用服务。
我看到一些解决方案涉及创建 "pull" 新数据的函数或更新 "Angular change service" 以将事件绑定到变量的建议。
但是,我的应用程序在很多地方使用了很多变量。我必须在使用它们的每个组件中分别订阅每个变量,并更改服务以对每个变量发出更改,这似乎不正确。
我是不是漏掉了什么?
谢谢!!! 韦恩
例如:
主页组件。
import { Component, OnInit } from '@angular/core';
import { HomeButtonDirective } from '../home-button.directive';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
主页重复使用的按钮指令:
import { Directive, Input, OnInit, HostListener } from '@angular/core';
import { InfoService } from './info.service';
@Directive({
selector: '[appHomeButton]',
providers: [InfoService]
})
export class HomeButtonDirective {
@HostListener('click', ['$event']) onclick($event) {
this.info.showHome = false;
}
constructor(private info: InfoService) { }
ngOnInit() {
}
}
应用组件。如果 showHome===true:
将显示主页import { Component } from '@angular/core';
import { InfoService } from './info.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
providers: [InfoService]
})
export class AppComponent {
title = 'Testing a service';
showHome = true;
constructor(private info: InfoService) {
this.showHome = this.info.showHome; // this works...showHome becomes false per the service (see below)
}
}
最后,服务:
import { getTestBed } from '@angular/core/testing';
import { Injectable } from '@angular/core';
@Injectable()
export class InfoService {
showHome = false;
}
以我的经验,你说的变量可能是一个对象,你改变它的值属性而是它本身
你应该改变对象本身而不是改变他的属性。
所以,如果你想改变一个复杂的服务对象,你最好这样写代码:
this.oldObject = anotherObject
如有必要,将旧对象复制到新对象。
希望对您有所帮助。
It is easy to update the service in one place and have it update everywhere else automatically.?
使用 Angular 模块而不是组件注册服务。
from Angular docs
Angular module providers
(@NgModule.providers)
are registered with the application's root injector. Angular can inject the corresponding services in any class it creates. Once created, a service instance lives for the life of the app and Angular injects this one service instance in every class that needs it.
总结
如果我们希望全局共享依赖项的实例并在整个应用程序中共享 state
我们在 NgModule.
如果我们希望在组件的每个实例及其子实例之间共享依赖项的单独实例,我们在组件上配置它 providers
属性.
从 AngularJS 迁移到 Angular 时,我有相同的观察结果。
问题
我将使用一些示例代码来描述问题。假设我们正在构建一个 CommentComponent
来显示评论,并且数据来自名为 CommentService
的服务。然后我们会按照以下方式写一些东西:
this.comments: Array<Comment> = this.commentsService.commments;
这在初始化期间工作得很好。但是,当服务中的数据发生变化时(例如,将新评论推送到数组时),我们不会看到这些变化反映到我们的组件中。这是因为上面的代码只是构造函数内部的直接 (one-time) 赋值,意味着没有 two-way 绑定。
可能的解决方案
有多种解决方案可以解决上述问题。我会分享我知道的那些,但请随时扩展答案。
使用 Observables
在这种情况下,我更喜欢使用 BehaviorSubject,因为它会立即 return 订阅时的初始值或当前值。
private comments$: BehaviorSubject<Comment> = new BehaviorSubject([]);
...并在您的组件或您需要反映更改的任何地方订阅可观察对象:
this.commentsService.subscribe(comments => this.comments = comments);
从模板引用
另一种解决方案(或解决方法)是直接从模板引用服务 属性,这允许 two-way 绑定:
<div *ngFor="let comment of commentsService.comments">
{{ comment | json }}
</div>
更改检测策略
另一个解决方案可能是调整 Change Detection Strategy。