balazska
balazska

Reputation: 971

Aurelia - custom element does not inherit binding context by default. Is it okay?

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

Answers (1)

Jeremy Danyow
Jeremy Danyow

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

Related Questions