How to interpolate a string and variable in a function call

Silverstripe Version: 5.0

Question:

I’m trying to dynamically output some form fields. The call in the form template:

$Up.Fields.dataFieldByName(type$ID) or
$Up.Fields.dataFieldByName(type{$ID}) or
$Up.Fields.dataFieldByName({type$ID})

Doesn’t work. Nothing is output. Quotes make no difference.

Hard code test:
$Up.Fields.dataFieldByName(type1)

Does work. Checkboxes are output.

$ID has a value. For example:

type$ID

Does output type1 in the form.

If I (unhelpfully) rename the form fields to just the ID then this works:

$Up.Fields.dataFieldByName($ID)

So it seems the function call can take a variable.

What’s the trick to interpolate the string and var?

The docs say:

$Foo("param"), $Foo('param'), and $Foo(param) will all pass 'param' as a string. It is recommended that you always use quotes when passing a string for clarity

So type$ID is passed as that literal string.

I got something working but I’m hoping there’s a better way…

Currently:

Form template call is: $Up.Fields.dataFieldByName($Up.ThePage.getSomeValue($ID))

Form creation in controller:

$form->setFormMethod('GET')
    # bunch of settings here
    ->customise([
        # bunch of stuff here
        'ThePage' => $this
    ]);

In the controller:

public function getSomeValue($id)
{
    return 'type['.$id.']';
}

That works. Gotta be a better way…?

There is currently no way to pass variables into functions from a template. I’m honestly surprised that example works, but it’s great that it does!
Generally though, for something like this, you’d want to handle the logic in your controller, and just use the result in your template.

I have edited your post slightly to remove an offensive word - please try to avoid language that might offend others. :slight_smile:

There is currently no way to pass variables into functions from a template. I’m honestly surprised that example works

Seems there is then? If variable subs work is it worth looking at interpolation?

Generally though, for something like this, you’d want to handle the logic in your controller, and just use the result in your template.

Please explain further.
The logic of field creation is in a controller. The template is just pushing out dynamic fields in a loop. I have a set of type fields I need to split across different parents that are in accordions.

For more context, more of the template is:

        <% loop $Classification1Subs %>
        <div class="filter-group-accoridion">
            <div class="d-flex w-100 align-items-center justify-content-between py-2 accordion-trigger <% if $SearchFilters.Sub1 == $ID %>open<% end_if %>">
                <div class="display-5 fw-500">$Title</div>
                <div class="svg-chevron ms-3"><% include SVG_chevron %></div>
            </div>
            <div class="accordion-content <% if $Up.SearchFilters.Sub1 == $ID %>d-block<% end_if %>">
                <div class="pb-3">
                    <div class="row">
                        $Up.Fields.dataFieldByName($Up.ThePage.getTheTypeName($ID))
                    </div>
                </div>
            </div>
        </div>
        <% end_loop %>

What could I do in the controller that would let me use just the result? This is what you’d want to see in a template.