Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a template as content, which is in turn passed to another component

Tags:

angular

Using Angular 4.0.3

I'm creating a component my-component, which has an input of value, and is passed an ng-template as content. Example usage would be:

<my-component [value]="value">
  <ng-template let-value>
    <p><strong>Value rendered in user supplied template: {{value}}</strong></p>
  </ng-template>
</my-component>

It's the job of my-component to figure out whether the user is on a mobile device or not. If they are, we want to render a my-native-component. Otherwise, it'll render a my-custom-component.

My code for my-component so far is:

@Component({
  selector: 'my-component',
  template: `
  <my-custom-component *ngIf="useCustom" [value]="value">
    <ng-template [ngTemplateOutlet]="templateVariable"></ng-template>
  </my-custom-component>
  
  <my-native-component *ngIf="!useCustom" [value]="value">
    <ng-template [ngTemplateOutlet]="templateVariable"></ng-template>
  </my-native-component>
  `
})
class MyComponent {
  @ContentChild(TemplateRef)
  private templateVariable: TemplateRef;
  
  @Input()
  private value: string;
  
  @Input()
  private useCustom: bool = false;
}

To keep the example simple, there's no checking of whether the user is on mobile or not here. Instead, a useCustom input has been added.

The template passed as the content is referenced as templateVariable, and is passed as a new template via ng-template and ngTemplateOutlet.

In this example, my-native-component and my-custom-component are identical, except for their names. They have the same value input as my-component, and also receive a template as their content. This is what my-native-component looks like:

@Component({
  selector: 'my-native-component',
  template: `
  <h3>my-native-component (value: {{value}})</h3>
  <p>Rendered template:</p>
  <ng-template [ngTemplateOutlet]="templateVariable" [ngOutletContext]="{$implicit: value}"></ng-template>
  <p>Done</p>
  `
})
class MyNativeComponent {
  @ContentChild(TemplateRef)
  private templateVariable: TemplateRef;
  
  @Input()
  private value: string;
}

I can't figure out why the passed template is never rendered when the app runs. Perhaps I have a misunderstaning on how ng-template works?

The full runnable code is available on Plunker - https://embed.plnkr.co/fiDECy5gamOLvjPo2uhN/

What am I doing wrong?

like image 605
Josh Avatar asked May 05 '17 15:05

Josh


People also ask

How do I pass a ng template?

In order to have a template rendered in that container, we use the *ngTemplateOutlet to pass a reference to an existing template, such as the one we created earlier. We use @Input to pass a TemplateRef to our component.

How do I access the template reference variable in component?

Usually, the reference variable can only be accessed inside the template. However, you can use ViewChild decorator to reference it inside your component. @ViewChild('firstNameInput') nameInputRef: ElementRef; After that, you can use this.

What is the difference between Ng content ng container and ng template?

ng-container serves as a container for elements which can also accept structural directives but is not rendered to the DOM, while ng-template allows you to create template content that is not rendered until you specifically (conditionally or directly) add it to the DOM.

How does Angular component pass custom content?

The first step to passing data into an Angular component is to create a custom property to bind to. This is done via “input” binding to pass data from one component to another (typically parent to child). This custom input binding is created via the @Input() decorator!


1 Answers

Idea is you need to pass the template down to the hierarchy tree. See plunker here: https://plnkr.co/edit/hwww2QXDh9Je5Bc9ld3O?p=preview

In my-native-component:

<ng-container *ngTemplateOutlet="template; context: {$implicit: value}"></ng-container>

In my-component:

<my-native-component *ngIf="!useCustom" [value]="value" [template]="template">
  <ng-template [ngTemplateOutlet]="templateVariable"></ng-template>
</my-native-component>

In my-app:

<my-component [value]="value" [useCustom]="false" [template]="test"><!-- toggle useCustom true/false -->
  <ng-template #test let-value>
    <p><strong>Value rendered in user supplied template: {{value}}</strong></p>
  </ng-template>
</my-component>

Put this in components to allow the transfer of template.

@Input()
private template: TemplateRef;

Must keep this in mind. <ng-template> must need a container to output its content. It's hidden in HTML by default. https://angular.io/docs/ts/latest/guide/structural-directives.html#!#template

like image 160
wannadream Avatar answered Oct 10 '22 03:10

wannadream