Reputation: 971
Each view-model gets two parameters in its bind()
method: bindingContext
and overrideContext
. The first one describes the current scope, the second the outer scope(s): the parent, the parent's parent, etc. This looks something like that:
overrideContext: {
bindingContext: {...}, //current level
parentOverrideContext: {
bindingContext: {...}, //parent's binding context
parentOverrideContext: {...} //and so on
}
}
This lets the view-model access methods and fields from parents' scopes as well.
If a custom element is created, it receives the expected bindingContext
and overrideContext
parameters in bind()
. But when it passes them to its child(ren), it is not in the expected format, but:
overrideContext: {
bindingContext: {...}, //current level, this is ok
parentOverrideContext: null,
__parentOverrideContext: {...}, //this is the real
}
Note that the original parentOverrideContext
has been moved to __parentOverrideContext
. In this way, the templating engine won't be able to resolve anything from the parents' scope. Let's have a concrete example:
page.html:
<template>
Hello, user!
<custom-element-1>
<custom-element-2>
<button click.trigger="myHandler()">Call myHandler</button>
</custom-element-2>
</custom-element-1>
</template>
page.js:
export class MyPage {
myHandler() {
//do something here
}
}
Here I'd like to call a method defined on the parent's parent (MyPage
) from a button in the innermost view-model (<custom-element-2>
), but due to the different format, the templating cannot find the parent and cannot resolve the method.
After some debugging, I've realized that there is a flag (instruction.inheritBindingContext
), which determines if the parent should be included or not. The flag is true
for router-views by default, but false
for custom elements. The question: Am I not understanding it correctly and is this the desired behaviour? Or is it a bug?
Anyway, if someone interested, the flag can be easily changed:
import {customElement, processContent} from 'aurelia-templating';
@processContent((compiler, resources, node, instruction) => {
instruction.inheritBindingContext = true;
return true/false;
})
@customElement('custom-element-1')
export class CustomElement1 {}
Upvotes: 2
Views: 606
Reputation: 26406
This is intentional. It prevents developers from building custom elements that are not portable because they rely on specific properties of the outer scope.
https://www.danyow.net/aurelia-custom-element-vs-compose/
Upvotes: 2