Angular2 local components / template reuse

和自甴很熟 提交于 2019-12-07 00:50:06

问题


I'm writing some Angular2 templates that have repetitive portions with different containers. In this case, the view can change if things are grouped and if multi section mode is enabled. Please excuse the long example, but something like this:

<template [ngIf]="isCategoryGrouped">
    <div *ngFor="#categories of categories">
        <div>{{ categories.category.name }}</div>
        <div *ngFor="#thing of categories.things">
            <label *ngIf="isMultiSelectMode">
                <input type="checkbox" (change)="updateThingSelection(thing, $event)" />
                <img [src]="thing.image" /> {{ thing.name }}
            </label>
            <a href="javascript: void(0)" (click)="selectThing(thing)" *ngIf="! isMultiSelectMode">
                <img [src]="thing.image" /> {{ thing.name }}
            </a>
        </div>
    </div>
</template>
<template [ngIf]="! isCategoryGrouped">
    <div *ngFor="#thing of things">
        <label *ngIf="isMultiSelectMode">
            <input type="checkbox" (change)="updateThingSelection(thing, $event)" />
            <img [src]="thing.image" /> {{ thing.name }}
        </label>
        <a href="javascript: void(0)" (click)="selectThing(thing)" *ngIf="! isMultiSelectMode">
            <img [src]="thing.image" /> {{ thing.name }}
        </a>
    </div>
</template>

I'd really like to reuse portions of this without having to write a completely separate component and wire it all together, which would require a TypeScript file and a template. One method would be with local components, something like this:

<sub-component selector="thing-list" things="input">
    <div *ngFor="#thing of things">
        <label *ngIf="isMultiSelectMode">
            <input type="checkbox" (change)="updateThingSelection(thing, $event)"/>
            <img [src]="thing.image" /> {{ thing.name }}
        </label>
        <a href="javascript: void(0)" (click)="selectThing(thing)" *ngIf="! isMultiSelectMode">
            <img [src]="thing.image" /> {{ thing.name }}
        </a>
    </div>
</sub-component>

<template [ngIf]="isCategoryGrouped">
    <div *ngFor="#categories of categories">
        <div>{{ categories.category.name }}</div>
        <thing-list things="categories.things" />
    </div>
</template>
<thing-list [ngIf]="! isCategoryGrouped" things="things" />

I realize the above is a rough sketch and probably wouldn't work as is, but the apparent inability to reuse portions of the view like this is unfortunate. This sort of thing is quite simple in React, if I understand correctly.

I'm curious about elegant ways others have solved the reuse-of-portions-of-view without going so far as to write a new component (which our designers would then need to know about and style, etc...). Thanks.


回答1:


If your sections are identical in structure, just different in data, you could come up with a more generic model. Instead of referring to category and thing directly, map them into a generic object that you populate in a service before it gets to the view.

<div *ngFor="#item of items">
        ---
</div>

Here items would either be populated from things or categories.

You can then call it like so

<component [items]="fromThings"></component>
<component [items]="fromCategories"></component>

You are basically normalizing the view by not depending on the actual objects directly.




回答2:


You can also use *ngFor with [ngForTemplate] or the upcoming NgInsert (name will be changed) to make parts of your template reusable.




回答3:


You can now use <ng-template>

<ng-template #headerPanel>
    <header>
       This is my reusable header.
    </header>
</ng-template>

Then use like this:

  <ng-container *ngTemplateOutlet="headerPanel"></ng-container>

Official docs

Note: I'm not knowledgeable enough to explain difference between [ngTemplateOutlet] and *ngTemplateOutlet but if someone else wants to edit this answer or add another feel free.




回答4:


Call component recursively in template.

isList control which part to be used, default false.

thing.html

<template [ngIf]="isLlist">
    <div *ngFor="#thing of things">
        <label *ngIf="isMultiSelectMode">
            <input type="checkbox" (change)="updateThingSelection(thing, $event)"/>
            <img [src]="thing.image" /> {{ thing.name }}
        </label>
        <a href="javascript: void(0)" (click)="selectThing(thing)" *ngIf="! isMultiSelectMode">
            <img [src]="thing.image" /> {{ thing.name }}
        </a>
    </div>
</template>

<template [ngIf]="!isList">

    <template [ngIf]="isCategoryGrouped">
        <div *ngFor="#categories of categories">
            <div>{{ categories.category.name }}</div>
            <my-thing-component [isList]="true" [things]="categories.things"></my-thing-component>
        </div>
    </template>

    <templete [ngIf]="! isCategoryGrouped">
        <my-thing-component [isList]="true" [things]="things"></my-thing-component>
    </templete>

</template>

thing.component.ts

import {Component,Input} from '@angular/core';

@Component({
    selector: 'my-thing-component',
    templateUrl: 'thing.html' 
})
export class ThingComponent {
    @Input() isList = false;
    @Input() things;

    //Fill in the rest
}


来源:https://stackoverflow.com/questions/36612205/angular2-local-components-template-reuse

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!