I'd like to ask you people about workflow with Polymer. I know that I should use my own elements or double check if element that I need isn't alredy published. It's really nice, I admit it. However the Polymer Starter Kit comes as single-page app. Is it the recommended approach for using Polymer? What about large pages that would need a lot of data to be loaded? Are there alternative approaches?
You don't need to have all your elements rendered at same time. They can be created on the fly only when needed, and can be destroyed as well.
To create your elements on the fly, you can use DOM Manipulation methods like:
var myElement = document.createElement("my-element");
this.$.container.appendChild(myElement);
myElement.myProperty = "anything";
To remove, just do this way:
var myElement = this.$.container.querySelector("my-element");
myElement.parentNode.removeChild(myElement);
If you need dynamic load a HTML Import, you can use this.importHref if your code is inside a polymer Element (and it should be).
this.importHref('myElement.html', function(e) {
// Create your element here
});
Putting things together...
Suppose you have a polymer element like that:
<dom-module id="my-app">
<template>
<div id="container"></div>
<paper-button on-click="_loadElement">Load Element</paper-button>
<paper-button on-click="_removeElement">Remove Element</paper-button>
</template>
</dom-module>
<script>
Polymer({
is: 'my-app',
_loadElement: function() {
this.importHref('myElement.html', function(e) {
var myElement = document.createElement("my-element");
this.$.container.appendChild(myElement);
myElement.myProperty = "anything";
});
},
_removeElement: function() {
var myElement = this.$.container.querySelector("my-element");
myElement.parentNode.removeChild(myElement);
}
});
</script>
Related
I'm trying to observe added and removed dom nodes to my custom Polymer element without success. I've noticed that the this.$ is an empty object.
Polymer({
is: 'dramatic-view',
attached: function () {
this._observer = Polymer.dom(this.$.contentNode).observeNodes(function (info) {
console.log('kromid info', info);
});
}
});
The callback is being called only once (even tho I change content afterwards) with the following strange parameters:
I was following the docs here.
this.$ is a hash of elements in your template that have an id attribute (see Automatic node finding).
So, for this.$.contentNode to exist, you need an element with id="contentNode" in your <dom-module>'s <template>, and it must not be inside a dom-if or dom-repeat template:
<dom-module id="x-foo">
<template>
<content id="contentNode"></content>
</template>
</dom-module>
Nodes created dynamically (i.e., those inside dom-if or dom-repeat) must be queried with this.$$() (e.g., this.$$('#contentNode')). If you're trying to set them up in the attached callback, you'll need to wait until after the nodes are stamped, which could be observed with Polymer.RenderStatus.afterNextRender().
<dom-module id="x-foo">
<template>
<template is="dom-if" if="[[useDynamicContent]]">
<content id="contentNode"></content> <!-- unavailable to this.$ -->
</template>
</template>
<script>
Polymer({
is: 'x-foo',
attached: function() {
Polymer.RenderStatus.afterNextRender(this, function() {
var contentNode = this.$$('#contentNode');
if (contentNode) {
contentNode.observeNodes(...);
}
});
}
});
</script>
</dom-module>
To trigger the node observer, use Polymer's DOM API like this:
Polymer.dom(this).appendChild(node);
Polymer.dom(this).removeChild(node);
codepen
UPDATE It seems you're integrating Polymer with Elm, and expecting to see the observer callback for node-changes made my Elm. You'll need to hook Elm's calls to appendChild/removeChild somehow so that it uses Polymer's DOM API.
<template is="dom-bind" id="app">
<div>{{title}}</div>
<my-element></my-element>
</template>
Can I inside my-element force the auto-bind template to redraw?
I can get the template, but changing it does not trigger a redraw:
var app = document.querySelector('#app');
app.title = 'Zaphod';
Your code should work, except setting the title needs to wait until polymer is ready (i.e. elements have been registered and are ready to be interacted with).
var app = document.querySelector('#app');
document.addEventListener("WebComponentsReady", function () {
app.title = 'Zaphod';
});
What's the Polymer 1.0 equivalent to injectBoundHTML()?
(i.e. appending HTML strings to nodes within a Polymer element and having data bindings resolve)
A JSbin example - http://jsbin.com/jufase/edit?html,output
EDIT: don't have enough SO cred to accept my own answer yet, but it should be down below somewhere. TL;DR - use "dom-bind" templates
Although as techknowledgey pointed out it's not really supported well yet. The following seems to do the trick.
function injectBoundHTML(html, element) {
var template = document.createElement('template', 'dom-bind');
var doc = template.content.ownerDocument;
var div = doc.createElement('div');
div.innerHTML = html;
template.content.appendChild(div);
while (element.firstChild) {
element.removeChild(element.firstChild);
}
element.appendChild(Polymer.Base.instanceTemplate(template));
}
If your HTML was already parsed then use something like "doc.importNode(sourceNode, true);" instead of getting/setting innerHTML.
Looks like this is not really a supported feature yet, looking at the comments from #kevinpschaaf:
https://github.com/Polymer/polymer/issues/1778
Using dom-bind, I should be able to satisfy my use case, e.g. http://jsbin.com/caxelo/edit?html,output
Bindings are to properties by default, and hyphens can be used to denote capitalizations:
<element inner-h-t-m-l="{{prop}}"></element>
Thanks guys for the prototype that I updated for my own needs : Generate markup in polymer, as dom-repeat was unable to perform this operation.
Tags for search engines :
Polymer Generation dynamically dynamic markup custom element dom-repeat dom repeat balise dynamique dynamiquement
http://jsbin.com/wiziyeteco/edit?html,output
<!doctype html>
<html>
<head>
<title>polymer</title>
<script src="https://rawgit.com/webcomponents/webcomponentsjs/master/webcomponents-lite.js"></script>
<link rel="import" href="http://polygit.org/components/paper-button/paper-button.html">
</head>
<body>
<dom-module id="x-test">
<template>
<div id="container"></div>
</template>
</dom-module>
<script>
Polymer({
is: 'x-test',
ready: function() {
// Declare custom elements
var customElements = [
{name:'paper-button', title:'A'},
{name:'paper-button', title:'B'},
{name:'paper-button', title:'C'},
{name:'paper-button', title:'D'},
];
// Declare auto-binding, as we are at the root HTML document
var domBind = document.createElement('template', 'dom-bind');
domBind.customElements = customElements;
var domBindDocument = domBind.content.ownerDocument;
// Declare custom elements
for (var i in domBind.customElements) {
var item = domBind.customElements[i];
var elem = domBindDocument.createElement(item.name);
elem.setAttribute('raised', 1);
elem.innerHTML = item.title;
domBind.content.appendChild(elem);
}
// Append to #container
this.$.container.appendChild(domBind);
}
});
</script>
<x-test></x-test>
</body>
</html>
When I try document.querySelector('core-drawer-panel').togglePanel() in the console it works but when I do the following core-drawer-panel is not ready yet?
<template>
<core-drawer-panel forceNarrow>
</core-drawer-panel>
</template>
<script>
document.addEventListener('polymer-ready', function() {
document.querySelector('core-drawer-panel').togglePanel()
console.log('polymer-ready');
});
</script>
Note that I can not wrap it in a polymer element due to issues with other js frameworks.
try this
var template = document.querySelector('template');
template.addEventListener('template-bound', function () {
//code
});
with your element inside a template you need to look for template to be ready not polymer.
I am working on a Polymer project and I a few custom elements nested. For example, I have a custom element called <example-main>. Suppose that this element has a function called displayMessage()
I have another custom element defined inside <example-main> called <example-alerts>. I want the alerts element to be able to use the function in its parent, main, to display a message.
To achieve this, I am trying to select the element <example-main id='mainEl'> by using the Polymer's Automatic Node Finding hash, this.$.mainEl and using the function like so: this.$.mainEl.displayMessage();
However, I get this error message:
Uncaught TypeError: Cannot read property 'displayMessage' of undefined
Am I making a wrong approach of having Polymer elements call functions in other Polymer objects?
To visualize things a little better, the index.html would look something like:
...
<body>
<example-main id='mainEl'></example-main>
</body>
...
while example-main.html looks something like:
<polymer-element name='example-main'>
<template>
...
<example-alerts>
</template>
<script>
Polymer(example-element, {
displayMessage: function(){
//do message showing magic
}
});
</script>
</polymer-element>
and lastly, example-alerts.html looking like:
<polymer-element name='example-alerts'>
<template>
...
<paper-button on-tap='{{callFunction}}'></button>
</template>
<script>
Polymer(example-alerts, {
callFunction: function(){
//call the function in parent
this.$.mainEl.displayMessage();
}
});
</script>
</polymer-element>
You are not doing this correct way , you cannot find nodes this way .
Node finding just search within same element defined in elements outermost template.
You should either change your approach or you can use events to handle the situation pls see the sample demo which can work for you.
<polymer-element name='example-alerts'>
<template>
...
<paper-button on-tap='{{callFunction}}'></button>
</template>
<script>
Polymer(example-alerts, {
callFunction: function(){
//call the function in parent
this.fire('ouch', {msg: 'That hurt!'});
}
});
</script>
</polymer-element>
--Second Element
<polymer-element name='example-main'>
<template>
...
<example-alerts on-ouch='{{displayMessage}}'>
</template>
<script>
Polymer(example-element, {
displayMessage: function(){
//do message showing magic
}
});
</script>
</polymer-element>