首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >角5.相互导入类时类型标中的循环依赖关系

角5.相互导入类时类型标中的循环依赖关系
EN

Stack Overflow用户
提问于 2018-04-24 12:57:48
回答 4查看 1.3K关注 0票数 4

在角5应用与TypeScript。当尝试实现组件之间的通信时,我遇到了称为循环依赖项的问题。有两个组件radioradio-group

代码语言:javascript
复制
<radio-group [(value)]='selected'>
  <radio value='1'></radio>
  <radio value='2'></radio>
  <radio value='3'></radio>
</radio-group>

当用户选择和取消选择项时,它们相互通信。

组件实现示例RadioGroupComponent:

代码语言:javascript
复制
import { Component, forwardRef, Input, Optional, ContentChildren, 

QueryList, EventEmitter, Output, ChangeDetectorRef, ChangeDetectionStrategy, AfterContentInit, OnChanges } from '@angular/core';
import { RadioGroup } from './radio-group.component';

@Component({
  selector: 'radio',
  styles: [`:host{cursor:pointer;}`],
  template: `<div (click)='check()'>
  <span *ngIf='!checked'>⚪️</span>
  <span *ngIf='checked'></span>
  <span>Click me. Value: {{value}} Checked: {{checked}}</span>
  </div>`,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class Radio  {
  @Input() value: any;
  checked = false;
  private _radioGroup: RadioGroup;
  constructor(@Optional() radioGroup: RadioGroup, public cd: ChangeDetectorRef){
    this._radioGroup = radioGroup;
  }
  check(){
    this.checked = true;
    if(this._radioGroup){
      this._radioGroup.selected = this;
    }
    this.markForCheck();
  }
  markForCheck(){
    this.cd.markForCheck();
  }
}

RadioComponent:

代码语言:javascript
复制
import { Component, forwardRef, Input, Optional, ContentChildren, QueryList, EventEmitter, Output, ChangeDetectorRef, ChangeDetectionStrategy, AfterContentInit, OnChanges } from '@angular/core';
import { Radio } from './radio.component';

@Component({
  selector: 'radio-group',
  template: `<ng-content></ng-content>`,
})
export class RadioGroup implements AfterContentInit, OnChanges{
  set selected (component:Radio){
    this._selected = component;
    this.valueChange.emit(component.value);
  } 
  private _selected:Radio = null;
  @Input() value:any;
  @Output() valueChange = new EventEmitter();
  @ContentChildren(forwardRef(() => Radio)) radioComponents: QueryList<Radio>;

  ngAfterContentInit() { this.checkParentComponents();}
  ngOnChanges(){ this.checkParentComponents();}
  checkParentComponents():void{
    this.radioComponents 
    && this.radioComponents.forEach(item=>{
        item.checked = item.value==this.value;
        if(item.checked){ this._selected = item;}
        item.markForCheck();
    });
  }
}

在线示例

在一个文件中使用所有声明的示例(stackblitz.com)

带分隔文件的坏示例(stackblitz.com)

问题

如何通过循环依赖来解决这个问题,并将所有组件和实现放入分离的文件中?随着时间组件变得沉重,我如何将它们切成碎片?

EN

回答 4

Stack Overflow用户

发布于 2018-04-24 13:39:47

您不应该从RadioGroup编辑Radio属性。子组件和父组件之间的通信应该通过@Input@Output进行。

因此,从RadioGroup构造函数中删除Radio。相反,你可以做下面的事情,

代码语言:javascript
复制
import { 
   Component, 
   Input,
   EventEmitter,
   Output,
   ChangeDetectorRef,
   ChangeDetectionStrategy
} from '@angular/core';

@Component({
  selector: 'radio',
  styles: [`:host{cursor:pointer;}`],
  template: `
     <div (click)='check()'>
        <span *ngIf='!checked'>⚪️</span>
        <span *ngIf='checked'></span>
        <span>Click me. Value: {{value}} Checked: {{checked}}</span>
     </div>`,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class Radio  {
  @Input() value: any;
  @Output() valueChange: EventEmitter<any> = new EventEmitter();
  checked = false;
  constructor(public cd: ChangeDetectorRef){
  }
  check(){
    this.checked = true;
    this.valueChange.emit(this.value);
    this.markForCheck();
  }
  markForCheck(){
    this.cd.markForCheck();
  }
}

RadioGroup.component

代码语言:javascript
复制
@Component({
  selector: 'radio-group',
  template: `<ng-content></ng-content>`,
})
export class RadioGroup implements AfterContentInit, OnChanges, OnDestroy {
  set selected(component: Radio) {
    this._selected = component;
    this.valueChange.emit(component.value);
  }
  private _selected: Radio = null;
  @Input() value: any;
  @Output() valueChange = new EventEmitter();
  @ContentChildren(forwardRef(() => Radio)) radioComponents: QueryList<Radio>;

  subscriptionList = [];

  ngAfterContentInit() { this.checkParentComponents(); }
  ngOnChanges() { this.checkParentComponents(); }
  checkParentComponents(): void {
    if (this.radioComponents) {
      this.subscriptionList = this.radioComponents.map(item => {
        item.checked = item.value === this.value;
        if (item.checked) { this._selected = item; }
        item.markForCheck();
        // subscribe to each child "valueChange" event and return these subscriptions.
        return item.valueChange.subscription(value => this.selected = value);
      });

    }
  }

  ngOnDestroy() {
      // don't forget to unsubscribe.
      if (this.subscriptionList && this.subscriptionList.length ) {
          this.subscriptionList.forEach(sub => sub.unsubscribe());
      }
  }
}
票数 2
EN

Stack Overflow用户

发布于 2018-04-24 13:20:34

Radio组件构造函数中尝试而不是

代码语言:javascript
复制
constructor(@Optional() radioGroup: RadioGroup, public cd: ChangeDetectorRef)

这段代码

代码语言:javascript
复制
constructor(@Inject(forwardRef(() => RadioGroup)) radioGroup: RadioGroup, public cd: ChangeDetectorRef)
票数 0
EN

Stack Overflow用户

发布于 2019-03-14 19:59:20

当您需要设置组件之间的通信时

不能使用@Output@Input,使用providers。DependencyInjection允许您在需要时重写构造函数类中的注入。

DependencyInjection (angular.io)

避免循环依赖(angular.io)

无线电组.组件:

代码语言:javascript
复制
import { RadioGroupBase } from './radio-group-base';

@Component({
  selector: 'radio-group',
  ...
  ==> providers: [{provide: RadioGroupBase, useExisting: RadioGroup}]
})
export class RadioGroup implements AfterContentInit, OnChanges{
...
}

radio.component.ts:

代码语言:javascript
复制
import { RadioGroupBase } from './radio-group-base';

@Component({
  selector: 'radio',
  ...
})
export class Radio  {
  constructor(
   ==> @Optional() radioGroup: RadioGroupBase, 
  ){
    //variable radioGroup will be undefined when there is no provider.
  }

无线电-群-基地:

代码语言:javascript
复制
export class RadioGroupBase {
  selected: any;
}

工作解决方案:

https://stackblitz.com/edit/angular-gyqmve

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50002311

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档