Angular 2 中如何在组件内访问 ng-content?

53

如何从组件类本身访问组件的 "content"?

我想做这样的事情:

<upper>my text to transform to upper case</upper>

我该如何在我的组件中获取其内容或上层标签,就像我使用 @Input 来获取属性一样?

@Component({
    selector: 'upper',
    template: `<ng-content></ng-content>`
})
export class UpperComponent {
    @Input 
    content: String;
}

提示:我知道可以使用管道进行大写转换,这只是一个示例,我不想创建大写组件,只是想知道如何从组件类中访问组件内容。


你需要HTML字符串还是特定组件的引用? - Günter Zöchbauer
5个回答

60

如果您想获取插入内容中组件的引用,可以使用:

@Component({
    selector: 'upper',
    template: `<ng-content></ng-content>`
})
export class UpperComponent {
    @ContentChild(SomeComponent) content: SomeComponent;
}
如果您包装<ng-content>,则可以像这样访问传输的内容:
@Component({
    selector: 'upper',
    template: `
  <div #contentWrapper>
    <ng-content></ng-content>
  </div>`
})
export class UpperComponent {
    @ViewChild('contentWrapper') content: ElementRef;

    ngAfterViewInit() {
      console.debug(this.content.nativeElement);
    }
}

如果我使用包装器,那么我应该使用 @ViewChild 而不是 @ContentChild 来访问它? - Daniel Kobler
@Günter Zöchbauer 很好的想法!!! 它帮助我重构了Angular Material对话框。 - Samy Sammour

37

你需要利用@ContentChild装饰器来实现这个功能。

@Component({
  selector: 'upper',
  template: `<ng-content></ng-content>`
})
export class UpperComponent {
  @Input 
  content: String;

  @ContentChild(...)
  element: any;
}

编辑

我进一步调查了您的问题,由于您没有根内部DOM元素,因此在这里无法使用@ContentChild

您需要直接利用DOM。以下是可行的解决方案:

@Component({
  selector: 'upper',
  template: `<ng-content></ng-content>`
})
export class UpperComponent {
  constructor(private elt:ElementRef, private renderer:Renderer) {
  }

  ngAfterViewInit() {
    var textNode = this.elt.nativeElement.childNodes[0];
    var textInput = textNode.nodeValue;
    this.renderer.setText(textNode, textInput.toUpperCase());
  }
}

查看此 plunkr 以获取更多细节:https://plnkr.co/edit/KBxWOnyvLovboGWDGfat?p=preview


3
如果被转入的内容不是另一个组件,那怎么办?如果你只想要所有在 ng-content 中被转入的内容,该怎么办? - ykadaru

2

早上好,

我对这个话题进行了一些研究,因为在我的项目中发生了类似的情况。我发现有两种修饰符可以帮助您解决这个问题:ViewChildren和ContentChildren。根据我在网络上发现的,它们的区别主要在于ViewChildren访问组件内部,而ContentChildren访问DOM或组件本身。

要从ng-content访问上层元素,您必须更改上层元素,将其更改为以下内容:

<upper #upper>my text to transform to upper case</upper>

然后只需访问内部(在具有ng-content的组件中):

  @ViewChildren('upper') upper: QueryList<ElementRef>

同时,要访问组件整体(在含有 ng-content 的组件内):

  @ContentChildren('upper') upper: QueryList<ElementRef>

你从哪里获取了这些信息:https://netbasal.com/understanding-viewchildren-contentchildren-and-querylist-in-angular-896b0c689f6e

本文介绍了在Angular中使用ViewChild、ContentChild和QueryList的方法。这些工具可以帮助我们在组件中查找和访问子元素,包括直接子元素和嵌套子元素。通过使用这些工具,我们可以更方便地管理和操作DOM元素,提高代码的可读性和可维护性。

2

https://angular.io/api/core/ContentChildren

class SomeDir implements AfterContentInit {

  @ContentChildren(ChildDirective) contentChildren : QueryList<ChildDirective>;

  ngAfterContentInit() {
    // contentChildren is set
  }
}

请注意,如果您在ngAfterContentInit或更晚的事件中使用console.log(contentChildren),它才能正常工作。

非常奇怪,我即使使用forwardref和descendants:true,在AfterContentInit()中检查,它仍然返回一个空列表。 - K-Dawg

0

你也可以使用TemplateRef,这是最终为我工作的方法,因为我正在使用服务来初始化我的组件。

your-component.component.html

<!-- Modal Component & Content -->
<ng-template #modal>
  ... modal content here ...
</ng-template>

your-component.component.ts 文件中

@ViewChild('modal') modalContentRef!: TemplateRef<any>;
... pass your modalContentRef into your child ... 

... 对我来说,这个服务就像是中间人 - [未显示] ...

modal.component.html

<div class="modal-container">
    <!-- Content will be rendered here in the ng-container -->
    <ng-container *ngTemplateOutlet="modalContentRef">
    </ng-container>
</div>

modal.component.ts 文件中

@Input() modalContentRef: TemplateRef<any> | null = null;

这就是我用TemplateRef解决问题的方法,因为由于服务创建了模态框,所以无法使用ng-content

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接