使用 angular2 从服务更新组件中的变量更改

IT技术 javascript angular
2021-03-12 04:28:20

我的应用程序有一个 NameService 保存名称。

App 有两个子组件 Navbar 和 TheContent 引用此服务。每当服务中的名称发生变化时,我都希望它在其他两个组件中都进行更新。我怎样才能做到这一点?

import {Component, Injectable} from 'angular2/core'

// Name Service

@Injectable()
class NameService {
  name: any;
  constructor() {
    this.name = "Jack";
  }
  change(){
    this.name = "Jane";
  }
}

// The navbar
@Component({
  selector: 'navbar',
  template: '<div>This is the navbar, user name is {{name}}.</div>'
})
export class Navbar {
  name: any;
  constructor(nameService: NameService) {
    this.name = nameService.name;
  }
}

// The content area
@Component({
  selector: 'thecontent',
  template: '<div>This is the content area. Hello user {{name}}. <button (click)=changeMyName()>Change the name</button></div>'
})
export class TheContent {

  name: any;

  constructor(public nameService: NameService) {
    this.name = nameService.name;
  }
  changeMyName() {
       this.nameService.change();
     console.log(this.nameService.name);
  }
}


@Component({
  selector: 'app',
  providers: [NameService],
  directives: [TheContent, Navbar],
  template: '<navbar></navbar><thecontent></thecontent>'
})
export class App {
  constructor(public nameService: NameService) {
  }
}
3个回答

在服务中提供一个事件并在组件中订阅它:

@Injectable()
class NameService {
  name: any;
  // EventEmitter should not be used this way - only for `@Output()`s
  //nameChange: EventEmitter<string> = new EventEmitter<string>();
  nameChange: Subject<string> = new Subject<string>();
  constructor() {
    this.name = "Jack";
  }
  change(){
    this.name = 'Jane';
    this.nameChange.next(this.name);
  }
}
export class SomeComponent { 
  constructor(private nameService: NameService) {
    this.name = nameService.name;
    this._subscription = nameService.nameChange.subscribe((value) => { 
      this.name = value; 
    });
  }

  ngOnDestroy() {
   //prevent memory leak when component destroyed
    this._subscription.unsubscribe();
  }
}

另请参阅
angular.io - COMPONENT INTERACTION - 父母和孩子通过服务进行交流

@micronyks 问题不在于重新加载恕我直言时保持value。为此,您需要将数据持久化到服务器并重新加载它,或者至少使用 localstorage 将其存储在浏览器中。
2021-04-21 04:28:20
let subscription=nameService.nameChange.subscribe((value) => { this.name = value; }); subscription.unsubscribe(). 我遇到了这个问题,因此免责声明。如果订阅必须从其他方法取消,则该变量应为类级别
2021-04-30 04:28:20
我一直在尝试实施此解决方案,但在服务中出现错误,提示property 'emit' does not exist on type 'Subject<string>'. 我在上述解决方案中遗漏了什么吗?此解决方案是否有可用的 Plunkr?
2021-04-30 04:28:20
还要记得取消订阅组件中的事件,否则组件实例不会被释放。需要对 subscribe 函数返回的对象调用 unsubscribe 。
2021-05-02 04:28:20
@Scipion 一般来说,如果您强制订阅,您也应该强制取消订阅。在这种情况下,订阅此服务的组件可能仍会执行传递给subscribe()名称更改的回调,即使它已经被销毁,因为订阅在组件被垃圾收集之前一直保持活动状态,这可能不会在订阅结束之前发生取消。
2021-05-05 04:28:20

由于nameinNameService是一种原始类型,您将在服务和组件中获得不同的实例。当您name在 中更改NameService,组件属性仍然具有初始值,并且绑定无法按预期工作。

您应该在此处应用 angular1“点规则”并绑定到引用类型。更改NameService以存储包含名称的对象。

export interface Info {
   name:string;
}

@Injectable()
class NameService {
  info: Info = { name : "Jack" };
  change(){
    this.info.name = "Jane";
  }
}

您可以绑定到此对象并name自动获取属性更新

// The navbar
@Component({
  selector: 'navbar',
  template: '<div>This is the navbar, user name is {{info.name}}.</div>'
})
export class Navbar {
  info: Info;
  constructor(nameService: NameService) {
    this.info = nameService.info;
  }
}
“如果你改变了nameNameService你的服务和组件就会有一个不同的实例。” 即使您不更改该值,组件也会name在构造函数中获得自己的原始属性。这个新的原始属性的初始值是name分配时服务中属性的值我想说明的一点是,对于原始类型,您永远不会拥有相同的“实例”。一个带有引用类型的人可以获得两个(或更多)引用同一个实例的东西。
2021-04-17 04:28:20
@BHull,它之所以有效,是因为对于一个对象,服务和组件都引用同一个对象……并且它们每个都有对那个对象引用对于原始类型(字符串、数字、布尔值),组件在构造函数中获得它自己的原始值副本。name对服务中的原始属性所做的任何更改都与您name对组件中的原始属性所做的任何更改无关
2021-04-21 04:28:20
哇,为什么这与 EventEmitter 方式相比有效?感觉工作少了很多?
2021-05-06 04:28:20
@micronyks 在 angular2 中,您可以拥有多个服务实例。您不应providers在两个组件上都定义这样每个组件都有自己的NameService plnkr.co/edit/nScZgT1hsIKHZ7Z5E6u3?p=preview
2021-05-07 04:28:20
这也是我要做的方式。在 angular 1 中,“模型中总是有一个点”是减少同步绑定工作的好方法,它可能也适用于 Angular2,具体取决于用例。没有它,使用事件发射器来同步模型会变得乏味。
2021-05-15 04:28:20

我认为 Günter 提供的解决方案是最好的。

也就是说,您必须意识到 Angular2 服务是发生在注入器树中的单例。这意味着:

  • 如果您在应用程序级别(在方法的第二个参数内)定义您的服务,则bootstrap该实例可以由所有元素(组件和服务)共享。
  • 如果您在组件级别(在providers属性内)定义服务,则实例将特定于组件及其子组件。

有关此类方面的更多详细信息,您可以查看“分层依赖注入”文档:https : //angular.io/docs/ts/latest/guide/hierarchical-dependency-injection.html

希望对你有帮助,蒂埃里