Custom Element Binding Context - What is Exactly How to Access the Parent Virtual Machine

I could not find the answer in the docs, so I ask here. What is the binding context passed to the bind method of the custom item? Is it just equal to the currently active ViewModel router? At least this is what I have discovered so far.

Why is this not the parent element (in terms of the DOM) of the VM?

with this code

 @customElement("myelem") @inlineView("<template><content></content></template>") export class MyElem{ bind(ctx){ console.log(ctx); } } // welcome.html <myelem> <h3>inside myelem</h3> <myelem> <h4>inside inside ... </h4> </myelem> </myelem> 

console output is only the current welcome model printed twice.

I expect this to be Welcome for the first (external) myelem , but myelem for the second (internal) myelem ...

Please explain why I am not right here, and how the internal user element can know about this actual context (by which I mean external in the above case), without using ugly hacks, such as creating a secret property in a "shared" context (the one which is actually transmitted to both of them)

+7
javascript aurelia
source share
1 answer

In terms of data binding, both elements are bound to the same binding context. Consider this example:

 <div foo.bind="bar"> <div foo.bind="bar"></div> </div> 

Would you expect both <div> elements to have the same binding context? And the element foo property must be bound to the same bar property. The same is true in this scenario:

 <myelem foo.bind="bar"> <myelem foo.bind="bar"></myelem> </myelem> 

Both instances of <myelem> bound to the same binding / model context.

If I understood the question correctly, you would like the internal instance of the MyElem class to refer to the external instance of the MyElem class. Fortunately, you are using Aurelia, so there is a very good way to do this ... declare it as a dependency using the inject decorator:

 import {inject, Parent} from 'aurelia-dependency-injection'; import {customElement} from 'aurelia-framework'; @customElement("myelem") @inject(Parent.of(MyElem)) export class MyElem { constructor(parent) { this.parent = parent; } ... } 

There is, however, a warning ...

By default, the default Aurelia injection container creates an instance of the requested item if the instance is not found in the container. This means that @inject(Parent.of(MyElem)) not exactly what we want. In situations where there is no parent instance of MyElem, the container will create one for us, and not return null. Usually we used @inject(Optional.of(MyElem)) to tell the container to provide us with an instance only if it exists in the container. I do not know how to combine Parent.of and Optional.of. I will create a problem in the dependency repository of the aurelia installation so that we can add this function.

At the same time, we can easily create our own resolver that combines the behavior of Parent.of and Optional.of:

 import {resolver} from 'aurelia-dependency-injection'; @resolver() export class OptionalParent { constructor(key) { this.key = key; } get(container) { if (container.parent && container.parent.hasResolver(this.key, false)) { return container.parent.get(this.key) } return null; } static of(key) { return new OptionalParent(key); } } 

So, the new version of our MyElem class will look like this:

 import {inject} from 'aurelia-dependency-injection'; import {customElement} from 'aurelia-framework'; import {OptionalParent} from './optional-parent'; @customElement("myelem") @inject(OptionalParent.of(MyElem)) export class MyElem { constructor(parent) { this.parent = parent; } ... } 

Here is a working example. Check the console for log messages showing the result:

https://gist.run/?id=1a84e0a466fb928aa075

+14
source share

All Articles