app-localize-behavior and nested template - polymer

How can I manage to use a behavior (Polymer.AppLocalizeBehavior) inside a nested template: the created scope hides the localize() function.
<template>
...
<div class="content">
<div class="card-container">
{{localize('greeting')}} <---- OK!
<div class="layout horizontal wrap">
<template is="dom-repeat" items="{{employees}}">
<paper-card>
<div class="card-content">
<h2>{{localize('greeting')}}</h2> <---- EMPTY....
Example appreciated.
Thanks
--nick
EDIT 2016 May, 05
A small project showing the issue is available here: https://github.com/nocquidant/polymer-intl/
Instructions are in README.md

UPDATE (6/4/16): The <app-localize-behavior> bug was caused by a Polymer core bug, which is now fixed in Polymer 1.5.0 (jsfiddle).
UPDATE (5/20/16): This appears to be a bug in Polymer 1.4.0, as demonstrated in this jsfiddle. My demo from above had worked because I was using Polymer's latest code from master. (Note there are several commits since the v1.4.0 tag.)
As a workaround, use Bower to install a working commit of Polymer (as of 20-May-2016, the master branch is at commit 409ad83, which works properly with <app-localize-behavior>):
bower i -S polymer#409ad83
Bower will prompt you to select a specific Polymer version, in which case you should enter !1.
Unable to find a suitable version for polymer, please choose one by typing one of the numbers below:
1) polymer#409ad83 which resolved to 409ad83
2) polymer#^1.4.0 which resolved to 1.4.0 and is required by polymer-intl
3) polymer#^1.0.0 which resolved to 1.4.0 and is required by iron-media-query#1.0.8
4) polymer#^1.2.1 which resolved to 1.4.0 and is required by paper-behaviors#1.0.11
5) polymer#^1.3.0 which resolved to 1.4.0 and is required by app-localize-behavior#0.9.0
6) polymer#^1.2.0 which resolved to 1.4.0 and is required by iron-selector#1.5.2
7) polymer#^1.1.0 which resolved to 1.4.0 and is required by iron-flex-layout#1.3.1
Prefix the choice with ! to persist it to bower.json
? Answer
I didn't have any trouble using localize('greeting') inside a template repeater. Can you post a jsfiddle of your code?
Here's a working snippet (based on <app-localize-behavior> demo):
<head>
<base href="https://polygit.org/polymer+:master/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<script src="https://rawgit.com/yahoo/intl-messageformat/d361003/dist/intl-messageformat.min.js"></script>
<link rel="import" href="polymer/polymer.html">
<link rel="import" href="paper-toggle-button/paper-toggle-button.html">
<link rel="import" href="app-localize-behavior/app-localize-behavior.html">
</head>
<body>
<x-local-translate></x-local-translate>
<dom-module id="x-local-translate">
<template>
<div>
<span title="english">🇬🇧</span>
<paper-toggle-button on-change="_toggle" id="switch"></paper-toggle-button>
<span title="french">🇫🇷</span>
</div>
<div>
<h4>Outside Repeater</h4>
<div>
<div>{{localize('greeting')}}</div>
</div>
<h4>Template Repeater Items</h4>
<template is="dom-repeat" items="{{things}}">
<div>{{localize('greeting')}}</div>
</template>
</div>
</template>
<script>
Polymer({
is: "x-local-translate",
behaviors: [
Polymer.AppLocalizeBehavior
],
properties: {
things: {
type: Array,
value: function() {
return [1, 2, 3];
}
},
/* Overriden from AppLocalizeBehavior */
language: {
value: 'en',
type: String
},
/* Overriden from AppLocalizeBehavior */
resources: {
type: Object,
value: function() {
return {
'en': {
'greeting': 'Hello!'
},
'fr': {
'greeting': 'Bonjour!'
}
};
}
}
},
_toggle: function() {
this.language = this.$.switch.checked ? 'fr' : 'en';
}
});
</script>
</dom-module>
</body>
jsfiddle

Related

How to implement custom filters in Polymer 1.7.x

I am trying to implement a custom filter using Polymer v1.7.0 currently. However, it does not work at all; when I try to use a filter the output is just the raw expression, unprocessed.
I have tried it like it's done here: https://github.com/PolymerLabs/polymer-patterns/blob/master/snippets/filters/using-custom-filters.html but using this code:
<div id="toFixed">{{10.123456789 | toFixed(2)}}</div>
only results in
{{10.123456789 | toFixed(2)}} in the resulting document.
Is my linked source outdated? I couldn't find any valuable information in the Polymer docs so a nudge into the right the direction is appreciated.
You don't need pipe in Polymer 1.x to achieve this. You can directly call an function and pass it the value that you want to
<base href="https://polygit.org/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
<dom-module id="my-element">
<template>
{{format(myVal)}}
<br>{{format("hello")}}
</template>
</dom-module>
<script>
Polymer({
is: "my-element",
properties: {
myVal: {
type: String,
value: "Hi"
}
},
format: function(input) {
return input + " John";
}
});
</script>
<my-element></my-element>

Polymer 1.0: polymer-element not showing

The below code does not show in the browser. This works in Polymer 0.5. Is there code difference as I am using 1.0?:
<link rel="import" href="../bower_components/polymer/polymer.html">
<polymer-element name="my-name">
<template>
<h1> Hello {{name}}</h1>
</template>
<script>
Polymer('my-name', {
ready: function() {
this.name = "Brown";
}
});
</script>
</polymer-element>
Basically you need to rewrite your element based on the new requirements. You can easily follow it in the migration guide, registration element section.
You should rewrite it like following:
<dom-module id="my-name">
<template>
<!--Keep in mind in polymer 1.0 you can't have whitespaces in bound tags-->
<h1>Hello <span>{{name}}</span></h1>
</template>
<script>
Polymer({
is: "my-name",
ready: function () {
this.name = "Brown";
}
});
</script>
</dom-module>
I did a Plunker where you can reproduce it.
<link rel="import" href="../bower_components/polymer/polymer.html">
<dom-module id="my-name">
<style>
/*your styles go here*/
<style>
<template>
<!-- Things to show in element view -->
<h1> Hello <span>{{name}}</span></h1>
</template>
<dom-module>
<script>
// Your script goes here
Polymer({
is: 'my-name',
properties: {
name: {
type: String,
value: 'Brown'
}
}
});
</script>
There are many differences when migrating from Polymer 0.5 to Polymer 1.0 +. They changed the old polymer-element to dom-module and name attribute to id. The constructor is also changed as i shown in the example. Read https://www.polymer-project.org/1.0/docs/migration.html to get more info on migrating.
polymer 1.0 changes <polymer-element name="my-name"> to <dom-module id="my-name">.
I think you should follow the documentation of polymer 1.0
Polymer 1.0 documentation

Polymer 1.0 - routing

I'm new to Polymer. I start writing a simple webapp in which
1. User first land in a login page
2. If user passes login, then direct user to content page
I write an element "login"
<dom-module id="login">
<template>
<!-- local DOM for your element -->
<p>Username</p>
<input class="paper-font-body2" value="{{email::change}}" type="email">
<br/>
<p>Password</p>
<input class="paper-font-body2" value="{{password::change}}" type="password">
<p>{{errorMessage}}</p>
<iron-ajax
id="ajax"
url=""
method="POST"
on-response="signInResponse"
debounce-duration="300">
</iron-ajax>
<button on-click="signIn">Signin</button>
</template>
</dom-module>
<script>
// element registration
Polymer({
is: "login",
// add properties and methods on the element's prototype
properties: {
// declare properties for the element's public API
email: {
type: String,
value: "username"
},
password: {
type: String,
value: "password"
},
errorMessage: {
type: String,
value: ""
}
},
signIn: function() {
this.$.ajax.url = "http://myserver/login/email";
this.$.ajax.params = {"email":this.email, "password": this.password};
this.$.ajax.generateRequest();
},
signInResponse: function(request) {
response = request.detail.response;
console.log(response);
if (response.code == '0') {
this.fire("signin-success", response);
} else {
this.fire("signin-fail", response);
}
}
});
</script>
On index.html (main page), I use
<self-login
sign-in-success="onSignedIn"
></self-login>
Question: in the onSignedIn() callback, I would route my page to /content. How can I do?
EDIT 1: As #zacharytamas suggest, I try to use app-router as following
index.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<title>app-router</title>
<script src="../bower_components/webcomponentsjs/webcomponents-lite.js"></script>
<link rel="stylesheet" href="styles/main.css" shim-shadowdom>
<link rel="import" href="../bower_components/app-router/app-router.html">
</head>
<body unresolved>
<app-router>
<app-route path="/" import="/elements/home-page.html"></app-route>
<app-route path="/test" import="/elements/home-page.html"></app-route>
<app-route path="*" import="/elements/not-found-page.html"></app-route>
</app-router>
<script src="scripts/app.js"></script>
</body>
</html>
home-page.html
<dom-module id="home-page" noscript>
<template>
<h2>Hello</h2>
</template>
</dom-module>
It shows a blank page when I browse to both http://localhost:3000/ and http://localhost:3000/test on Chrome. Any idea?
Polymer does not have routing built into it by default. There are several front-end routing frameworks you can use with Polymer, however.
A very commonly used approach is a custom element called app-router, which lets you define routes declaratively with just HTML alone. I've had some success with it before. Check out the websitefor information on setting it up.
Another HTML-based way of doing it is a custom element made by a member of the Polymer team called more-routing. Google has a video series about Polymer called Polycasts which made a video explaining the more-routing approach. You should check that video out for info about getting started.
Another option is to do it with JavaScript using the page.js framework. This is the method used the Polymer Starter Kit. Here's another Polycast to get you started on that way.
Welcome to the Polymer world!
Good news! The Polymer team has released an official router. An excellent introduction is available on their blog:
https://www.polymer-project.org/1.0/blog/routing
And the Readme.md on the Github repo is quite instructive:
https://github.com/PolymerElements/app-route
There are two elements necessary for basic functionality, <app-location> and <app-route>
The following is a simple example:
<app-location route="{{route}}"></app-location>
<app-route
route="[[route]]"
pattern="/users"
active="{{usersRouteIsActive}}">
</app-route>
In the above example usersRouteIsActive will receive a boolean value, true if the route matches /users, and false if it does not. Simple, right? After this, as your application's routes get more complicated the app-route element has more features that will support those needs.
Try using 'dna-router'. Its relatively new and supports Polymer-1.0.
You can create routing purely in html.
Dna-router also supports user-authentication. You can pass login status and loggedin data in its 'dna-config' element. Router will show page based on login status.
You can declare which states need user authentication.
Its still under development and have some glitches in it. But worth giving a try.
Github: https://github.com/Saquib764/dna-router/
The answer depends on the kind of router you use. I was unhappy with the state of Polymer routers, so I wrote excess-router. With this router, you would:
define your routes, and make /content is a default route
configure router to be started manually
start the router manually on signin
<excess-router-config manual-start></excess-router-config>
<excess-route route="/content"></excess-route>
<excess-route route="/(.*)" redirect-to="/content" activation-modifiers="x"></excess-route>
<script>
function onSignedIn() {
Excess.RouteManager.start();
}
</script>
I solving this problem just adding in page template this code:
<script>
Polymer({
is: 'home-page'
});
</script>
Full page code:
<link href="../bower_components/polymer/polymer.html" rel="import">
<dom-module id="home-page">
<template>
<div>Home page</div>
</template>
<script>
Polymer({
is: 'home-page'
});
</script>
</dom-module>
As of Polymer 1.4, carbon-route (later renamed app-route) can be used:
https://github.com/polymerelements/carbon-route
https://blog.polymer-project.org/announcements/2016/03/28/carbon-route-released/
https://www.polymer-project.org/1.0/articles/routing.html
Here's an example taken from the polymer blog:
<carbon-location route="{{route}}">
</carbon-location>
<carbon-route route="{{route}}" pattern="/tabs/:tabName" data="{{data}}">
</carbon-route>
<paper-tabs selected="{{data.tabName}}" attr-for-selected="key">
<paper-tab key="foo">Foo</paper-tab>
<paper-tab key="bar">Bar</paper-tab>
<paper-tab key="baz">Baz!</paper-tab>
</paper-tabs>
<neon-animated-pages selected="{{data.tabName}}"
attr-for-selected="key"
entry-animation="slide-from-left-animation"
exit-animation="slide-right-animation">
<neon-animatable key="foo">Foo Page Here</neon-animatable>
<neon-animatable key="bar">Bar Page Goes Here</neon-animatable>
<neon-animatable key="baz">Baz Page, the Best One of the Three</neon-animatable>
</neon-animated-pages>
See also similar question: Routing in polymer 1.0

app-router not working imperatively way

I have this Polymer custom element:
<link rel="import" href="../../../bower_components/polymer/polymer.html">
<link rel="import" href="../../../bower_components/core-animated-pages/core-animated-pages.html">
<link rel="import" href="../../../bower_components/app-router/app-router.html">
<polymer-element name="custom-pages" attributes="selected">
<template>
<link rel="stylesheet" href="custom-pages.css">
<app-router id="router" bindRouter core-animated-pages transitions="cross-fade-all" trailingSlash="ignore">
<template repeat="{{page in pages}}">
<app-router path="{{page.path}}" import="{{page.url}}"></app-router>
</template>
</app-router>
</template>
<script>
(function() {
Polymer({
selected: 0,
pages: [{
path: "/home",
url: '../custom-home/custom-home.html'
}, {
path: "/about",
url: '../custom-about/custom-about.html'
}],
selectedChanged: function(oldValue, newValue) {
router = this.$.router;
router.go(this.pages[newValue].path);
}
});
})();
</script>
</polymer-element>
Elements custom-home and custom-about should be lazy loaded when "selected" change, but not is happening (no page is displayed).
You have a syntax error in your template definition, nested tags are to be app-route rather than app-routeR:
<app-router id="router" ...>
<template repeat="{{page in pages}}">
<!-- ⇓ superfluous r, nested are app-route -->
<app-router path="{{page.path}}" import="{{page.url}}"></app-router>
<!-- SHOULD BE: -->
<app-route path="{{page.path}}" import="{{page.url}}"></app-route>
</template>
</app-router>
Currently you have created a bundle of empty routers.
Plus, the documentation says:
If you use go(path, options) you should also set the mode to hash or pushstate on the router.
I am not sure if this affects your case, since you do not seem to pass options.
Hope it helps.

Polymer: how to parse the index to the elements using template repeat

I've been trying to use Polymer for a project I'm working on. And although I enjoyed it quite a lot so far, I ran into a problem I just can't solve.
I dumped it down to a simple example. Basically it's just a list element (item-list) that contains item elements (item-card) and i want to parse the items position to the element via the attribute pos. But for some reason the items attribute is allways undefined! Is this because the attribute is bound to the variable i, which dies after the template repeat? If so, how do I work around it? Is there a different approach I should be using here?
SOLUTION: You can find the solution by reading through all the comments, but to sum it up: apperantly there was a timing issue and the attribute wasn't ready at the ready callback. But I found out about the domReady callback (polymer lifecycle documentation). Using domReady it works just fine! Thanks to Günter Zöchbauer for the help!
This is the item-list.html:
<link rel="import" href="components/polymer/polymer.html">
<link rel="import" href="item-card.html">
<polymer-element name="item-list">
<template>
<style>
</style>
<template repeat="{{values, i in data.data}}">
<item-card pos="{{i}}"></item-card>
</template>
</template>
<script>
Polymer({
created: function()
{
this.num = 123456;
this.data = { "data":
[
{
"value":999
},
{
"value":666
},
{
"value":555
},
{
"value":222
}
]
};
}
});
</script>
</polymer-element>
This is the item-card.html
<link rel="import" href="components/polymer/polymer.html">
<polymer-element name="item-card" attributes="pos">
<template>
<style>
</style>
</template>
<script>
Polymer({
ready: function()
{
console.log("ready: " + this.pos);
}
});
</script>
</polymer-element>
I didn't bother putting the index.html in, since it just containts one item-list element.
Thanks alot!!
I think you need a pos field in <item-card> in addition to the attributes="pos" declaration.
The repeated element also references the bound model which can be accessed like querySelector('item-card').templateInstance.model property.
See https://github.com/PolymerLabs/polymer-selector/blob/master/polymer-selector.html#L286 for an example.
Info:
According to the comments it turned out to be a timing issue. The value wasn't yet assigned when the ready callback was called but using domReady worked.