如何正确 "wrap" 包含 <template> 标签的 Angular 2 组件?

How to properly "wrap" an Angular 2 component that contains <template> tags?

我正在尝试用我自己的组件包装一个组件,在这种情况下是一个 primeNG PickList,以便我能够向它添加一个 NgModel 属性。我正在关注 this guide as my reference.

因此,primeNG 选择列表允许用户select 和重新排序列表中的项目。

<p-pickList [source]="list1" [target]="list2">
    <template let-car>
        <div class="ui-helper-clearfix">
            <img src="showcase/resources/demo/images/car/{{car.brand}}.gif" style="display:inline-block;margin:2px 0 2px 2px"/>
            <div style="font-size:14px;float:right;margin:15px 5px 0 0">{{car.brand}} - {{car.year}} - {{car.color}}</div>
        </div>
    </template>
</p-pickList>

所以我希望能够将上面的内容包装在我自己的组件中

我试过自己做这个。我的方法是将原始组件的 @Input@Output@ContentChild 值放入我的自定义组件中。本质上它只是 redefining the original variables of the component and proxying it through。所以它看起来像这样:

import {
    Component, OnInit, Input, forwardRef, Output, EventEmitter,
    ContentChild, TemplateRef
} from '@angular/core';
import {
    ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR,
    NG_VALIDATORS
} from '@angular/forms';

@Component({
    selector: 'form-primeng-picklist',
    template: `
    <p-pickList [source]="source"
        [target]="target" [responsive]="responsive" [showSourceControls]="showSourceControls" 
        [showTargetControls]="showTargetControls" (onMoveToTarget)="onMoveToTarget"
        (onMovetoSource)="onMovetoSource" [sourceStyle]="sourceStyle" [targetStyle]="targetStyle">
        <template [pTemplateWrapper]="itemTemplate" ></template>
    </p-pickList>
    `,
    providers: [
        {
            provide: NG_VALUE_ACCESSOR,
            useExisting: forwardRef(() => PickListFormComponent), multi: true
        },
        {
            provide: NG_VALIDATORS,
            useExisting: forwardRef(() => PickListFormComponent), multi: true
        }
    ],
})
export class PickListFormComponent implements ControlValueAccessor {

    @Input() source: any[];
    @Input() target: any[];
    @Input() sourceHeader: string;
    @Input() targetHeader: string;
    @Input() responsive: boolean;
    @Input() style: any;
    @Input() styleClass: string;
    @Input() sourceStyle: any;
    @Input() targetStyle: any;
    @Input() showSourceControls: boolean = true;
    @Input() showTargetControls: boolean = true;
    @Output() onMovetoSource: EventEmitter<any> = new EventEmitter();
    @Output() onMoveToTarget: EventEmitter<any> = new EventEmitter();
    @ContentChild(TemplateRef) itemTemplate: TemplateRef<any>;

    propagateChange: any = () => { };
    validateFn: any = () => { };

    constructor() { }

    /**
     * Write a new value to the element.
     */
    writeValue(value: any): void {
        if (value) {
            console.log('VALUE IS = ' + JSON.stringify(value));
            this.target = value;
        }
    }
    /**
     * Set the function to be called when the control receives a change event.
     */
    registerOnChange(fn: any): void {
        this.propagateChange = fn;
    }
    /**
     * Set the function to be called when the control receives a touch event.
     */
    registerOnTouched(fn: any): void {

    }

    validate(c: FormControl) {
        return this.validateFn(c);
    }
}

示例用法(失败)

<form-primeng-picklist
    [source]="myList" [target]="artifactorySelectedList" [responsive]="true" [showSourceControls]="false"
    [showTargetControls]="false" (onMoveToTarget)="addChecksums($event)" (onMovetoSource)="removeChecksums($event)"
    [sourceStyle]="{'height':'300px'}" [targetStyle]="{'height':'300px'}"
    [(ngModel)]="testPickList" name="testPickList">
            <template let-artifact>
            <div class="ui-grid" style="border-bottom:1px solid #D5D5D5;">
                <div class="ui-grid-row">
                    <div class="ui-grid-col-1" style="text-align:center">
                        <span><i class="fa fa-archive fa-3x" aria-hidden="true"></i></span>
                    </div>
                    <div class="ui-grid-col-11">
                        <span><strong>Name:</strong> {{artifact.artifact}}</span>
                        <span><strong>Revision:</strong> {{artifact.revision}}</span>
                        <strong>Organisation:</strong> {{artifact.organisation}}
                        <strong>Branch:</strong> {{artifact.branch}}
                    </div>
                </div>
            </div>
        </template>
</form-primeng-picklist>

因此,当我在我的 html 中传递任何 @Input@Output 值时,这会起作用。 当我尝试 'pass through' 带有内容 <template> 标签时它不起作用,我正在努力弄清楚如何做到这一点。

所以一般的问题是 如何正确包装允许您使用 <template> 标签的自定义组件? (没有渲染)

也许这个解决方案对你有用

选择列表-form.component.ts

替换

<template [pTemplateWrapper]="itemTemplate" ></template>

<template let-item>
  <template [pTemplateWrapper]="itemTemplate" [item]="item"></template>
</template>

因此您的模板应如下所示:

<p-pickList ...>
  <template let-item>
    <template [pTemplateWrapper]="itemTemplate" [item]="item"></template>
  </template>
</p-pickList>