Custom element's Binding Context - what is it exactly, how to access parent VM

主宰稳场 提交于 2019-11-30 20:20:39

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>

You would expect both <div> elements to have the same binding context right? Both element's foo property should be bound to the same model's bar property. The same holds true in this scenario:

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

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

If I understand the question correctly, you would like an elegant way to give the inner MyElem class instance a reference to the outer MyElem class instance. Luckily, you're using Aurelia so there is a very nice 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's one caveat however...

The Aurelia dependency-injection container's default behavior is to create an instance of the requested item if an instance is not found in the container. This means that @inject(Parent.of(MyElem)) is not quite what we want. In situations where there is no parent MyElem instance the container will create one for us instead of returning null. Normally we'd use @inject(Optional.of(MyElem)) to tell the container to give us the instance, only when it exists in the container. I don't know of a way to combine Parent.of and Optional.of. I'll create an issue in the aurelia dependency-injection repository so we can get this feature added.

In the meantime, 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 would 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's a working example. Check the console for log messages showing the result:

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!