如何在组件B中渲染组件A的一部分

How to render a part of Component A in Component B

我有一个组件 AB

<div class="A">
    <div class="A1"></div>
    <div class="A2"></div>
</div>

<div class="B">
    <!--want to display <div class="A1"></div> here-->
</div>

组件 B 不包含组件 A 或绕过

<componentA></componentA>
<componentB></componentB>

我尝试将 <div class="A1"></div> 包装到 ng-template 中,然后在 componentB 中查询,但它始终是 undefined:

@ViewChild('templ') templ: TemplateRef<any>;

然后我意识到@ViewChild是查询子组件,那你怎么查询和渲染<ng-template>它不是子组件?

渲染组件 A 的模板作为组件 B

的内容
<ComponentB>
   <ComponentA></ComponentA>
</ComponentB>

componentB 渲染的内部模板 'content'(在本例中为 ComponentA 的模板)

ComponentB.component.html

<ng-content> </ng-content>

要访问 ComponentB 中呈现的 ComponentA,请使用 ContentChild

@ContentChild(ComponentA) footer: componentA;

您可以在父组件中创建公共 ng-template 并将其 templateRef 传递给组件 Input 绑定中的子组件。稍后内部组件将填充该模板的模板绑定。

这意味着在两个组件中添加 @Input a1: TemplateRef<any>; 并在组件 A 和 B 的父组件(基本上它们具有相同的父组件)的父组件中放在 ng-template 下方。

<ng-template #a1>
    <div class="A1">
       {{item.Description}}
    </div>
</ng-tmeplate>

组件 A 模板

<div class="A">
    <ng-container 
       *ngTemplateOutlet="a1;context:{item: valueFromComponentA}">
    </ng-container>
    <div class="A2"></div>
</div>

组件 B 模板

<div class="B">
    <ng-container 
       *ngTemplateOutlet="a1;context:{item: valueFromComponentB}">
    </ng-container>
</div>

看看 Alex Rickabaugh 的 awesome sideNav sample,它演示的正是您所需要的。

基于此,您需要在 ComponentA 中定义一个 ng-container。然后你需要用自定义指令标记你的 ComponentB 部分,并且有一个连接 ComponentAComponentB:

的服务
<div class="A1"><div>
<div class="A2" *leftNav >
  <h3>Content</h3>
</div>

指令:

@Directive({
  selector: '[leftNav]',
})
export class LeftNavDirective implements OnInit {
  constructor(private leftNav: LeftNav, private ref: TemplateRef<any>) {}

  ngOnInit(): void {
    this.leftNav.setContents(this.ref);
  }
}

服务:

@Injectable()
export class LeftNav {
  private _state = new BehaviorSubject<TemplateRef<any>|null>(null);
  readonly contents = this._state.asObservable();

  setContents(ref: TemplateRef<any>): void {
    this._state.next(ref);
  }

  clearContents(): void {
    this._state.next(null);
  }
}

最后,在您的 ComponentB 中,您必须在 ngAfterViewInit 上订阅您的 <div class="A1"> ... <div> 内容:

ngAfterViewInit(): void {
    this
      .leftNav
      .contents
      .subscribe(ref => {
        if (this._current !== null) {
          this._current.destroy();
          this._current = null;
        }
        if (ref === null) {
          return;
        }
        this._current = this.vcr.createEmbeddedView(ref);
    });
  }

P.S 有关于该主题的 video and slides