Maxim Krabov
Maxim Krabov

Reputation: 715

Get template from a ng-content's child

I'm trying to implement a select component with Angular 5. It consists of select component itself and option component. It should be used this way:

<app-select placeholder="Select smth">
  <app-option *ngFor="let option of options" [value]="option">
    <img src="option.iconLocation"> {{ option.name }}
  </app-option>
</app-select>

If the value is not set, the user sees the placeholder, otherwise the user should see the exact content of the option he/she has selected, e.g. in that case image and text. So, how in SelectComponent can I access and render user specified template for the selected option?

The problem is not that I can't set the value with @Output(). It's the easy part. I want to render the value the same way the user of my SelectComponent specified in <app-option/>. An option should be able to contain anything inside (even another component, say CardComponent), and after the user has select a value, I want to show in the SelectComponent everything he/she saw in the option.

In SelectComponent's template I have something like

<div [ngSwitch]="isEmpty" (click)="pp.toggle()">
    <button *ngSwitchCase="true">
        {{ placeholder }}
    </button>
    <button *ngSwitchDefault>
        THIS SHOULD TURN INTO 
        <img src="option.iconLocation"> {{ option.name }} 
        OR ANYTHING ELSE USER SPECIFIED IN THE OPTION COMPONENT
    </button>
</div>
<popup #pp>
    <ng-content>HERE GOES THE USER'S TEMPLATE</ng-content>
</popup>

see an example. How do I get this <strong>{{ index }}</strong> {{ option.name }} part and render inside the button?

Upvotes: 0

Views: 138

Answers (1)

Maxime
Maxime

Reputation: 2234

You can use @Output decorator with EventEmitter to emit the value to top-level components (use it in your OptionComponent).

It will emit the new value when it changes. So you can subscribe it in any top-level components.

For example with your code:

<app-select placeholder="Select smth">
  <app-option *ngFor="let option of options" 
              [value]="option" 
              (onOptionChanged)="onOptionChangedMethod($event)">
    <img src="option.iconLocation"> {{ option.name }}
  </app-option>
</app-select>

onOptionChangedMethod(...) could be located in your SelectComponent or anywhere else.


EDIT:

I forked your example, I guess this is a good start: https://stackblitz.com/edit/angular-sfqvqp

Is that what you're looking for? I used @ViewChild to get the ElementRef of the transcluded ng-content that app-option uses.

Then, the emitted event now gives an object with the value, and the full ElementRef in order to inject it into SelectComponent that subscribes to this event.

N.B.: I don't know if it works well with components directly passed to app-option (it should), but I suggest you to take a look at "angular 2 access ng-content within component".

Upvotes: 1

Related Questions