In hyperHTML Components when calling the render function with a definition as follows
get defaultState() {
return {
myPerfectText: "perfect!",
isWorking: false
};
}
render() {
return this.html`
<my-fancy-dialog>
<template>
<span>${this.state.myPerfectText}</span>
${this.state.isWorking
? "it's working"
: "never will print this"}
</template>
</my-fancy-dialog>
`;
}
throws an Uncaught TypeError: this[(i - 1)] is not a function error
A common use case would be rendering Polymer elements that use a slotted template tag. (e.g. Dialog, DomRepeat, DomIf, ...)
a codepen or similar showing the error may be easier for us to help you
I hope the following pen demonstrates what is not working for me.
https://codepen.io/CoffeeDreamLabs/pen/XBXOpx
I haven't seen the "slotted template" pattern before but would it not make more sense to use the custom element approach outlined in docs?
Yes normally I would do that. But when using Polymer 2 (migrated to P3) components, where JS and HTML interoperability wasn't that great, usually people would use the templates declarative in HTML.
e.g.
iron-list -> https://www.webcomponents.org/element/PolymerElements/iron-list
vaadin-dialog -> https://www.webcomponents.org/element/vaadin/vaadin-dialog
...
i dont see a problem, the template is rendered
<div id="second"><template>
<h1>Hello, world!</h1>
<h2>Not used template rendered.</h2>
</template><!--_hyper: 630588406;--></div>
Yes that template is rendered. I added this component to show that the template is rendered when no values are inserted inside the template tag. But the template in the third (id) div is never rendered (where the value "someString" should be inserted).
that may be because templates need to be stamped for them to be real elements, hyper may be trying to use dom functions and they don't exist... curious why you need templates with hyper?
I don't think that the dom functions should be a problem. As in these (https://www.html5rocks.com/en/tutorials/webcomponents/template/) examples is shown things like textContent in childNodes can be set like on every other element.
And I don't desire to make new components with hyper implementing this behaviour, but I want to be able to use components already created by other folks that implemented such behaviour.
In iron-list and other components for example the template tag is expected as childNode.
/**
* Templetizes the user template.
*/
_ensureTemplatized: function() {
if (this.ctor) {
return;
}
this._userTemplate = this.queryEffectiveChildren('template');
if (!this._userTemplate) {
console.warn('iron-list requires a template to be provided in light-dom');
}
From https://github.com/PolymerElements/iron-list/blob/master/iron-list.html.
fwiw render.js#L41 does not return paths for values nested within <template/> (it does for values around the <template/>), not sure why or if this is intended, will keep digging.
Edit: makes some sense now, Updates.js#L90 call to childNodes() will (correctly) output the template node but not it's children (due to nested fragment) - I feel like this is working as expected and clearly see the reason for wanting nested template tags to _just work_ but I'm not sure about the correct approach to resolving this (eg, have a special handle for the template node Updates.js#L94).
As a patch you could add this:
if(child.nodeName === 'TEMPLATE') {
find(child.content, paths, parts)
continue
}
after Updates.js#L93 and it _should_ run find() again on the document fragments nodes and resolve your issue - but I'm not sure how this impacts the rest of hyper, maybe a check for nested fragment instead of template tag would be safer.
Edit: just checked on laptop and no luck
Just checked what was this bug about and ... well, it's complicated.
To start with, with hyperHTML it makes no sense to have <template> elements since everything the <template> can do, hyperHTML does it as well without it, and even better, keeping compatibility down to IE9 (or even IE8 with the no.js patch).
The second bit is that in browsers with HTMLTemplateElement support, their content cannot be mapped through childNodes as easily as just an index, you need to branch browsers with .content support from others.
And while above issue can have work arounds, the moment you would update the target node of the template through another render call, whatever thing the rest of the code used won't be affected, for the simple reason that template content is cloned, so my shortcuts to update nodes will update nodes of the template, but not elements previously created from such template.
// once you have this, calls to the render
// won't possibly update/change cloned values
var fragment = document.importNode(
this.querySelector('template').content,
true
);
However, if you understand why template inside hyperHTML is not really a good idea, but you want to use a template element regardless, you can create a work around such as:
render() {
return this.html`
<my-fancy-dialog>
${this.template`
<span>${this.state.myPerfectText}</span>
${this.state.isWorking
? "it's working"
: "it's not working"}
`}
</my-fancy-dialog>`;
}
get template() {
if (!this._template) {
const template = document.creteElement('template');
const render = hyperHTML.bind(template.content || template);
this._template = (chunks, ...values) => {
render(chunks, ...values);
return template;
};
}
return this._template;
}
where you bypass the <template> tag all together, but you still use the template magic.
You can see a working live example in this code pen, which is just a fork of yours.
I am closing this as I don't think it'd be beneficial for anyone to have a footgun included in this library, it'd cause more troubles than it solves, and the work around is, as you can see, deadly simple.
Thanks for rising this question though, I hope you'll migrate soon from template tags because with hyperHTML you really never need those (ironically, template is used behind the scene, but that's the only valid use case I can think of).
Here to answer other questions, if any.
Most helpful comment
Just checked what was this bug about and ... well, it's complicated.
To start with, with
hyperHTMLit makes no sense to have<template>elements since everything the<template>can do, hyperHTML does it as well without it, and even better, keeping compatibility down to IE9 (or even IE8 with theno.jspatch).The second bit is that in browsers with
HTMLTemplateElementsupport, their content cannot be mapped through childNodes as easily as just an index, you need to branch browsers with.contentsupport from others.And while above issue can have work arounds, the moment you would update the target node of the template through another render call, whatever thing the rest of the code used won't be affected, for the simple reason that template content is cloned, so my shortcuts to update nodes will update nodes of the template, but not elements previously created from such template.
However, if you understand why template inside hyperHTML is not really a good idea, but you want to use a template element regardless, you can create a work around such as:
where you bypass the
<template>tag all together, but you still use thetemplatemagic.You can see a working live example in this code pen, which is just a fork of yours.
I am closing this as I don't think it'd be beneficial for anyone to have a footgun included in this library, it'd cause more troubles than it solves, and the work around is, as you can see, deadly simple.
Thanks for rising this question though, I hope you'll migrate soon from
templatetags because withhyperHTMLyou really never need those (ironically, template is used behind the scene, but that's the only valid use case I can think of).Here to answer other questions, if any.