Passing multiple parameters to a structural direct

2019-08-24 08:05发布

问题:

I want to pass in multiple params to a structural directive, but what was working in Angular2 doesn't seem to work in Angular5 anymore

Here's my blah component which contains an accordion:

@Component(
    selector: "blah-scene",
    // language=HTML
    template: """
        <div>
            Blah Test Page
            <accordion>
                <div *accordionItem>
                    item1
                </div>
                <div *accordionItem>
                    item2
                </div>
            </accordion>
        </div>
    """,
    directives: const [
        Accordion,
        AccordionItemDirective
    ]
)
class BlahScene implements AfterContentInit, OnDestroy {
...
}

Accordion is defined as follow:

@Component(
    selector: 'accordion',
    // language=HTML
    template: """
    <ul class="accordion"
        [id]="id"
        [attr.data-slide-speed]="slideSpeed"
        [attr.data-multi-expand]="multiExpand"
        [attr.data-allow-all-closed]="allowAllClosed">
        <ng-content></ng-content>
    </ul>
    """,
    styles: const ["""
        .overflow-hidden {
            overflow: hidden;
        }
    """
    ],
)
class Accordion implements AfterContentInit, OnDestroy, OnChanges {

    @ContentChildren(AccordionItemDirective)
    List<AccordionItemDirective> items;

    ...

}

I'm expecting those two divs marked with *accordionItem to be rendered as accordion items which it does.

AccordionItem:

@Component(
    selector: "li",
    template: """
    <a
        *ngIf="visible"
        class="accordion-title"
        [attr.did]="title"
        (click)='onClickTitle(title)'>
        {{title?.toUpperCase()}}
        <img
            src="{{expandButtonPath()}}"
            class="expand-navbar"
            [class.disabled]='!allowClose && active'>
    </a>

    <div
        class="accordion-content no-padding"
        [class.hidden]='!active'
        [class.overflow-hidden]="hideScrollBars"
        [class.overflow-auto]="!hideScrollBars"
        data-tab-content>
        <template
            [ngIf]="renderAccordionItemContent && visible"
            [ngTemplateOutlet]="template">
        </template>
    </div>
    """,
    styles: const ["""
        ...
    """],
    directives: const [
        NgTemplateOutlet,
        coreDirectives
    ]
)
class AccordionItem implements AfterContentInit, OnDestroy {

    TemplateRef template;

   ...

}

And then the AccordionItemDirective which creates the AccordionItem and adds it to the DOM:

@Directive(selector: '[accordionItem]')
class AccordionItemDirective implements AfterContentInit {

    final ViewContainerRef vcRef;
    final TemplateRef template;

    AccordionItemDirective(this.vcRef, this.template);

    AccordionItem accordionItem;

    ComponentRef componentRef;
    String accordionId;

    @override
    ngAfterContentInit() async {

        template.createEmbeddedView();

        final ComponentRef<AccordionItem> component =
            vcRef.createComponent(accordionItemTemplate.AccordionItemNgFactory);
        accordionItem = component.instance;

        accordionItem
            ..template = template
            ..active = _accordionItemActive
            ..title = accordionItemTitle
            ..accordionId = accordionId;

    }

...

Up to here, it works fine, the AccordionItems are created and inserted as li inside the accordion

I now want to pass in params so that i can set the title and id and some other properties of that accordionItem On the accordionItemDirective, i add some inputs:

@Input("accordionItemId") String accordionItemId = "";
bool _accordionItemActive = false;

@Input("accordionItemTitle")
String accordionItemTitle = "Missing Title";

Expecting this to work:

<accordion>
    <div *accordionItem [accordionItemTitle]="'Title1'">
        item1
    </div>
    <div *accordionItem>
        item2
    </div>
</accordion>

i get this error:

lib/component/test/blah-scene.dart: ParseErrorLevel.FATAL: Can't bind to 'accordionItemTitle' since it isn't a known native property or known directive. Please fix typo or add to directives list.

Trying it without the square brackets:

<accordion>
    <div *accordionItem accordionItemTitle="'Title1'">
        item1
    </div>
    <div *accordionItem>
        item2
    </div>
</accordion>

it compiles, but nothing happens.

I try to intercept the input, but my log.fines aren't being printed at all

@Input("accordionItemTitle")
set accordionItemTitle(String title) {
    log.fine(title);
}
String get accordionItemTitle {
    return "Missing Title [...]";
}

In Angular2, this used to work:

        <accordion>
            <div *accordionItem="accordionItemTitle: 'Title1' ">
                item1
            </div>
            <div *accordionItem>
                item2
            </div>
        </accordion>

but that too is complaining:

ParseErrorLevel.FATAL: Can't bind to 'accordionItemAccordionItemTitle' since it isn't an input of any bound directive. Please check that the spelling is correct, and that the intended directive is included in the host component's list of directives

What is the correct way to pass in parameters to a structural directive ?

回答1:

Looks like this works for all inputs other than accordionItemId:

        <accordion>
            <div *accordionItem="title: 'Title1'; active: true ">
                item1
            </div>
            <div *accordionItem="title: 'Title2'; active: true ">
                item2
            </div>
        </accordion>