Polymer 1.x: accessing element within dom-if - polymer

Here is my JSBin
Click on the "First Name: James" text.
I have an input element within dom-if. In an event, I am making dom-if to pass and so the element will come into existence but I cannot access the input element immediately after making the dom-if condition pass.
May be I need to know when the dom-if is actually evaluated and why the element does not exist even if the condition has become true.
<!doctype html>
<head>
<meta charset="utf-8">
<base href="https://polygit.org/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link href="polymer/polymer.html" rel="import">
<link href="iron-form/iron-form.html" rel="import">
<link href="paper-input/paper-input.html" rel="import">
</head>
<body>
<dom-module id="x-element">
<template>
<style></style>
<template is="dom-if" if="{{!editMode}}">
<span id="name" on-tap="_makeEditable">{{name}}: {{value}}</div>
</template>
<template is="dom-if" if="{{editMode}}">
<paper-input id="input" label="{{name}}" value="{{value}}"></paper-input>
</template>
</template>
<script>
(function(){
Polymer({
is: "x-element",
properties: {
editMode: {
type: Boolean,
value: false
},
name: {
type:String,
value:"First Name"
},
value: {
type:String,
value:"James"
}
},
_makeEditable: function() {
this.editMode = true;
//how to find the input element here
//this.$$('#input').querySelector("input").focus();
//this.$.input.querySelector("input").focus();
}
});
})();
</script>
</dom-module>
<x-element></x-element>
</body>

This is because setting this.editMode to true does not update the DOM instantaneously.
You should be running your selector asynchronously, so that Polymer has some time to update the DOM, such as:
this.async(function() {
this.$$('#input').focus();
})
Fiddle here.

Related

Array value initialized in element doesn't show at the mediator level

Not sure what I'm doing wrong, but I expect to see the length of an array I've initialized. However, I see an empty value instead, when I access the data at 'mediator' level.
This code is also in a jsbin: http://jsbin.com/wujaruy/edit?html,output
<!doctype html>
<head>
<base href="https://cdn.rawgit.com/download/polymer-cdn/1.5.0/lib/">
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<dom-module id="x-container">
<template>
<!-- doesn't show the expected value of '3' -->
<div>In container; # of items:[[listItems.length]]</div>
<x-list listItems="{{listItems}}"></x-list>
</template>
<script>
Polymer({
is: 'x-container'
});
</script>
</dom-module>
<dom-module id="x-list">
<template>
<div>In x-list 1; # of items:[[listItems.length]]</div>
</template>
<script>
Polymer({
is: 'x-list',
properties: {
listItems: {type: Array, value: [1,2,3], notify: true}
}});
</script>
</dom-module>
<x-container listItems="{{listItems}}"></x-container >
</body>
Figured it out; I got bitten by the upper-case issue. Changing
<x-list listItems="{{listItems}}"></x-list>
to
<x-list list-items="{{listItems}}"></x-list>
fixes the issue

Imperatively setting attribute to declaratively created child element before ready in Polymer

Similar to this question, Init polymer attributes before ready(), but not quite the same.
Is it possible to imperatively set attribute of a child element in Polymer before the ready event of that child element fires?
https://plnkr.co/edit/fM7lAflOLWOFuIiE7e9q?p=preview
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script src="https://polygit.org/components/webcomponentsjs/webcomponents-lite.min.js"></script>
<link href="https://polygit.org/components/polymer/polymer.html" rel="import">
<link href="user-profile.html" rel="import">
</head>
<body>
<user-profile></user-profile>
</body>
</html>
user-profile.html:
<link href="https://polygit.org/components/polymer/polymer.html" rel="import">
<link href="address-card.html" rel="import">
<dom-module id="user-profile">
<template>
<address-card address$="{{address}}"></address-card>
</template>
<script>
Polymer({
is: "user-profile",
properties: {
address: {
type: String,
value: "Pass the value to the child"
}
}
});
</script>
</dom-module>
address-card.html:
<link href="https://polygit.org/components/polymer/polymer.html" rel="import">
<dom-module id="address-card">
<template>
{{content}}
</template>
<script>
Polymer({
is: "address-card",
properties: {
address: String
},
ready: function () {
alert(this.address);
}
});
</script>
</dom-module>
The element <user-profile>, pass the value {{primaryAddress}} to his child the element <address-card>. The element <user-profile> is a "mediator" that control/assing value to his child.
<dom-module id="user-profile">
<template>
…
<address-card address="{{address}}"></address-card>
</template>
…
properties: {
address: {
type: String,
value: "Pass the value to the child"
}
}
</dom-module>
In this scenario, I use the data binding system to pass the value from the parent to the child.
Linking paths with data bindings

Polymer reflect functions across elements

I have a behavior that is shared across elements.
In a element i have a on-change="_toggle" switch.
In a second element i have the same code from the first element without the switch button. when the switch is active it reflect to the element containing the switch.
Q: how can i reflect the on-change="_toggle" function across all elements?
my code:
1.
<script>
LanguageBehavior = {
behaviors: [
Polymer.AppLocalizeBehavior
],
properties: {
language: {
value: 'sl',
reflectToAttribute: true
},
},
attached: function() {
this.loadResources(this.resolveUrl('/data/locales.json'));
},
_toggle: function() {
this.language = this.$.switch.checked ? 'en' : 'sl';
// This function is the problem?
}
};
</script>
2
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/paper-toggle-button/paper-toggle-button.html">
<link rel="import" href="../../bower_components/app-localize-behavior/app-localize-behavior.html">
<link rel="import" href="behavior.html">
<dom-module id="bazdara-element-1">
<template>
<style>
:host {
display: block;
}
</style>
{{localize('menu_2')}} // THIS CHANGES WITH THE SWITCH
<span title="english">🇬🇧 SI</span>
<paper-toggle-button on-change="_toggle" id="switch"></paper-toggle-button>
<span title="french">EN</span>
</template>
<script>
Polymer({
is: 'bazdara-element-1',
behaviors: [Polymer.AppLocalizeBehavior, LanguageBehavior],
});
</script>
</dom-module>
3
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/app-localize-behavior/app-localize-behavior.html">
<link rel="import" href="behavior.html">
<dom-module id="bazdara-element-2">
<template>
<style>
:host {
display: block;
}
</style>
{{localize('menu_2')}} // THIS Doesnt change
</template>
<script>
Polymer({
is: 'bazdara-element-2',
behaviors: [Polymer.AppLocalizeBehavior, LanguageBehavior],
});
</script>
</dom-module>
As each element will have its own copy of the behavior your approach is not going to work. Right now the only options i can come up with is:
keep both your elements in one common element and change the property there.
If you are planning to have all your elements in one single html file you can then change this feature in that html file and bind the property to all your elements.

Polymer: Passing properties to child element doesn't work

I'm trying to output data from a custom Polymer component <data-component> in an <iron-list> but nothing is shown when I open the page. It works when I pass an array of objects directly to the iron-list like <iron-list items='[{"name": "test1"}, {"name":"test2"}]' >
What am I doing wrong here and is the <template is="dom-bind" id="t"> mandatory?
index.html
<html>
<head>
<script src="../../webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="../data-component.html">
<link rel="import" href="../../iron-list/iron-list.html">
</head>
<body unresolved>
<template is="dom-bind" id="t">
<data-component>
<!--<iron-list items='[{"name": "test1"}, {"name":"test2"}]' > WORKS -->
<iron-list items="{{data}}" >
<template>
<div>
Name: <span>{{item.name}}</span>
</div>
</template>
</iron-list>
</data-component>
</template>
</body>
</html>
data-component.html
<link rel="import" href="../polymer/polymer.html">
<dom-module id="data-component">
<template>
<content></content>
</template>
</dom-module>
<script>
window.coolData = [
{"name": "Bob"},
{"name": "Tim"},
{"name": "Mike"}
];
Polymer({
is: 'data-component',
properties: {
data: {
value: window.coolData
}
}
});
</script>
I'm going to suggest an alternative answer to what I have already posted. If you want your data-component to always contain the iron-list then you can use this version here. However, if the content of the data-component should be more flexible use my other answer.
If you move the iron-list inside the data-component you can remove the dom-bind in your index.html.
data-component.html
<link rel="import" href="../polymer/polymer.html">
<dom-module id="data-component">
<template>
<iron-list items="{{data}}" >
<template>
<div>
Name: <span>{{item.name}}</span>
</div>
</template>
</iron-list>
</template>
</dom-module>
<script>
window.coolData = [
{"name": "Bob"},
{"name": "Tim"},
{"name": "Mike"}
];
Polymer({
is: 'data-component',
properties: {
data: {
type: Array,
value: window.coolData
}
}
});
</script>
index.html
<body unresolved>
<data-component></data-component>
</body>
You also have to add a data-binding to your data-component. Otherwise, the system does not know that data (in your iron-list) should refer to the data property in your custom element.
<data-component data="{{data}}">
<iron-list items="{{data}}" >
...
</iron-list>
</data-component>
The dom-bind is necessary if you want to have data-binding outside of a Polymer element, which seems to be the case here.
You should also make sure that the data property is configured to notify changes and that its type is set to Array.
Polymer({
is: 'data-component',
properties: {
data: {
type: Array,
value: window.coolData,
notify: true
}
}
});

Polymer 1.0 deep path array binding

I am trying to get the following to work. It initially of course renders the content of parentItems, but when changing it, the template looping over the parentItems is not invoked. I have looked at the notifyPath, but am not sure if this is the right direction
<!doctype html>
<html>
<head>
<script src='bower_components/webcomponentsjs/webcomponents-lite.min.js'></script>
<link rel='import' href='bower_components/paper-button/paper-button.html'>
</head>
<body>
<dom-module id='my-element'>
<template>
<template is='dom-repeat' items='{{parentValues}}'>
<template is='dom-repeat' items='{{item.childValues}}'>
<div>{{item.value}}</div>
</template>
</template>
<paper-button on-tap='click'>click me</paper-button>
</template>
</dom-module>
<script>
Polymer({
is: 'my-element',
properties: {
parentValues: {
type: Array,
value: function() { return [ { childValues: [ { value: 'original value' } ] } ]}
}
},
click: function() {
this.parentValues[0].childValues[0].value = 'new value';
}
});
</script>
<my-element></my-element>
</body>
</html>
How can I get it to work?
Thanks a million :-)
I believe the issue, which #jeanPokou solved was that you need to use the 'this.set(Object, New Value)' to set the value on the nested object.
You can check this video from the 'Ask Polymer' series to learn more about why it doesn't update nested values: https://youtu.be/0GxteaIaj2Q
You need to use dom-repeat with as scope in your binding, and notifyPath to bubble up change to your array when changed
<!doctype html>
<html>
<head>
<script src='bower_components/webcomponentsjs/webcomponents-lite.min.js'></script>
<link rel='import' href='bower_components/paper-button/paper-button.html'>
</head>
<body>
<dom-module id='my-element'>
<template is='dom-repeat' items='{{parentValues}}' as ="parent">
<template is='dom-repeat' items='{{parent.childValues}}' as="child">
<div>{{child.value}}</div>
</template>
</template>
<paper-button on-tap='click'>click me</paper-button>
</template>
</dom-module>
<script>
Polymer({
is: 'my-element',
properties: {
parentValues: {
type: Array,
value: function() { return [ { childValues: [ { value: 'original value' } ] } ]}
}
},
click: function() {
// notify path to the properties using the polymer syntax
this.set('parentValues.0.childValues.0.value','changed value');
}
});
</script>
<my-element></my-element>
</body>
</html>