Polymer: import and bind templates from another file - polymer

Would it be possible to import templates from another file? I'm able to import javascript and stylesheet, but cannot figure out how to import html templates.
For example:
I defined various content-item templates in templates.html
<template id="hello>Hello {{ li.name }}</template>
<template id="hey">Hey!</template>
And then, I would like to re-use the templates in list.html
<link rel="import" href="templates.html">
<polymer-element name="list" attributes="type,data">
<template>
<template repeat="{{ li in items_in_data }}">
<template bind ref="hey"></template>
<template bind ref="{{ type }}"></template>
</template>
</template>
</polymer-element>
Finally, in app.html
<list data="items.json" type="hello"></list>
If I put the contents inside templates.html into list.html, it works fine. However, it does not seem to load or reference when using <link rel="import">. Any ideas?

Partial solution: The below works in chrome but not polyfill browsers (e.g. firefox). Need to look through polyfill code to figure out how to handle links in a file already linked.
The issue is that the content of the import is not inserted into the document but is just made available for use. See HTML5 Rocks imports - using content for more details. You can find all of the templates in the linked file and insert them into your polymer element's document fragment:
var importDoc = document.currentScript.ownerDocument;
var link = importDoc.querySelector('.myimports');
var templates = link.import.querySelectorAll('template');
for (var i=0;i<templates.length;i++) {
importDoc.head.appendChild(templates[i]);
}
Example
demo-templates.html
<template id="hello">Hello World!</template>
<template id="goodbye">See you tomorrow</template>
demo-importTemplates-list.html
<link class="myimports" rel="import" href="demo-templates.html">
<polymer-element name="demo-importTemplates-list">
<template>
<template repeat="{{ li in data }}">
<h1>{{li}}</h1>
<template bind ref="hello"></template> -- <template bind ref="goodbye"></template>
</template>
</template>
<script>
Polymer({
data: ['first','second','third']
});
// http://www.html5rocks.com/en/tutorials/webcomponents/imports/#usingcontent
// http://www.html5rocks.com/en/tutorials/webcomponents/imports/#include-templates
var importDoc = document.currentScript.ownerDocument;
var link = importDoc.querySelector('.myimports');
var templates = link.import.querySelectorAll('template');
for (var i=0;i<templates.length;i++) {
importDoc.head.appendChild(templates[i]);
}
</script>
</polymer-element>
index.html
<html lang="en">
<head>
<script src="../../webcomponents/bower_components/webcomponentsjs/webcomponents.min.js"></script>
<link rel="import" href="../../webcomponents/bower_components/polymer/polymer.html">
<link rel="import" href="demo-importTemplates-list.html">
<title>demo-importTemplates</title>
</head>
<body>
<demo-importTemplates-list type="hello"></demo-importTemplates-list>
</body>
</html>

Related

Polymer 1.0 paper-tabs doesn't fully support array splice

when array item is removed and another one is added in one splice on model array, paper-tabs just removes removed item from DOM without adding a new one.
Please, take a look:
<!doctype html>
<html>
<head>
<title>paper-tabs-splicing-problem</title>
<meta name="description" content="When array item is removed and another one is added in one splice on model array, paper-tabs just removes removed item from DOM without adding a new one.">
<script src="https://rawgit.com/EdVaIl/polymer/master/dist/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="https://rawgit.com/EdVaIl/polymer/master/dist/bower_components/paper-tabs/paper-tabs.html">
</head>
<body>
<template is="dom-bind" id="app">
<template is="dom-repeat" items="[[items]]">
<div>[[item]]</div>
</template>
<paper-tabs scrollable>
<template is="dom-repeat" items="[[items]]">
<paper-tab>[[item]]</paper-tab>
</template>
</paper-tabs>
</template>
<script>
(function(document) {
'use strict';
var app = document.querySelector('#app');
app.addEventListener('dom-change', function() {
app.items = ['square', 'circle', 'pillow', 'triangle'];
});
window.addEventListener('WebComponentsReady', function() {
app.splice('items', 2, 1, 'line');
});
})(document);
</script>
</body>
</html>
You probably need to use the Polymer Array Mutation methods. See polymer array mutation docs

Polymer 1.0 Extending Elements - paper-dialog with custom element

I am am trying to create a custom element that plays a youtube video in paper-dialog. So videoPlayer = Polymer.dom(this.root).querySelector('video-player'); inherits/has access to that paper-dialogs open method, I am trying to extend my custom element. It isn't working, but hopefully I am on the right track and someone can show me correctly.
I am using Polymer 1.0, but I only have https://www.polymer-project.org/0.5/docs/polymer/polymer.html#extending-other-elements to go by for extending elements.
<link rel="import" href="../bower_components/paper-dialog/paper-dialog.html">
<link rel="import" href="../bower_components/paper-icon-button/paper-icon-button.html">
<link rel="import" href="../bower_components/iron-icons/iron-icons.html">
<link rel="import" href="../bower_components/google-youtube/google-youtube.html">
<link rel="import" href="../bower_components/polymer/polymer.html">
<dom-module id="video-player">
<template>
<div class="layout horizontal">
<paper-button dialog-dismiss>
<paper-icon-button icon="arrow-back"></paper-icon-button>
</paper-button>
</div>
<div style="height: 100%; width: 100%">
<google-youtube style="height: 100%;"
video-id="YMWd7QnXY8E"
rel="1"
start="5"
playsinline="0"
controls="2"
showinfo="0"
width="100%"
height="100%"
autoplay="1">
</google-youtube>
</div>
</template>
<script>
Polymer({
is: "video-player"
});
</script>
<paper-dialog name="video-player" extends="video-player">
<template>
<shadow></shadow>
</template>
<script>
Polymer();
</script>
</paper-dialog>
<video-player></video-player>
As was mentioned in the comments, you can't yet extend custom elements, so the existing pattern (or at least the one I use) is to make use of behaviors wherever possible and wrappers wherever not.
e.g.
<dom-module id="popup-video-player">
<template>
<video-player></video-player>
</template>
<script>
Polymer({
is: 'popup-video-player',
behaviors: [Polymer.PaperDialogBehavior],
...
});
</script>
</dom-module>
Now you can use <popup-video-player> just like a paper-dialog.
I know it stinks because if video-player has a bunch of properties that you want access to, you have to copy them in the popup-video-player element's API, which is not exactly DRY.
If you look at the paper-input source, you'll see them doing the same thing. It's obvious that they want to extend iron-input, but they can't so you get things like this:
<input is="iron-input" id="input"
aria-labelledby$="[[_ariaLabelledBy]]"
aria-describedby$="[[_ariaDescribedBy]]"
disabled$="[[disabled]]"
title$="[[title]]"
... >
As a side note, you could always hook into the <video-player>s "properties" property and make the API additions programatically.
maybe something like this would work: (untested!)
Polymer({
...
properties: (function () {
var prop = {
//special properties specific to the pop up version of video-player
//..obviously be careful to avoid name space conflicts.
};
var video_player = document.createElement('video-player');
video_player.properties.keys().forEach( function(key) {
props[key] = video_player[key];
});
return props;
}()),
});

template repeat in polymer 1.0

I've created a test polymer element where in I was figuring out how to use use arrays in templates. My code does not work and the documentation for 1.0 doesn't really talk much about how to use repeat in template tags.
my element:
<!-- Imports polymer -->
<link rel="import" href="polymer/polymer.html">
<!-- Defines element markup -->
<dom-module id="my-element" >
<template>
<style>
my-element
</style>
<h2>{{data}}</h2>
<ul>
<template repeat={{column in columns}} bind>
<li>{{column}}</li>
</template>
</ul>
</template>
</dom-module>
<!-- Registers custom element -->
<script>
Polymer({
is: 'my-element',
// Fires when an instance of the element is created
created: function() {
},
// Fires when the local DOM has been fully prepared
ready: function() {},
// Fires when the element was inserted into the document
attached: function() {},
// Fires when the element was removed from the document
detached: function() {},
// Fires when an attribute was added, removed, or updated
attributeChanged: function(name, type) {
alert("changed");
},
properties:{
data :String,
columns:Array
}
});
</script>
and the index.html page where I'm using the element:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title><my-repo></title>
<!-- Imports polyfill -->
<script src="webcomponents-lite.min.js"></script>
<!-- Imports
custom element -->
<link rel="import" href="my-element.html">
<!-- Runs custom element -->
<my-element users = '{{[1,2,3,4]}}' data="This is a polymer table"></my-element>
Please let me know what's wrong with my code!!
You have to use
<template is="dom-repeat" items="{{users}}">
<li>{{item}}</li>
</template>
And in main file:
<my-element users="[1,2,3,4]" data="This is a polymer table"></my-element>
You can search Youtube for Polycast, a series by Google Developers where they're talking about Polymer for beginners and showing cool tricks.
Polymer 1.0 does not allow expressions in data binding. The problem is in:
<my-element users = '{{[1,2,3,4]}}' ...>
You need to replace {{[1,2,3,4]}} with a property. Something like this:
<template is="dom-bind">
<my-element users = '{{myarray}}' data="This is a polymer table"></my-element>
</template>
<script>
(function() {
var template = document.querySelector('template[is="dom-bind"]');
template.myarray = [1,2,3,4];
})();
</script>

How to use apps-global with polymer's sampler-scaffold?

I am using sample-scaffold from https://github.com/Polymer/sampler-scaffold and define some globale variables using app-globals as described in https://www.polymer-project.org/docs/polymer/polymer.html#global
like
<app-globals myvar="value"></app-globals>
<sampler-scaffold>
<core-item label="Page 1" url="page1.html"></core-item>
</sampler-scaffold>
page1.html contains also the app-globals without values.
<app-globals id="globals"></app-globals>
However, the globals element does not contain any values. Is there a way to define globals across iframes using app-globals?
What about using the Polymer Element extensions? and inheritance to keep the interface of the app-globals object static? My Plunker: http://embed.plnkr.co/uDPTVP/preview
app-config.html
<!-- per https://www.polymer-project.org/docs/polymer/polymer.html#extending-other-elements -->
<link rel="import" href="http://www.polymer-project.org/components/polymer/polymer.html">
<link rel="import" href="app-globals.html">
<polymer-element name="app-config" extends="app-globals">
<script>
Polymer({
ready: function () {
this.super();
this.values.GloabalSettingsVal1 = "GDG FTW"
}
});
</script>
</polymer-element>

how to inject <template> into polymer component by providing it as element content

i want to inject a template into an polymer component like this :
<polymer-element name="foo-bar">
<template>
<content></content>
<!-- content is expected to contain a template with id="layout"-->
<template bind ref="layout">
default content template
</template>
</template>
<script src="index.js"></script>
</polymer-element>
usage of the component :
<foo-bar>
<template id="layout">another content template</template>
</foo-bar>
unfortunately the template provided as content of the element is not taken over for some reason.
when simluate the wished behaviour using
<polymer-element name="foo-bar">
<template>
<template id="layout">
custom content template
</template>
<template bind ref="layout">
default content template
</template>
</template>
<script src="index.js"></script>
</polymer-element>
the referenced template(id="layout") is used as expected.
Any help is appreciated :-)
<template ref="layout"> says use the template#layout for my content. So I would expect the template in your shadow dom to use the content of the light dom template. This is what you see in http://jsbin.com/takipi/1/edit.
However, if you want to use render the light dom <template> the user provides, you must activate it using template.createInstance(). By default, templates are inert. For this use case, you also don't need <content>. That's for rendering and in this case, it doesn't really make sense.
The example below also show how to set things up. It also shows how you can use {{}} bindings in the light dom <template> and fill them when the instance is created.
<div id="container"></div>
<template if="{{showDefault}}">
default content template
</template>
attached: function() {
var template = this.querySelector('template');
if (template) {
this.$.container.appendChild(
template.createInstance({foo: 5}));
this.showDefault = false;
}
}
Full code:
<script src="http://www.polymer-project.org/platform.js"></script>
<script src="http://www.polymer-project.org/polymer.js"></script>
<polymer-element name="foo-bar">
<template>
<div id="container"></div>
<template if="{{showDefault}}">
default content template
</template>
</template>
<script>
Polymer({
showDefault: true,
attached: function() {
var template = this.querySelector('template');
if (template) {
// Allow Polymer expressions in the template's {{}}.
if (!template.bindingDelegate) {
template.bindingDelegate = this.element.syntax;
}
this.$.container.appendChild(
template.createInstance({foo: 5}));
this.showDefault = false;
}
}
});
</script>
</polymer-element>
<foo-bar>
<template>
<b>another</b> content template. Also supports data: {{foo}}
</template>
</foo-bar>