Replaceable templates not working across multiple levels
Replaceable templates accross multiple levels as shown in the following sketch are not working. The replaceable template in tab.html gets replaced with empty content.
tab.html
<template>
<div class="title">Tab-Title</div>
<template replaceable part="tab1-content"></template>
</template>
tab-control.html
<template>
<tab>
<template replace-part="tab1-content">
<template replaceable part="tab1"></template>
</template>
</tab>
</template>
app.html
<template>
<tab-control>
<template replace-part="tab1">
<form>...</form>
</template>
</tab-control>
</template>
Neither works this:
tab.html
<template>
<div class="title">Tab-Title</div>
<template replaceable part="tab1-content"></template>
</template>
tab-control.html
<template>
<tab>
<template replaceable part="tab1"></template>
</tab>
</template>
app.html
<template>
<tab-control>
<template replace-part="tab1">
<template replace-part="tab1-content">
<form>...</form>
</template>
</template>
</tab-control>
</template>
At the moment replaceable parts are single level.
@StrahilKazlachev the first example is actually designed to be single level if the templates are replaced top-down.
By single level I meant direct. In the first example you are targeting from App in <tab>, through <tab-control>. This just isn't supported.
Also looking for this feature! https://discourse.aurelia.io/t/render-template-within-template-within-element/2221
I'm uncertain whether we can support this feature. Consider the following example:
a.html
<template>
<div replaceable part="part-1">
<div replaceable part="part-1a">Part 1a</div>
<div replaceable part="part-1b">Part 1b</div>
</div>
<div replaceable part="part-2">
<div replaceable part="part-2a">Part 2a</div>
<div replaceable part="part-2b">Part 2b</div>
</div>
</template>
What we are seeing here is 2 levels deep replaceable templates, with part="part-1" and part="part-2"
Now suppose use this custom element in the following way:
app.html
<template>
<a>
<template replace-part="part-1">...</template>
</a>
</template>
The moment we replace part="part-1" in a.html with <template replace-part="part-1">...</template> from app.html, we lose all information about the replaced destination, because the parent <template replaceable part="part-1"> is lost, thus all the children of it:
<div replaceable part="part-1"> <!-- if this is replaced -->
<!-- all the following are gone, no trace of what to replace inside -->
<div replaceable part="part-1a">Part 1a</div>
<div replaceable part="part-1b">Part 1b</div>
</div>
This is like assigning a new object to a property, there is no way to know what old properties there were for reconciliation.
In case that we know all to-be-replaced parts of the destination, and all provided parts to replace them, what should be done with non-replaceable parts?
a.html
<template>
<div replaceable part="part-1">
<!-- what should be done for this -->
<h1>Not replaceable 1</h1>
<div replaceable part="part-1a">Part 1a</div>
<div replaceable part="part-1b">Part 1b</div>
</div>
<div replaceable part="part-2">
<!-- what should be done for this -->
<h1>Not replaceable 2</h1>
<div replaceable part="part-2a">Part 2a</div>
<div replaceable part="part-2b">Part 2b</div>
</div>
</template>
For the above template, maybe part-1, part-1a, part-1b, part-2, part-2a, part-2b can all be made to work, what can be done with the two <h1/> elements once we want to replace both part-x and part-xa, part-xb?
thoughts ? @Mobe91 @StrahilKazlachev @JoshMcCullough @fkleuver @EisenbergEffect
@bigopon If you add a (failing or passing) test for it in the vNext repo I can debug and see what might be needed to make it work, or establish whether it's possible at all (and give solid reasoning why not, if not).
@bigopon If you have chosen to replace part-1, in your example, you have specifically chosen to "not care about and replace" the entire contents, including the other replaceable parts. IMO that is completely fine, and the correct result. If you intended to replace only the inner parts, you could have done that as well. This allows for the most flexibility.
Additionally, you added the <h1> which is "not replaceable" however, it is completely replaceable since it resides within a replaceable template. So it never was actually "not replaceable" in your example. The two <h1> elements should be replaced if the user is providing a replacement for the containing replaceable part.
@fkleuver @JoshMcCullough I would imagine something like this
foo.html
<template>
<div replaceable part="part-1">
<h1>Not replaceable 1</h1>
<div replaceable part="part-1a">Part 1a</div>
<div replaceable part="part-1b">Part 1b</div>
</div>
<div replaceable part="part-2">
<h1>Not replaceable 2</h1>
<div replaceable part="part-2a">Part 2a</div>
<div replaceable part="part-2b">Part 2b</div>
</div>
</template>
Case 1: I want to replace part-1 (or part-2, simplified to only part-1):
app.html
<a>
<template replace-part="part-1">
... i don't care what is in side part-1 in the destination. this is gonna be the content
</template>
</a>
Case 2: I want to replace part-1/part-1a:
<foo>
<template replace-part="part-1/part-1a">
... i don't care what is inside part-1 in the destination.
... i don't care what is inside part-1a in the destination
... i don't care what is inside part-1b in the destination
... This is gonna be the content of part-1a in part-1
</template>
</foo>
Case 2: I want to replace part-1/part-1a and part-1/part-1b:
<foo>
<template replace-part="part-1/part-1a">
... i don't care what is inside part-1 in the destination.
... i don't care what is inside part-1a in the destination
... i don't care what is inside part-1b in the destination
... This is gonna be the content of part-1a in part-1
</template>
<template replace-part="part-1/part-1b">
... i don't care what is inside part-1 in the destination.
... i don't care what is inside part-1a in the destination
... i don't care what is inside part-1b in the destination
... This is gonna be the content of part-1b in part-1
</template>
</foo>
Additionally, you added the
<h1>which is "not replaceable" however, it is completely replaceable since it resides within a replaceable template. So it never was actually "not replaceable" in your example. The two<h1>elements should be replaced if the user is providing a replacement for the containing replaceable part.
@JoshMcCullough Yes, it was there to demonstrate that we can't conditionally pick what to be replaced, when we provide both parent-replaceable and child-replaceable.
So I wouldn't think you'd use replace-part="part-1/part-1a", but rather simply replace-part="part-1a.
I think all of your examples are correct in your latest comment. And it's up to the user to decide if they are replacing the outer or inner parts in this case. Aurelia could potentially raise an error/warning if a user tried to do this )using your example) ...
<!-- example to cause an error -->
<foo>
<template replace-part="part-1">
...new content for part 1
</template>
<template replace-part="part-1a">
...new content for part 1a
</template>
</foo>
ERROR: Cannot replace both parts "part-1" and "part-1a", one is nested within the other.
@bigopon With regard to your example I would expect this to behave like @JoshMcCullough described.
But I don't see how your example relates to my original one because you don't really have nested templates but rather just nested replacement points within a single template..
While I understand that multi-level replacement is not supported right now I feel that it should be possible to support it by just processing the replacement points top-to-bottom and by reprocessing each intermediate replacement result. When I apply such an algorithm to version 1 of my original example, I end up with the correct end result:
- Process
app.html - Instantiate the
tab-controltemplate which yields a logical intermediate view of
<template>
<tab-control>
<tab>
<template replace-part="tab1-content">
<template replaceable part="tab1"></template>
</template>
</tab>
</tab-control>
</template>
- Apply replacements for part
tab1defined inapp.htmlwhich yields
<template>
<tab-control>
<tab>
<template replace-part="tab1-content">
<form>...</form>
</template>
</tab>
</tab-control>
</template>
- Now we need to instantiate and replace again - instantiate
tabwith result
<template>
<tab-control>
<tab>
<div class="title">Tab-Title</div>
<template replaceable part="tab1-content"></template>
</tab>
</tab-control>
</template>
- Apply replacements for part
tab1-contentdefined in the intermediate result of step 3 which yields the expected end result
<template>
<tab-control>
<tab>
<div class="title">Tab-Title</div>
<form>...</form>
</tab>
</tab-control>
</template>