How to Access Member Functions in Polymer Elements

David Voyles
Share

This article is part of a web dev tech series from Microsoft. Thank you for supporting the partners who make SitePoint possible.

image 1- polymer

I’m working on a silly Polymer project right now, which parses a Pokémon database and returns a picture of a Pokémon, then speaks the creature’s name over your speakers. Here’s the source code for my project.

It’s my first time using Polymer, and I’m certainly getting snagged in a few spots. Most recently, it was trying to return member functions of a Polymer object that I created. Took me forever to figure this out, so I wanted to share it with you in this tutorial.

Sidenote: you can also search for my more detailed write-up on Web Components here.

The Wrong Way

I have a Web Component which looks like this:

<x -radial-buttons id="radial-button-template"></x>

If I try to access it by its ID…

var  temp = document.querySelector("#radial-button-template");
// returns <x -radial-buttons id="radial-button-template"></x>

I cannot access any of the functions inside it. They return undefined. So if I tried this:

var  temp = document.querySelector("#radial-button-template");
temp.getFirstElement  // returns undefined

Why Is This Happening?

This is due to the Shadow DOM’s encapsulation. It is both a gift and a curse. In this case, I am accessing the element, and not the shadowRoot, which will expose the public methods attached to the Shadow DOM object.

In the next step, you’ll see how I can access the member functions in my custom element, as well as how I can return nodes that lie even deeper in my web component.

Rob Dobson of Google’s Polymer team explains this well in this blog post. Eric Bidleman goes into even more detail in his advanced Shadow DOM article. I strongly suggest taking the time to read these over to better understand how this version of the DOM works.

One Way of Doing It

var btn = document.querySelector("x-radial-buttons");

Notice that I’m not using the hash symbol (#) to access the element, as though it were an ID. Instead, you need to simply refer to the name of the polymer-element itself:

document.querySelector("x-radial-buttons");

so now I can write:

var temp = document.querySelector("x-radial-buttons");
// ALSO returns <x-radial-buttons id="radial-button-template"></x-radial-buttons>

Now I can access all of the members like this:

var temp = document.querySelector("x-radial-buttons");
temp.getFirstElement
// returns <paper-radio-button label="English-US" id="paper_radio_btn_en-US" on-click="{{ changeAccentUS }}" role="radio" tabindex="0" aria-checked="false" aria-label="English-US"></paper-radio-button>

Therefore, I suggest not assigning an ID to your polymer-element at all. As Rob made clear in the comments below, you can query for a custom element however you want (via ID, class, attr, or element name) and get the same thing. Here’s his example: http://jsbin.com/qikaya/2/edit

Another way of doing it…

You can also grab the ID of a polymer element and access the member functions.

This is done by using a ‘polymer-ready’ event. As the docs describe it:

Polymer parses element definitions and handles their upgrade asynchronously. If you prematurely fetch the element from the DOM before it has a chance to upgrade, you’ll be working with a plain HTML element, instead of your custom element.

And this is exactly the issue I was running into earlier. I was trying to grab functions within my polymer-element before Polymer had a chance to upgrade it. Here’s an example:

<head>
  <link rel="import" href="path/to/x-foo.html">
</head>
<body>
  <x-foo></x-foo>
  <script>
    window.addEventListener('polymer-ready', function(e) {
      var xFoo = document.querySelector('x-foo');
      xFoo.barProperty = 'baz';
    });
  </script>
</body>

In conclusion, as long as you wrap the functions you are trying to call in the polymer-ready event, you should be good to go, and can call functions from your polymer-element.

How I Use It

(function (PokémonApp) {

// Grab inputs and button for speech-to-text
var form                 = document.querySelector('#player-form'),
    input                = document.querySelector('#player-input'),
    playerElement        = document.querySelector('#player-element'),
    xPokémon             = document.querySelector('#x-Pokémon'),
    btnChangeAccent      = document.querySelector('#btn-change-accent'),
    radialButtonTemplate = document.querySelector("#radial-button-template"),
  	playerAccent     = playerElement.getAttribute("accent");

// Take text from input & set it as the text that the speaker will say.
// Set the name of the Pokémon, which angular will then grab from the Pokémon DB 
input.addEventListener('input', function (e) {
	playerElement.setAttribute('text', input.value);
	xPokémon.name = input.value;
});


// Say the text when button is pressed
form.addEventListener('submit', function (e) {
	e.preventDefault();
	playerElement.speak();
	var btn = document.querySelector("x-radial-buttons");
	btn.getFirstElement();
});
<header>
<h1>article header h1</h1>
<p>This web app takes advantage of Web Components and Polymer to enable new HTML features in the browser.</p>
<p>
	In this particular case, we are using <a href="https://github.com/passy/x-Pokémon">
	the x-Pokémon web component </a> to pull the images from a database, as well as the 
	<a href="http://zenorocha.github.io/voice-elements/">voice-elements web component</a> to speak the name of the Pokémon we entered.							
</p>
<h2>Change the accent</h2>
<x-radial-buttons id="radial-button-template"></x-radial-buttons>
</header>

More JavaScript Learning

It might surprise you a bit, but Microsoft has a bunch of free learning on many open source JavaScript topics and we’re on a mission to create a lot more with Microsoft Edge coming.

Here’s our team’s broader learning series on HTML, CSS, and JS:

This article is part of a web dev tech series from Microsoft. We’re excited to share Microsoft Edge and the new EdgeHTML rendering engine with you. Get free virtual machines or test remotely on your Mac, iOS, Android, or Windows device at http://dev.modern.ie/