Get reference to dynamically created element - javascript

In Polymer you can use this.$.idOfElement to get an element with an id of idOfElement.
How can I get a dynamically created element by its id if I only have the value of id in a variable?
Note: The element I want to reach out to is created dynamically like this:
<template is="dom-repeat" items="[[days]]" as="o">
<my-custom-element id$="[[getId(o)]]"></my-custom-element>
</template>
I have plenty of these <my-custom-element> in my app and need to get hold of them one by one.
Edit:
None of these work, they all return undefined or null:
this.$[id]
this.$$(id)
this.root.querySelector('my-custom-element#' + id)
Polymer.dom(e.currentTarget).querySelector('my-custom-element#' + id)

You cannot use the automatic node finder (this.$.x) for dynamic nodes. You have to use this.$$(selector), which acts like document.querySelector() constrained to children of the current element.
This why you must use this.$$('#' + nodeId) as suggested by Alan.
Polymer({
is: 'my-elem',
makeRed: function() {
this.$$('#li2').style.color = 'red';
}
});
<!DOCTYPE html>
<html>
<head>
<base href="https://polygit.org/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link href="polymer/polymer.html" rel="import"/>
</head>
<body>
<my-elem></my-elem>
<dom-module id="my-elem">
<template>
<ul>
<template is="dom-repeat" items='[ 1, 2, 3 ]'>
<li id="li[[item]]">{{item}}</li>
</template>
</ul>
<input type="button" value="make 2 red" on-tap="makeRed" />
</template>
</dom-module>
</body>
</html>

Related

Selcting the first <content> element with polymer 1

I am using Polymer 1 for web-development and I am encountering a small lack of understanding. Imagine the following:
<div class="value">
<content></content>
</div>
I can easily style the content with the .value selector. Now I only want to style the First content element. :first-child etc. doesn't seem to work.
How can I select different elements of my <content></content> in Polymer?
Thanks!
Note that <content> has been deprecated for <slot>.
To target the first child of the <slot>/<content>, use ::slotted(:first-child):
HTMLImports.whenReady(() => {
Polymer({
is: 'x-foo',
properties: {
foo: {
type: String,
value: 'Hello world!'
}
}
});
});
<head>
<base href="https://cdn.rawgit.com/download/polymer-cdn/1.8.0/lib/">
<script src="webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<x-foo>
<div>first</div>
<div>second</div>
<div>third</div>
</x-foo>
<dom-module id="x-foo">
<template>
<style>
::slotted(:first-child) {
color: red;
}
</style>
<slot></slot>
</template>
</dom-module>
</body>

Polymer - simple way to access child element properties from parent element

I have a simple polymer element that looks like this:
<link rel="import" href="../../bower_components/polymer/polymer.html">
<dom-module id="selector-course">
<template>
<style>
paper-dropdown-menu {
padding:5px;
}
</style>
<paper-dropdown-menu label="Course">
<paper-listbox class="dropdown-content" selected="{{selected}}" attr-for-selected="value" id="courseSelect">
<paper-item value="main">Main</paper-item>
<paper-item value="soup">Soup</paper-item>
<paper-item value="dessert">Dessert</paper-item>
<paper-item value="appetizer">Appetizer</paper-item>
</paper-listbox>
</paper-dropdown-menu>
</template>
<script>
Polymer({
is: 'selector-course'
});
</script>
</dom-module>
This element is stored in a separate HTML file and then used in a couple of my other elements like this:
<link rel="import" href="components/selector-course.html">
...
<selector-course selected="{{recipe.course}}"></selector-course>
Now, within my parent elements I need to access the selected value of <selector-course>
Right now, I have a solution that looks like this:
this.shadowRoot.querySelector('selector-course').shadowRoot.querySelector('#courseSelect').selectedItem.getAttribute("value");
This works, however, this query seems absurdly complex for such a trivial task as accessing the property of an element.
Is there a more simple way to achieve the same thing?
Oh no, this is a very bad idea. Accessing internal elements is very brittle, because it requires parent elements to have deep (pun intended) knowledge about the implementation details of <selector-course>. Not to mention that your method will not work with Shady DOM.
In your case you could simply adding a notifying property to your element
Polymer({
is: 'selector-course',
properties: {
selected: {
notify: true
}
}
});
To select it's value outside data binding you can use the method #a1626 mentions
var selected = this.$('selector-course').selected;
Polymer({
is: 'selector-course',
properties: {
selected: {
notify: true
}
}
});
<!DOCTYPE html>
<html>
<head>
<base href="https://polygit.org/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link href="polymer/polymer.html" rel="import"/>
<link href="paper-dropdown-menu/paper-dropdown-menu.html" rel="import"/>
<link href="paper-listbox/paper-listbox.html" rel="import"/>
<link href="paper-item/paper-item.html" rel="import"/>
</head>
<body>
<template is="dom-bind">
<selector-course selected="{{selection}}"></selector-course>
<div>{{selection}}</div>
</template>
<dom-module id="selector-course">
<template>
<style>
paper-dropdown-menu {
padding:5px;
}
</style>
<paper-dropdown-menu label="Course">
<paper-listbox class="dropdown-content" selected="{{selected}}" attr-for-selected="value" id="courseSelect">
<paper-item value="main">Main</paper-item>
<paper-item value="soup">Soup</paper-item>
<paper-item value="dessert">Dessert</paper-item>
<paper-item value="appetizer">Appetizer</paper-item>
</paper-listbox>
</paper-dropdown-menu>
</template>
</dom-module>
</body>
</html>
Your parent element seems to be a Polymer element in itself as you have used binding. In that case you can access property using
this.$.<id of child>.<property name>
Or in case your element is inside dom-if or dom-repeat
this.$$(<querySelector>).<property name>
You can check it out here
In your case it'll be
<selector-course selected="{{selected}}" id="mySelector"></selector-course>
In javascript
this.$.selected

Nested Polymer Components Content Issue

foo.html:
<link rel="import" href="bar.html">
<dom-module id="p-foo">
<template>
<p-bar>
<content select=".myContent"></content>
</p-bar>
</template>
<script>
Polymer( {
is: 'p-foo',
} )
</script>
</dom-module>
bar.html:
<dom-module id="p-bar">
<template>
bar open
<content select=".myContent"></content>
bar closed
</template>
<script>
Polymer( {
is: 'p-bar',
} )
</script>
</dom-module>
demo.html:
<!DOCTYPE html>
<html>
<head>
...
<link rel="import" href="foo.html">
</head>
<body>
<p-foo><div class="myContent"><strong>hello</strong></div></p-foo>
</body>
</html>
The expected output:
bar open
hello
bar closed
What I sometimes get:
bar open
bar closed
hello
The error I am getting is not 100% reproducible. It only happens a percentage of the time I refresh the page. It also appears that the more complicated the content is the higher chance of the error occurring.
It seems that polymer tries to select .myContent before the bar component is has completely rendered.
You need to register your new custom elements with a call to Polymer().
Also, as already stated in comments, your custom elements need to contain an hypen. For example: <p-foo>and <p-bar>.
foo.html:
<link rel="import" href="bar.html">
<dom-module id="p-foo">
<template>
<p-bar>
<content select=".myContent"></content>
</p-bar>
</template>
<script>
Polymer( {
is: 'p-foo',
} )
</script>
</dom-module>
bar.html:
<dom-module id="p-bar">
<template>
bar open
<content select=".myContent"></content>
bar closed
</template>
<script>
Polymer( {
is: 'p-bar',
} )
</script>
</dom-module>
demo.html:
<head>
...
<link rel="import" href="foo.html">
</head>
<body>
<p-foo><div class="myContent"><strong>hello</strong></div></p-foo>
</body>
</html>

How can I change polymer element template by passing param attribute

I'm creating a slider web component from scratch to learn.
I want the button to hide when the attribute controlVisible is false and show when it's true, but my selector $('#botaoVoltar') doesn't get anything.
What am I missing?
index.html:
<body>
<slider-js controlVisible='false' ></slider-js>
</body>
polymer.html:
<polymer-element name="slider-js">
<template>
<center>
<div id="container">
<div id="Buttons">
<button name="voltar" id="botaoVoltar"><<</button>
</div>
</div>
</center>
</template>
</polymer-element>
<script>
Polymer('slider-js', {
controlVisible: false,
ready: function () {
if (this.controlVisible === false) {
$('#botaoVoltar').hide();
} else {
$('#botaoVoltar').show();
}
}
});
</script>
The attribute is working fine. If I console.log it, I can see if it is true or false, but the template still renders with the button.
jQuery can't get at Polymer's local DOM, so you'd have to use Polymer's own DOM API. Actually, Polymer's automatic node finding provides quick access to nodes that have IDs with this.$. For instance, you could access the botaoVoltar button in your example with this.$.botaoVoltar.
It looks like you're using old Polymer (pre 1.0). You should switch to the latest version of Polymer (1.5.0). Here's your code upgraded to the newest Polymer version:
<head>
<base href="https://polygit.org/polymer+1.5.0/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<span>With control-visible:</span>
<x-slider control-visible></x-slider>
<span>Without control-visible:</span>
<x-slider></x-slider>
<!-- Normally, you would define this element in its own file. -->
<dom-module id="x-slider">
<template>
<div id="container">
<div id="Buttons">
<button id="botaoVoltar"><<</button>
<button>>></button>
</div>
</div>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-slider',
properties : {
controlVisible: {
type: Boolean,
value: false
}
},
ready: function() {
this.$.botaoVoltar.hidden = !this.controlVisible;
}
});
});
</script>
</dom-module>
</body>
codepen

Polymer webcomponents data binding an js object/array

On https://www.polymer-project.org/1.0/ the show the usage with firebase as datasource. However I'd like to use a simple js variable (array/object) as datasource e.g. an array with friends. However I'm not getting the array bound to the polymer.
How can I bind an js array as data bining to an polymer?
Example HTML Page index.html
<!DOCTYPE html>
<html lang="en">
<head>
<script src="/bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="friends-list.html">
</head>
<body>
<h1>Hello Data Object Arry Binding</h1>
<script>
var friends = [
{"name":"manual"},
{"name":"john"},
{"name":"doe","starred":true}
];
</script>
<friend-list data="friends"></friend-list>
</body>
</html
with expecting friend-list.html polymar may be something like this:
<dom-module id="friend-list">
<link rel="import" type="css" href="friend-list.css">
<template>
<template is="dom-repeat" items="{{data}}">
<contact-card starred="{{item.starred}}">
<img src="{{item.img}}">
<span>{{item.name}}</span>
</contact-card>
</template>
</template>
<script>
Polymer({
is: 'friend-list',
properties: {
data: Object
}
});
</script>
</dom-module>
You have to use dom-bind template if you want to use data binding outside of an element declaration.
<template is="dom-bind" id="app">
<h1>Hello Data Object Arry Binding</h1>
<friend-list data="{{friends}}"></friend-list>
</template>
<script type="text/javascript">
var app = document.getElementById('app');
app.friends = [
{"name":"manual"},
{"name":"john"},
{"name":"doe","starred":true}
];
</script>

Categories