3

我在 Angular 6 中使用 componentFactoryResolver 创建了一个动态组件,我需要每 3 秒更新一次它的属性。

const componentFactory = this.cfr.resolveComponentFactory(componentType);
const component: ComponentRef<any> = vcr.createComponent(componentFactory);

component.instance.property = this.newData;

    setInterval(() => {
      this.loadNewData().then((data) => {
        this.newData = data;
      });
    }, 3000);

该属性没有得到更新。我发现动态生成的组件不支持属性绑定。那么,如何使用新数据更新属性?有什么解决方法吗?

4

4 回答 4

1

在这些类型的用例中使用ng-interconnect进行通信。

  1. 在父组件中创建广播器

     let broadcaster = interconnect.createBroadcaster('home-messgae');   
    
  2. 从动态组件内部从广播者接收

     interconnect.receiveFrom('home-message', '', (data) => {
        console.log('do something with ' + data);
     );
    
  3. 从父组件开始发射

    broadcaster.emit('hello dynamic child');
    

文章:https ://charlie-code.medium.com/simplify-your-angular-development-using-ng-interconnect-1b94c68e9141

于 2020-11-10T03:58:58.200 回答
1

有点晚了,但我发现你的问题很有趣...... :)

我做了一个 Stackblitz 示例:https ://stackblitz.com/edit/angular-3gvrrz

由于我不完全确定您的要求,因此我在共享服务中使用@Input()和使用 a来制作示例。BehaviorSubject

export class AppComponent implements OnInit {
  name = 'Angular';
  @ViewChild(ContainerDirective, { static: true }) container: ContainerDirective;
  DATA = ['Angular', 'Material', 'Nativescript', 'Ionic'];
  index = 0;

  constructor(private componentFactoryResolver: ComponentFactoryResolver,
    private commonService: CommonService) {}

  ngOnInit() {
    const viewContainerRef = this.container.viewContainerRef;
    viewContainerRef.clear();
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(HelloComponent);
    const componentRef = viewContainerRef.createComponent(componentFactory);
    (<HelloComponent>componentRef.instance).name = 'Starting...';

    setInterval(() => {
      if (this.index > this.DATA.length - 1) {
        this.index = 0;
      }
      const nextName: string = this.DATA[this.index++];
      (<HelloComponent>componentRef.instance).name = nextName;
      this.commonService.setName(nextName)
    }, 3000);
  }
}
于 2019-12-13T00:06:22.550 回答
0

https://github.com/BhadraAnirban/dynamic_component_to_HTMLElement/blob/main/README.md

我们将数据传递给组件属性。

如果您使用 [innerHTML] 来呈现来自服务器的 html 内容,它也将起作用。

<div [innerHtml]="templateString"></div>

创建一个组件(这里我已经创建了 - SignatureControlComponent)并将其添加到模块的 entryComponent 中。

@Component({
  selector: 'app-signature-control',
  templateUrl: './signature-control.component.html',
  styleUrls: ['./signature-control.component.scss']
})
export class SignatureControlComponent implements OnInit {
role: string;
}

在 app.nmodule-

entryComponents: [SignatureControlComponent]

在您将要创建组件并添加到 HTML 元素的主组件中(我使用了 EditTemplateComponent)。

使用构造函数注入 ComponentFactoryResolver、ViewContainerRef、Renderer2。

constructor( 
  private elem: ElementRef, private viewContainerRef: ViewContainerRef,
  private componentFactoryResolver: ComponentFactoryResolver, private renderer: Renderer2) { }

使用 ngAfterViewChecked 生命周期钩子获取使用类的 HTML 元素(我使用了类名“签名”)。这也将 [innerHTML] 用于呈现来自服务器的 html 内容。

ngAfterViewChecked() {
    if(!this.isElementsRendered)
    {
      
      let elements = this.elem.nativeElement.querySelectorAll('.Signature');
      if(elements.length > 0)
      {
        this.isElementsRendered = true;
        elements.forEach(element => {
          this.CreateSignatureComponent(element);
        })
      }
    }   
  }

最后创建组件的实例并附加到元素。

CreateSignatureComponent(element: HTMLElement){    
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(SignatureControlComponent);    
    let componentInstance = this.viewContainerRef.createComponent(componentFactory);
    const loaderComponentElement = componentInstance.location.nativeElement;
  // Assign value to the property
    componentInstance.instance.role = 'PMKJ!';

    this.renderer.appendChild(element, loaderComponentElement);
  }

于 2021-05-22T18:52:48.703 回答
0

使用您的代码示例。您创建一个组件工厂如下

const componentFactory = this.cfr.resolveComponentFactory(componentType);

然后使用视图容器引用创建组件引用,如下所示:

this.componentRef = vcr.createComponent(componentFactory);

您应该能够使用此组件引用来更新您当前的组件。通过执行以下操作: (this.componentRef.instance).value = this.value在您的 setInterval 函数中。在您的代码中,它看起来像这样:

setInterval(() => {
  this.loadNewData().then((data) => {
    (this.componentRef.instance).newData = data;
  });
}, 3000);

如果您@Input() newData: any;在组件中放置一个必须接收新数据的组件,那么您的组件应该接收数据。希望这会有所帮助并完全回答您的问题。

于 2021-05-13T13:26:08.770 回答