Создание вложенных динамических компонентов в angular

Я хочу знать, как создавать вложенные динамические компоненты и поддерживать их отношения между родительскими и дочерними элементами.

Например, у меня есть такие данные,

- A
--A.1
--A.2
-B
--B.1
-C 

Я хотел создать такой компонент,

<A>
   <A1></A1>
   <A2></A2>
</A>
<B>
   <B1></B1>
</B>
<C></C>

Но с моим кодом я мог создать только родительский компонент или дочерний компонент. Но не то и другое вместе.

Ниже мой код,

  setRootViewContainerRef(view: ViewContainerRef): void {
    this.rootViewContainer = view;
  }

  createComponent(content: any, type: any) {
 console.log(content);
    if (content.child && content.child.length > 0) {
      content.child.forEach(type => {
        const typeP = this.contentMappings[type.type];
        this.createComponent(type, typeP);
      });
    } else {
      this.renderComp(content,type)
    }
  }

  renderComp(content,type) {
    if (!type) {
      return
    }
    this.componentFactory = this.componentFactoryResolver.resolveComponentFactory(type);
    this.componentReference = this.rootViewContainer.createComponent(this.componentFactory);

    if (this.componentReference.instance.contentOnCreate) {
      this.componentReference.instance.contentOnCreate(content);
    }
  }

С помощью этого кода я получаю такой вывод.

Ссылка на рабочий пример, StackBlitz

Пожалуйста, помогите мне решить эту проблему.


Обновлено.

Даже после добавления viewChild он все равно бросает viewchild not defined.

Обратитесь к этому изображению. В component.instance я не вижу дочерний элемент представления.

введите здесь описание изображения

Обновленная ссылка stackblitz https://stackblitz.com/edit/angular-dynamic-new-mepwch?file=src/app/content/a/a.component.ts


person user007    schedule 25.07.2019    source источник


Ответы (1)


Вы должны создать ViewContainer на каждом уровне, который будет отображать дочерние компоненты:

a.component.html

<p>
a works!
</p>
<ng-container #container></ng-container>

a.component.ts

export class AComponent implements OnInit {
  @ViewChild('container', { read: ViewContainerRef, static: true }) embeddedContainer: ViewContainerRef;

А затем отрендерить компонент в выделенный контейнер:

create-dynamic-component.service.ts

@Injectable()
export class CreateDynamicComponentService {
  constructor(
    private componentFactoryResolver: ComponentFactoryResolver,
    @Inject(CONTENT_MAPPINGS) private contentMappings: any,
    private inlineService: InlineService
  ) { }


  createComponent(content: any, type: any, vcRef) {
    const componentRef = this.renderComp(content, type, vcRef)
    if (content.child && content.child.length) {
      if (!componentRef.instance.embeddedContainer) {
        const cmpName = componentRef.instance.constructor.name;
        throw new TypeError(`Trying to render embedded content. ${cmpName} must have @ViewChild() embeddedContainer defined`);
      }

       content.child.forEach(type => {
        const typeP = this.contentMappings[type.type];
        this.createComponent(type, typeP, componentRef.instance.embeddedContainer);
      });
    }
  }

  renderComp(content,type, vcRef: ViewContainerRef) {
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(type);
    const componentRef = vcRef.createComponent<any>(componentFactory);

    if (componentRef.instance.contentOnCreate) {
      componentRef.instance.contentOnCreate(content);
    }

    return componentRef;
  }
}

Обратите внимание, как метод renderComp принимает ViewContainerRef из компонента с дочерними элементами:

 this.createComponent(type, typeP, componentRef.instance.embeddedContainer);

Разветвленный Stackblitz

person yurzui    schedule 25.07.2019
comment
Это не работает в Angular v8. Я получаю эту ошибку Property 'instance' does not exist on type 'void'.ts(2339) - person user007; 25.07.2019
comment
Похоже, ты что-то забыл. Попробуйте эту версию stackblitz .com / edit / angular-dynamic-new-tbz6kx? file = src / app /. - person yurzui; 25.07.2019
comment
Как вы сказали, я добавил viewChild в A comp, также обновил html, но в консоли он показывает, что must have @ViewChild() embeddedContainer defined. - person user007; 25.07.2019
comment
Вы пробовали мой пример? Вы видели, что я определил <ng-container #container></ng-container> в AComponent? Если он дает вам эту ошибку, это означает, что компонент не имеет определенного контейнера. - person yurzui; 25.07.2019
comment
Да, я определил. По какой-то причине emmbededComponent не приходит. Я добавил это в A comp `@ViewChild ('container', {read: ViewContainerRef, static: false}) embeddedContainer: ViewContainerRef;` и в html <ng-container #container></ng-container> - person user007; 26.07.2019
comment
Воспроизведите его в stackblitz - person yurzui; 26.07.2019
comment
Я воспроизвел проблему, проверьте это stackblitz.com/edit/angular-dynamic-new-mepwch?file=src/app/ - person user007; 26.07.2019
comment
@ViewChild('container', { read: ViewContainerRef, static: true }) stackblitz.com / edit / angular-dynamic-new-j7v3za? file = src / app /. - person yurzui; 26.07.2019
comment
да. Сработало Спасибо. Ты спас мне день - person user007; 26.07.2019
comment
@yurzui Отличный ответ. Вы должны обновить его тем, что в вашем комментарии: статическая: истинная часть. - person BigJ; 01.11.2020