Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 TemplateRef Selector

In my datatable project, developers have the ability to declare templates in the table declaration to be used for the header cell and the body cell.

<datatable>
    <datatable-column name="Name">
        <template let-column="column">
            Header: {{column.name}}
        </template>
        <template let-value="value">
            Hi: <strong>{{value}}</strong>
        </template>
    </datatable-column>
    <datatable-column name="Age">
        <datatable-body-template let-value="value">
            I'm: <strong>{{value}}</strong> old
        </datatable-body-template>
    </datatable-column>
</datatable>

in the above example, the first template is the header cell template and the second one is the body cell template and the order matters. If you only declare one template, it will only do body cell template. You can see how this is being done currently here.

I do currently allow you to pass TemplateRefs via a Input to the column directive but that approach is ok but as an API consumer, the declarative templates inside the component definition is a cleaner approach.

Its also worth noting, that its not possible to do naming via something like #body and #header since you can have multiple columns making the names not unique.

This DSL is not very intuitive because its not very explicit which is which and it depends on order. ng-content allows you to put in a selector attribute, I was wondering what the best way to accomplish something like that with templates would be? So something like:

<datatable>
    <datatable-column name="Name">
        <datatable-header-template let-column="column">
            Header: {{column.name}}
        </datatable-header-template>
        <datatable-body-template let-value="value">
            Hi: <strong>{{value}}</strong>
        </datatable-body-template>
    </datatable-column>
</datatable>

I was digging around trying to see if its possible to override the TemplateRef but I'm not sure thats even a good idea.

So with all that said... my question, how can i accomplish named selector template refs?

like image 283
amcdnl Avatar asked Mar 11 '23 15:03

amcdnl


1 Answers

You can pass the templates to inputs

<template #header let-column="column">
    Header: {{column.name}}
</template>

<template #body let-value="value">
    Hi: <strong>{{value}}</strong>
</template>

<datatable>
    <datatable-column name="Name" [header]="header" [column]="body"></datatable-column>
</datatable>

update

It is also possible to add template variables and query by these

<datatable>
  <template let-column="column" #header>
    header1
  </template>
  <template let-value="value" #column>
    column1
  </template>

  <template let-value="value" #column>
    column2
  </template>

  @ContentChildren('header', {read: TemplateRef}) headerTemplates:QueryList<TemplateRef>;
  @ContentChildren('column', {read: TemplateRef}) columnTemplates:QueryList<TemplateRef>;

or use directives. This approach allows to pass additional information

@Directive({
  selector: '[header]';
})
class HeaderTemplate {
  constructor(private template:TemplateRef) {};

  @Input() header:String;
}

@Directive({
  selector: '[column]';
})
class ColumnTemplate {
  constructor(private template:TemplateRef) {};

  @Input() column:String;
}
<datatable>
  <template let-column="column" header="1">
    header1
  </template>
  <template let-value="value" column="1">
    column1
  </template>

  <template let-value="value" column="2">
    column2
  </template>

</datatable>
@ContentChildren(HeaderTemplate) headerTemplates:QueryList<HeaderTemplate>;
@ContentChildren(ColumnTemplate) columnTemplates:QueryList<ColumnTemplate>;

the properties template and header / column of headerTemplate / columnTemplate allow you to access the template and a passed value (can have additional @Inputs() but one that matches the selector is easiest to use).

Plunker example

like image 146
Günter Zöchbauer Avatar answered Mar 29 '23 23:03

Günter Zöchbauer