Access to light DOM when using webcomponents.js (Shadow DOM polyfill) - polymer

I'm trying to access the light DOM when using the webcomponents.js polyfill but it does not seem to work. (works fine in native Shadow DOM/Chrome)
Here is a reduced test of what I’m trying to do:
sample: http://jsbin.com/wudakapujo/1/
code: http://jsbin.com/wudakapujo/1/edit
Any hints/pointers regarding how I could access the Light DOM data when using the Shadow DOM polyfill would be greatly appreciated
Thanks!

Try adding <content></content> to your template, or <content select="span"></content> to just get the span tag.
<template>
<h1>SHADOW DOM CONTENT</h1>
<content select="span"></content>
</template>

Did you try looking in
this.content.getDistributedNodes()
See
https://www.polymer-project.org/resources/faq.html#accessContentDOM

Related

How to share variables with siblings?

I'm very new to Polymer, so please don't hold back any information!
I have a basic webpage with a standard format, and I'm trying to figure out how I can expose the #nav component variable currentSelection with the #main component, which depends on the selection for switching out the correct template:
head
body
div#nav
div#main
div#footer
I understand the encapsulation aspect of Polymer, but I lack an understanding of the glue, eventing system, and different instantiation patterns for the dynamic HTML, especially since Polymer 0.5 is deprecated.
Does <template is="dom-bind"> actually render as if it weren't a <template>? I'm thinking to wrap the whole site in one, but I'm not sure that's a good idea.
Why not make your #nav and #main custom components? That way you could bind to currentSelection like so:
<my-nav current-selection="{{currentSelection}}"></my-nav>
<my-main current-selection="[[currentSelection]]"></my-main>
The dom-bind template is necessary to make bindings work between elements in the main document (i.e index.html), so you could either use dom-bind:
<template is="dom-bind">
<my-nav current-selection="{{currentSelection}}"></my-nav>
<my-main current-selection="[[currentSelection]]"></my-main>
<my-footer></my-footer>
</template>
Or you could put all of your elements in another custom component such as my-app in which the bindings will work:
index.html
<body>
<my-app></my-app>
</body>
my-app.html
<template>
<my-nav current-selection="{{currentSelection}}"></my-nav>
<my-main current-selection="[[currentSelection]]"></my-main>
<my-footer></my-footer>
</template>

Call Method of Child Web Component

I'm really having difficulty trying to figure out how to call a function of a nested Polymer web component.
Here's the markup:
<rise-playlist>
<rise-playlist-item duration="5">
<rise-distribution distribution='[{"id":"VGZUDDWYAZHY"}]'></rise-distribution>
</rise-playlist-item>
</rise-playlist>
The rise-distribution component has a canPlay function that I would like to call from inside of rise-playlist.
The dom-module definition of rise-playlist looks like this:
<dom-module id="rise-playlist">
<template>
<content id="items" select="rise-playlist-item"></content>
</template>
</dom-module>
I can successfully access the rise-distribution element like this:
var distribution = Polymer.dom(this.$.items[0]).querySelector("rise-distribution");
However, when I try to call distribution.canPlay(), it says that distribution.canPlay is not a function.
I've defined the dom-module of rise-playlist-item like this:
<dom-module id="rise-playlist-item">
<content id="dist" select="rise-distribution"></content>
</dom-module>
Not sure if I need that <content> tag, although neither works.
Any ideas?
Thx.
I know that there have been a while but I am sure this problems still occurs as it is being viewed number of times.
Probably there is a problem with your component definition. Let me explain.
This is the way you put your child component inside DOM:
<your-child-component></your-child-component>
And and this should be the definition of your component:
Polymer({
is: 'your-child-component',
apiMethod: function() {
//some stuff
}
});
If you by mistake or due copy-paste error mistype the is: 'your-child-component' part, so it will not reflect the <your-child-component> you will get confused becouse your:
this.$$('your-child-component').apiMethod();
will tell you that there is no method you are willing to call.
Polymer correctly identified and selected from DOM <your-child-component> but if you have different is property (like for example is: your_child_component>) it will not attach its API to dom element you selected.
I hope that it will help if anyone ever will encounter this problem.

Dynamically injecting a template in Polymer 1.0

I'm trying to inject and display a <template> the right way into a Polymer Webapp, but I have a few difficulties with it. (… or maybe I misunderstood the 1.0 Documentation?)
The documentation about manipulation the DOM says:
Polymer provides a custom API for manipulating DOM such that local DOM and light DOM trees are properly maintained. These methods and properties have the same signatures as their standard DOM equivalents, except that properties and methods that return a list of nodes return an Array, not a NodeList.
Note: All DOM manipulation must use this API, as opposed to DOM API directly on nodes.
So I guess I have to use Polymer.dom API everywhere to manipulate the DOM, which makes sense to me, because this way Polymer can stay in sync with the generated shady DOM. No DOM.appendChild(), instead Polymer.dom().appendChild(). And manipulating the shady DOM directly wouldn't be a great idea … or would it?
Imagine a simple page structure:
<body>
<template is="dom-bind" id="app">
<main>
<template is="dom-bind" id="content">
<p>Lorem ipsum dolor sit amet.</p>
</template>
</main>
</template>
</body>
And a second small snippet which I can import into the page.
<template id="snippet">
<p>Consectetur adipisici elit.</p>
</template>
This template should be replaced/referenced with the #content. So, let's start.
Importing the snippet is easy. I can fetch it and get the DOM Element of it.
Polymer.Base.importHref('/snippet', function(e) {
// on success: imported content is in e.target.import
var template = Polymer.dom(e.target.import).querySelector('#snippet');
// until here it works, `template` is the template from my snippet
...
Now I guess I have to append this to my template#app and change the ref of template#content to content… if changing the ref is still supported? And how am I supposed to do that? I get stuck every time, no matter how I approach this.
var app = Polymer.dom(this).querySelector('#app'); // Works, is template#app
var app = document.querySelector('#app'); // Same result
Polymer.dom(app).appendChild(template); // will append it, but outside of the document fragment
Polymer.dom(app.root).appendChild(template); // won't do anything
Polymer.dom(app).querySelector('template'); // undefined
Polymer.dom(app.root).querySelector('template'); // undefined
app.querySelector('template'); // undefined
I looked hours and days into this, trying to find a solution. It works with the standard DOM API, but I don't think that's the right way to do this. If somebody could solve my confusion, it would be really great.
EDIT: Or will Polymer.dom(this) do it's thing and I don't need to call Polymer.dom(app)? But again, I tried it and it won't work. Aaargh, it's just so confusing.
If I understood you correctly and you want to insert the template to local dom (inserting it somewhere else doesn't really make sense) then it's Polymer.dom(this.root).appendChild.
From https://www.polymer-project.org/1.0/docs/devguide/local-dom.html#dom-api: In order to insert/append into the local dom of a custom element, use this.root as the parent.

How to create an instance of Polymer element programmatically?

Please refer to this JSBin, basically I would like to create an instance of an element in its parent element scope. Wondering how should I do this?
If possible, is there a declarative way to do this?
Thanks.
PS. Please open the link in Chrome only.
There are several ways to instantiate and element.
Declarative:
<my-element>
JS:
document.createElement('my-element');
Constructor (if one is find):
new MyElement();
See http://www.html5rocks.com/en/tutorials/webcomponents/customelements/#instantiating
I believe you are looking for the constructor (see here) attribute.
You need to include it in your polymer element declaration.
<polymer-element name="p-paper"
attributes="content"
constructor="Paper"
noscript>
And then you can create instances of your element like this -
// How to create an instance of <p-paper> here?
var paper = new Paper();

Polymer document.querySelector not working as expected

Either I am doing something horribly wrong or Polymer just doesn't like me. See following:
<polymer-element name="menu-paper-ui" noscript>
<template>
<paper-dialog heading="Dialog" transition="paper-dialog-transition-bottom">
[ .. ]
</paper-dialog>
<paper-button label="Dialog Bottom" on-tap="{{toggleDialog}}"></paper-button>
</template>
<script>
Polymer('menu-paper-ui', {
toggleDialog : function() {
var dialog = document.querySelector('paper-dialog');
console.log(dialog); //returns null
dialog.toggle();
}
})
</script>
</polymer-element>
Now, I have my reasons to use querySelector. So, if someone can tell me whats going wrong that will be great!
This question is nearly identical to Using querySelector to find nested elements inside a Polymer template returns null.
The short answer is that elements in a polymer-element's template are put into the ShadowDOM of that element, are not not visible to the anything outside of that element. This is so that you can control styling more easily, and element IDs are scoped.
You can either give the dialog an id and use Polymer's automatic node finding, or use this.shadowRoot.querySelector('paper-dialog').
The Problem is that you can not access the shadow DOM inside a custom element with document.querySelector. See my answer to a similar question.