Context:
I am carrying out tests about web component composition in different contexts. Particularly I am trying to relate several web component by getting access to one of them from another one by a searching process within the DOM
/ Shadow DOM
of the involved components.
Problem:
Let's suppose we have a web component named x-foo
requiring to access another one x-randgen
. The latter component exposes business methods used by the former. In order to avoid a tightly coupled communication between both components I would like to use a discovery mechanism in x-foo
to access x-randgen
through a searching process across DOM
and Shadow DOM
models. In particular I identify two possible scenarios. Either both x-foo
and x-randgen
instantiated are in the global context (index.html) or they both appear within another template, say x-bar
. The problem is that the searching process should be implemented differently in each case. Following I show a pseudocode with my approach summarizing, in essence, my question. (The global example can be found here: http://jsbin.com/qokif/1/)
Polymer('x-foo', {
...
getRandGen: function () {
if (<<x-foo & x-randgen are in the global context>>)
return document.querySelector('x-randgen');
else if (<<x-foo & x-randgen are in a template>>)
return <<the x-randgen tag within the template>>;
}
});
Question:
I would appreciate if someone could reformulate the snippet above in proper terms according to the Polymer technology.
You could write your problem function like this:
getRandGen: function () {
var root = this;
while (root.parentNode) {
root = root.parentNode;
}
return root.querySelector('x-randgen');
}
http://jsbin.com/xufewi/1/edit
Other solutions can be made using monostate pattern (rare) or a proper controller (common).
The monostate idea is that a particular element expresses a conduit to a shared-state (i.e. the max
value). Wherever you need access to the shared-state, you simply create one of the accessor elements.
The controller idea is that the element bubbles an event requesting the randgen
utility. Some ancestor (the controller) handles the event and provides the resource. This is a type of dependency management that's great for design flexibility.
http://jsbin.com/tudow/1/edit
Two bugs in your jsbin. The first is that you want domReady
, not ready
because you call getRandGen()
inside, which queries the DOM. Even that is a bit brittle though because it depends on the x-randgen
element existing at the time that your x-foo
's domReady event fires (so it wouldn't work if x-randgen
is in a conditional template e.g.
The second issue is that document.querySelector('x-randgen')
won't find an <x-randgen>
inside of a ShadowDOM.
A bit of terminology clarification here. The "template context" and "global context" ideas aren't quite right. Polymer elements instantiate their <template>
s inside of their shadow roots, which establish a shadow dom. The shadow dom is an abstraction for isolating components, so that they're less likely to interfere with the rest of the page, and the page is less likely to interfere with them. It is possible to reach across the shadow dom boundary, but just be aware that you may be reaching into the implementation details of other components.
All that to say that if you don't care what x-randgen
you get a hold of, even if it's within some totally unrelated component, this should work: document.querySelector('x-randgen') || document.querySelector('body /deep/ x-randgen')
. JSBin: http://jsbin.com/goqikire/1/edit
Ideally though you'd have a better idea of where the x-randgen
will be relative to your x-foo
, or as I suggested above the component responsible for both the x-randgen
and the x-foo
can explicitly make them aware of each other.
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