1

I am trying to wrap a component, a primeNG PickList in this case, with my own component so that I am able to add an NgModel attribute to it. I am following this guide as my reference.

So a primeNG picklist allows a user to select and reorder items from a list.

<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>

So I want to be able to wrap the above in my own component

I tried doing this on my own. My approach was to take the original component's @Input, @Output and @ContentChild values into my custom component. In essence it is just redefining the original variables of the component and proxying it through. So it looks like this:

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);
    }
}

Example usage (that fails)

<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>

So this works when I passthrough any @Input and @Output values in my html. It does not work when I try to 'pass through' the <template> tag with content and I am struggling to figure out how to do this.

So the general question is how do you properly wrap a custom component which allows you to use <template> tags? (nothing renders)

1 Answer 1

1

Perhaps this solution will work for you

pick-list-form.component.ts

Replace

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

with

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

So your template should look like:

<p-pickList ...>
  <template let-item>
    <template [pTemplateWrapper]="itemTemplate" [item]="item"></template>
  </template>
</p-pickList>
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.