http://aurelia.io/hub.html#/doc/article/aurelia/framework/latest/app-configuration-and-startup/8
Have updated Aurelia docs with solution (scroll down a little).
Special thanks to Charleh for hint.
Aurelia has this nice feature calls enhance
, which can help you enhancing specific parts of your application with Aurelia functional.
But can we have multiple enhance statements on the same page? It seems problematical.
Example:
Task: enhance first component on the page, then get some data from the server and enhance second component on the page with server data as binding context
HTML
<!DOCTYPE html>
<html>
<head>
<title>Title</title>
</head>
<body>
<my-component1></my-component1>
<my-component2></my-component2>
</body>
</html>
JS
import { bootstrap } from 'aurelia-bootstrapper-webpack';
bootstrap(function(aurelia) {
aurelia.use
.standardConfiguration()
.globalResources("my-component1", "my-component2");
aurelia.start().then((app) => {
// Enhance first element
app.enhance(null, document.querySelector('my-component1'));
// Get some data from server and then enhance second element with binding context
getSomeDataFromServer().then((data) => {
app.enhance(data, document.querySelector('my-component2'));
});
});
});
Result:
In the result we will enhance first component, but when it's time for the second one, Aurelia will try to enhance first component one more time!
It happens because of aurelia-framework.js
_configureHost
method.
So basically when you start enhance
it starts this method with your element as an application host:
Aurelia.prototype.enhance = function enhance() {
var _this2 = this;
var bindingContext = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
var applicationHost = arguments.length <= 1 || arguments[1] === undefined ? null : arguments[1];
this._configureHost(applicationHost || _aureliaPal.DOM.querySelectorAll('body')[0]);
return new Promise(function (resolve) {
var engine = _this2.container.get(_aureliaTemplating.TemplatingEngine);
_this2.root = engine.enhance({ container: _this2.container, element: _this2.host, resources: _this2.resources, bindingContext: bindingContext });
_this2.root.attached();
_this2._onAureliaComposed();
resolve(_this2);
});
};
And inside the _configureHost
we can see this if statement which is just checking if our app instance is already host configured then do nothing.
Aurelia.prototype._configureHost = function _configureHost(applicationHost) {
if (this.hostConfigured) {
return;
}
...
Problem So the actual problem here is that any enhanced element automatically became an application host (root) and when you try to enhance another element with the same aurelia instance you will just end up enhancing the first element always.
Question Is this some way around for the cases when I want to enhance several elements on the page?
There's a clue here:
this.root = engine.enhance({container: this.container, element: this.host, resources: this.resources, bindingContext: bindingContext});
this.root.attached();
The aurelia.enhance
just wraps the TemplatingEngine
instance's .enhance
method.
You could just pull TemplatingEngine
from the container and call .enhance
on it passing the bindingContext
since aurelia.enhance
does just that (but adds the additional "host configure" step that you've already done via your first .enhance
call).
So that bit might look like:
import { Container } from 'aurelia-dependency-injection';
let engine = Container.instance.get(TemplatingEngine);
engine.enhance({ container: Container.instance, element: document.querySelect('my-component2'), resources: (you might need to inject these too), bindingContext: someContext });
(disclaimer: I didn't test the above so it may not be accurate - also you probably need to pass the resources object in - you can inject it or pull it from the container - I believe the type is just Resources
)
However - something to note: your my-component2
won't actually be a child of your host element my-component1
. I'm not sure if that will cause issues further down the line but it's just a thought.
I'm still curious as to why you'd want to bootstrap an Aurelia instance and then have it enhance multiple elements on the same page instead of just wrapping all that server response logic inside the component's viewmodel itself?
Maybe you can give a bit more context to the reason behind this?
My workaround for this issue for now (thanks to Charleh for the clue):
import { bootstrap } from 'aurelia-bootstrapper-webpack';
import {TemplatingEngine} from "aurelia-framework";
let enhanceNode = function (app, node, bindingContext = null) {
let engine = app.container.get(TemplatingEngine);
let component = engine.enhance({container: app.container, element: node, resources: app.resources, bindingContext: bindingContext});
component.attached();
}
bootstrap(function(aurelia) {
aurelia.use
.standardConfiguration()
.globalResources("my-component1", "my-component2")
aurelia.start().then((app) => {
enhanceNode(document.querySelector('my-component1'));
enhanceNode(document.querySelector('my-component2'));
});
});
That way you can skip host configuration for the app and can enhance as many custom elements as you want on the page.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With