I have an instance using Select2 that allows me to render a template for the results. Right now we are writing our HTML in strings and I’d like to put it in a HTML Template and require it somehow. If I can preserve binding behaviors that would be awesome. Does anyone have any ideas?
Can you provide some pseudo code examples?
In the view-model we pass in options to a select2 instance:
const select2Options = {
templateResult: item => { return `<div><span>${item}</span></div>` }
}
Where I’d like to require the template instead of using raw strings:
import Select2Template from './select2-template.html'
const select2Options = {
templateResult: Select2Template
}
With the template declaring the binding values:
<template bindable="item">
<div>
<span>${item}</span>
</div>
</template>
Even if I have to construct the template with a callback function, that would be fine because it would allow me to create more manageable code.
I think it’s similar to what the aurelia dynamic html component can do, or at least I hope so. Can you have a look at that plugin?
I looked at that component but, that is just a custom element that takes raw strings and renders them. My goal is to get away from raw strings and require a template.
I needed to do this today and after carefully studying the way that Select2 behaves and how Aurelia v1’s templating engine works I came up with a solution:
import $ from 'jquery';
import { autoinject, bindable, Container, TemplatingEngine, ViewSlot } from 'aurelia-framework';
...
select2Options.templateResult = (item) => {
const randomId = `option-${Math.random().toString(36)}`; // create a randomized ID so that we have a reference to the container
const element = document.createElement('div');
this.templatingEngine.compose({
container: this.container,
view: PLATFORM.moduleName("./select2-template.html"),
bindingContext: item,
viewResources: null,
viewSlot: new ViewSlot(element, true)
}).then(() => {
// `compose` works asynchronously and the process of rendering continues after this callback (for instance inflating child components). Thus, we append the element to the container
document.getElementById(randomId).appendChild(element);
});
return $(`<div id="${randomId}"></div>`); // this will be inflated by the callback
};
The main struggle I ran into is that Select2 requires the templateResult
to return synchronously while Aurelia’s templating engine works asynchronously. I tried loading the template’s viewFactory
asynchronously when the page loads and using it to create new views and bind synchronously to return inflated HTML, but this doesn’t work on child components so the template only worked one layer deep.
Hope this helps anyone else who ends up having the same issue!