Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extensible template parts #810

Open
annevk opened this issue May 2, 2019 · 1 comment
Open

Extensible template parts #810

annevk opened this issue May 2, 2019 · 1 comment

Comments

@annevk
Copy link
Collaborator

annevk commented May 2, 2019

During the F2F @JanMiksovsky and @justinfagnani brought up some use cases for being able to create your own parts, that the browser would still be responsible for to clone. E.g., having a way to deal with JavaScript properties.

It'd be interesting to know the exact use cases and requirements around this. What kind of information does such a part need to carry that the browser would be responsible to clone? Can we avoid cloning requiring executing JavaScript? Etc.

(Not saying we need this feature for v0 by the way, but it's good to know where folks want to take it as it might influence the design.)

@JanMiksovsky
Copy link

Sorry for the delay in replying to this…

The basic issue is that most components need some way to reliably reference elements (parts) in their shadow tree to manipulate their contents, apply styles, or wire up event handlers.

All of the Elix components have those needs, but since you asked for specific examples, here’s a representative one. The CalendarMonth component is made up of subelements that render different parts of the calendar: the month/year, the column headers for the week days, and an CalendarDays element that can show the actual grid of dates:

<calendar-month>
  <calendar-month-year-header id=“monthYearHeader"></calendar-month-year-header>
  <calendar-day-names-header id=“dayNamesHeader”></calendar-day-names-header>
  <calendar-days id=“daysGrid”></calendar-days>
</calendar-month>

If you set the date property on the outer CalendarMonth, one of the things it will do in response is pass that date to the inner CalendarDays date grid. So somewhere in the definition for CalendarMonth there’s code that effectively does:

// The date has changed, pass it to the shadow element showing the grid of dates.
this.daysGrid.date = this.date;

The issue lies in the above reference to the subelement, this.daysGrid. What’s the best way for a component to create and hold onto such references? There are currently two basic strategies:

  1. Always dynamically look up the shadow element in question, e.g., via this.shadowRoot.getElementById. This is what we do in Elix. –or–
  2. Compute a static map/dictionary of the interesting shadow elements after the template has been cloned. It’s my understand that that is what Google’s Polymer library did to create a node map, in which this.$.foo pointed to a shadow element with ID “foo". This requires a post-clone shadow tree walk via something like this.shadowRoot.querySelectorAll(‘[id]’). I think lit-html does something similar, although instead of using IDs, it appears to maintain a simple array. That array maps one-to-one between the ${...} template literal placeholders and the shadow nodes produced for those placeholders.

When template instantiation was proposed, the Polymer/lit-html team and I observed it would be useful to provide a cloneWithParts template primitive that let someone clone a template and get references to the cloned parts. The developer could imperatively create a list of parts that referenced nodes in a template. (That might entail a tree walk of the template — but the walk is only being done once for the template, not once per component instance.) After invoking cloneWithParts, the parts would now reference the nodes in the cloned shadow tree.

Given this, I think the answer to the question about what information would the part need to carry that the browser would clone is: the part would essentially be the AttributeTemplatePart or NodeTemplatePart from Apple’s proposal — i.e., just the information to effectively address the attribute portion or node, respectively, after the template has been cloned. The main difference from Apple’s proposal is that it’d be possible to construct a set of parts imperatively without requiring, among other things, the use of any particular mustache syntax.

@justinfagnani The above is based on my recollection of the conversation at the April 2019 F2F. If I’ve gotten anything wrong or omitted important details, please chime in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants