Inconsistency in passing parameters between soy templates
Hey guys,
I made a test of a use case in metal-soy, as I was going through some strange situations with Soy templates.
Test
Theoretically in the test below was to expect FooBar in the final result, but the return is FooFooBar. Ignoring the fact that I'm just passing name as a reference to .content.
comp = new NestedDataComponent({
label: 'Foo',
name: 'Bar'
});
assert.strictEqual('FooBar', comp.element.textContent);
{namespace NestedData}
{template .render}
{@param? label: string}
{@param name: string}
<div>
{if $label}{$label}{/if}
{call .content}
{param name: $name /}
{/call}
</div>
{/template}
{template .content}
{@param? label: string}
{@param name: string}
{if $label}
{$label}
{/if}
{if $name}
{$name}
{/if}
{/template}
Analysis
Observing the generated soy.js.
ie_open('div');
if (label) {
itext((goog.asserts.assert((label) != null), label));
}
$content(opt_data, null, opt_ijData);
ie_close('div');
We can observe the part where the function is called. Passing all parameters.
$content(opt_data, null, opt_ijData);
Behaving like a data = "all".
if we go further in the tests by modifying the parameter name in the .render template. From name to bar and run the test again, it returns FooBar as expected.
{@param bar: string}
<div>
{if $label}{$label}{/if}
{call .content}
{param name: $bar /}
{/call}
</div>
In generated file.
$content({name: bar}, null, opt_ijData);
It is observed that when the parameter names are the same between the templates, soy returns the function with the variable of objects with all the parameters or is opt_data.
For a kind of "masquerading" this behavior of the soy, would be to use in this case, in the call the data ="$name", that it would pass only this parameter.
Problems
It may seem like a small behavior but this can cause big problems in larger applications and can not keep track of names in different components, this already becomes bad, since we want to maintain a consistency of API between components like the case of Clay components.
It can be seen in Clay components in a ClayLabel use case. It depends on ClayLink.
This component consists of 2 templates, .render and .content. When I call .content I pass all the parameters that it expects.
LINE 25
./packages/clay-label/src/ClayLabel.soy
{call .content}
{param _handleCloseButtonClick: $_handleCloseButtonClick /}
{param closeable: $closeable /}
{param href: $href /}
{param label: $label /}
{param spritemap: $spritemap /}
{/call}
{template .content}
{@param? _handleCloseButtonClick: any}
{@param? closeable: bool}
{@param? href: string}
{@param? label: string}
{@param? spritemap: string}
Looking at the generated soy.js, we have the section where .content is called in .render, it passes all the parameters that ClayLabel receives.
$content(opt_data, null, opt_ijData);
In the .content template I call ClayLink by passing the href and label parameters.
LINE 46
./packages/clay-label/src/ClayLabel.soy
{if $href}
{call ClayLink.render}
{param href: $href /}
{param label: $label /}
{/call}
{else}
{$label}
{/if}
ClayLabel gets style and its default value is secondary.
LINE 14
./packages/clay-label/src/ClayLabel.soy
{template .render}
...
{@param? style: string}
...
In the generated soy.js file, it can be seen that it passes all the parameters that the .content template receives, ie all the parameters that ClayLabel is receiving.
$templateAlias1(opt_data, null, opt_ijData);
ClayLink receives the style parameter to render in the class attribute thelink - {$ style}.
LINE 28
./packages/clay-link/src/ClayLink.soy
{let $classes kind="text"}
{if $buttonStyle}
btn btn-{$buttonStyle}
{elseif $style}
link-{$style}
{/if}
{if $elementClasses}
{sp}{$elementClasses}
{/if}
{/let}
The result of this is when we call ClayLink in ClayLabel, it renders with the link-secondary class. As you can see in the jest snapshot.
LINE 21
./packages/clay-label/src/__tests__/__snapshots__/ClayLabel.js.snap
<span class="label label-secondary">
<a class="link-secondary" href="#1">Foo</a>
</span>
This is worrisome it can cause several problems in the application and developers may be slow to track this problem.
Thanks for reading this far 😅.
Thanks for reporting @matuzalemsteles,
Unfortunately this is probably an issue in closure-template's SoyToIncrementalDomSrcCompiler that is implemented by metal-tools-soy.
I doubt this is something we'll be able to easily fix ourselves.
They aren't always responsive to github issues, but can you try reporting this on https://github.com/google/closure-templates?
Hey @Robert-Frampton , I imagined this, I thought to put it here, in case someone goes through this same problem know how to dribble this and avoid bigger problems. I'll report it there so it might be fixed. Thanks!