Skip to content

fix: support filters for f-children in declarative templates #7631

Description

@radium-v

🐛 Bug Report

f-children in FAST declarative templates does not parse the filter elements(...) syntax, even though the runtime children() directive supports filter through ChildrenDirectiveOptions / NodeBehaviorOptions. This creates an inconsistency between runtime FAST directives and declarative <f-template> syntax.

💻 Repro or Code Sample

Given a declarative template using f-children with an element filter:

<f-template name="test-element">
    <template>
        <ul f-children="{childItems filter elements()}">
            <li>One</li>
            Text node
            <li>Two</li>
        </ul>
    </template>
</f-template>

or with a selector:

<f-template name="test-element">
    <template>
        <ul f-children="{childItems filter elements(li)}">
            <li>One</li>
            <span>Ignored</span>
            <li>Two</li>
        </ul>
    </template>
</f-template>

The declarative parser currently handles filter elements(...) only for f-slotted:

case "slotted": {
    const parts = propName.trim().split(" filter ");
    const slottedOption = {
        property: parts[0],
    };

    if (parts[1]) {
        if (parts[1].startsWith("elements(")) {
            let params = parts[1].replace("elements(", "");
            params = params.substring(0, params.lastIndexOf(")"));
            Object.assign(slottedOption, {
                filter: elements(params || undefined),
            });
        }
    }

    externalValues.push(slotted(slottedOption));
    break;
}

but f-children passes the full string directly as the property name:

case "children": {
    externalValues.push(children(propName));
    break;
}

🤔 Expected Behavior

f-children should support the same filter elements(...) declarative syntax as f-slotted, because the runtime children() directive supports filters through ChildrenDirectiveOptions, which extends NodeBehaviorOptions.

Expected examples:

<ul f-children="{childItems filter elements()}"></ul>
<ul f-children="{childItems filter elements(li)}"></ul>

These should resolve to runtime directive options equivalent to:

children({
    property: "childItems",
    filter: elements(),
});

and:

children({
    property: "childItems",
    filter: elements("li"),
});

😯 Current Behavior

f-children="{childItems filter elements()}" is parsed as:

children("childItems filter elements()")

That means the source property becomes the literal string "childItems filter elements()" instead of "childItems", and no filter is applied.

This differs from f-slotted, where the same filter elements(...) syntax is parsed into an options object with property and filter.

💁 Possible Solution

Share the existing filter elements(...) parsing path between f-slotted and f-children in TemplateParser.resolveAttributeDirective().

For example, parse the directive value once into:

{
    property: string;
    filter?: ElementsFilter;
}

Then use that parsed option for both supported directives:

case "children": {
    externalValues.push(children(parsedOption));
    break;
}

case "slotted": {
    externalValues.push(slotted(parsedOption));
    break;
}

Add declarative fixture coverage for:

<ul f-children="{childItems filter elements()}"></ul>
<ul f-children="{childItems filter elements(li)}"></ul>

and update declarative syntax docs if this is intended to be supported.

🔦 Context

This came up while generating declarative <f-template> HTML from compiled FAST templates. Runtime children({ property, filter: elements(...) }) is representable in FAST Element, but there is no equivalent declarative syntax path because f-children does not parse filters.

Related issue found during search:

🌍 Your Environment

  • OS & Device: macOS
  • Browser: Not browser-specific; affects FAST Element declarative template parsing
  • Version: @microsoft/fast-element 3.0.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions