how to bind the values using object in polymer 3.x? - polymer

I'm trying to bind the values using an object reference like this:
this.set('state', tab1Data);
but values are not binding with respective input fields.
We are using the polymer 3.x version

It depends very much on where you bind your data and how you bind it.
As you provide not so much information on the concrete context, I would guess, that you bind your data, outside the element ths calls this.set('state', ...) .
Then your property needs to have the notify-flag been set to true, otherwise changes won't be propagated outside.
The following code shows this behavior:
<html>
<head>
<script src="https://unpkg.com/#webcomponents/webcomponentsjs#latest/webcomponents-loader.js"></script>
</head>
<body>
<script type="module">
import {PolymerElement, html} from 'https://unpkg.com/#polymer/polymer/polymer-element.js?module';
import 'https://unpkg.com/#polymer/paper-button/paper-button.js?module';
class MyElement extends PolymerElement {
static get properties() {
return {
someData: {
type: Object,
value: () => {return {}},
notify: true
},
otherData: {
type: Object,
value: () => {return {}},
notify: false
},
counter: Number
}
}
constructor() {
super();
this.counter = 0;
}
static get template() {
return html`
<style> :host { display: block; } .mood { color: green; } </style>
Mood: <span class="mood">[[someData.mood]] ([[otherData.mood]])</span>
<paper-button raised on-click="setNewObject">set object</paper-button>
<paper-button raised on-click="setNewValue">set value</paper-button>
`;
}
setNewObject() {
this.counter++
const mood = `good [${this.counter}]`
this.set('someData', {mood: mood});
this.set('otherData', {mood: mood});
}
setNewValue() {
this.counter++
const mood = `better [${this.counter}]`
this.set('someData.mood', mood);
this.set('otherData.mood', mood);
}
}
customElements.define('my-element', MyElement);
class MySecondElement extends PolymerElement {
static get properties() {
return {
mood: String
}
}
static get template() {
return html`Web Components are <span>[[mood]]</span>!`;
}
}
customElements.define('my-second-element', MySecondElement);
class MyApp extends PolymerElement {
static get template() {
return html`
<my-element some-data="{{someData}}" other-data="{{otherData}}" ></my-element>
<h2>notify true</h2>
<my-second-element mood="[[someData.mood]]"></my-second-element>
<h2>notify false</h2>
<my-second-element mood="[[otherData.mood]]"></my-second-element>
`;
}
}
customElements.define('my-app', MyApp);
</script>
<my-app></my-app>
</body>
</html>

You should put the code on the value which set on the localstorage. I show it here.
import '#polymer/iron-localstorage/iron-localstorage.js';
....
<iron-localstorage name="user-info" value="{{userInfo}}" on-iron-localstorage-load-empty="initializeUserInfo"></iron-localstorage>
<vaadin-text-field id="test">
........
initializeUserInfo(){
this.set('userInfo', []);
}
ready(){
super.ready();
this.set('userInfo', this.$.test.value);
}
This is able to set data in the localstorage.

Related

Why does Webcomponent object value is shared between the different instances of the same webcomponent?

I created a web component called TestElement with Polymer as below. It simply has an object value and a function which adds values to this component.
<dom-module id="test-element">
<template>Test Element</template>
<script>
class TestElement extends Polymer.Element {
static get is() { return "test-element"; }
static get properties() {
return {
_myVar: {
type: Object,
value: {},
},
};
}
addNew(key, val) {
this._myVar[key] = val;
}
}
customElements.define(TestElement.is, TestElement);
</script>
</dom-module>
I created two instances of this in a parent element as follows:
class ParentElement extends Polymer.Element {
static get is() { return "parent-element"; }
ready() {
super.ready();
this.$.myElement.addNew('key1', 'val-1');
this.$.myElement2.addNew('key2', 'val2');
console.log(this.$.myElement._myVar); // Expected to have {'key1': 'val-1'} but got {'key1': 'val-1', 'key2': 'val2'}. Why?
}
}
In the console log above, I expect to have {'key1': 'val-1'} but got {'key1': 'val-1', 'key2': 'val2'}. Why?
If you want to have a working example please refer to this plunkr:
http://plnkr.co/edit/7jSwTTBbBxD4qCbUoCGI?p=preview
JavaScript objects are by reference and when you define the default value it's a single object.
static get properties() {
return {
_myVar: {
type: Object,
value: {},
},
};
}
To avoid this you can define a function that will return a new object for each component instance.
static get properties() {
return {
_myVar: {
type: Object,
value: function() { return {}; },
},
};
}
While thinking through it I found a solution.
Test Element
class TestElement extends Polymer.Element {
static get is() { return "test-element"; }
static get properties() {
return {
_myVar: {
type: Object,
value: {},
},
};
}
ready() {
super();
_myVar = {}; // if initialized like this, the objects are not shared anymore.
}
addNew(key, val) {
this._myVar[key] = val;
}
}
customElements.define(TestElement.is, TestElement);
So below, logs what I expected:
class ParentElement extends Polymer.Element {
static get is() { return "parent-element"; }
ready() {
super.ready();
this.$.myElement.addNew('key1', 'val-1');
this.$.myElement2.addNew('key2', 'val2');
// Expected to have {'key1': 'val-1'} and got {'key1': 'val-1'} check! :)
console.log(this.$.myElement._myVar);
}
}

Render Object using lit.html

Scenario :
Inside my webComponent - health-check.js file I have:
static get properties() {
return {
plan:Object,
};
}
<div class="body"><p class="title">${this.plan.title}</p></div>
and
Inside my index.html file I pass json like below:
<health-check plan='{ "title" : "Solution Architecure",
"status" : "Approved" }'></health-check>
but it doesn't render title inside my health-check component
Problem :
Render Object Value with using lit.html?
Render title inside my health-check component.
Any ideas?
I think you cannot pass the object from html file because it's just html not lit-element or lit-html and lit-html seems not try to parse value in this case (Update I just found another way to define property see below). But of course you can still pass string and parse it inside element.
In index.html
<health-check planString='{
"title": "Solution Architecure",
"status": "Approved"
}'>
</health-check>
In health-check.js
class HealthCheck extends LitElement {
static get properties () {
return {
planString: String
}
}
render () {
return html`
<div class='body'>
<p class='title'>${JSON.parse(this.planString).title}</p>
</div>
`
}
}
But I would recommend to wrap you code in single entrypoint like my-app element
In index.html
<my-app></my-app>
In app.js
class App extends LitElement {
render () {
return html`
<health-check .plan='${{
title: 'Solution Architecure',
status: 'Approved'
}}'>
</health-check>
`
}
}
In health-check.js
class HealthCheck extends LitElement {
static get properties () {
return {
plan: Object
}
}
constructor () {
super()
this.plan = {}
}
render () {
return html`
<div class='body'>
<p class='title'>${this.plan.title}</p>
</div>
`
}
}
Update
You can define property type to tell lit-element how to serialize and deserialize.
class HealthCheck extends LitElement {
static get properties () {
return {
plan: {
type: {
fromAttribute (value) {
return JSON.parse(value)
}
}
}
}
}
render () {
return html`
<div class='body'>
<p class='title'>${this.plan.title}</p>
</div>
`
}
}
Note: This code written in lit-element 0.6.x and lit-html 0.11.x

Polymer paper-input imperative key-bindings

I'm trying to bind the enter key on a paper-input by specifying:
<paper-input class="flex" key-bindings="[[keys]]"></paper-input>
and the following properties on the host element:
keys: {
type: Object,
value: function() {
return {
'enter': this._addVariant
};
}.bind(this)
}
also tried this version:
keys: {
type: Object,
value: function() {
return {
'enter': '_addVariant'
};
}.bind(this)
}
Both do not work and I can't find any references on google. Does somebody know what I'm missing? Maybe the keyEventTarget?
Maybe this is a different way then you look for. But it works, what is the pressed key is:
<paper-input value="{{vall::input}}" on-keydown="_keyEvets" label="Arıyorum">
</template>
<script>
class MyTest extends Polymer.Element {
static get is() { return 'test-component'; }
static get observers() {return ['checkVall(vall)']}
checkVall(v){
console.log('vall :'+ v);
}
_keyEvets(k) {
console.log('_keyEvets',k.code);
}
}
Here is link to a sample

Does core Polymer 2.0 support two-way binding?

I seem to be having trouble getting two-way binding to work with Polymer 2.0. I'm keeping things minimal, only using Polymer.Element.
I define a parent component:
<dom-module id="example1a-component">
<template>
<xtal-fetch req-url="generated.json" result="{{myFetchResult}}"></xtal-fetch>
<div>fetch result:
<span>{{myFetchResult}}</span>
</div>
</template>
<script>
class Example1a extends Polymer.Element{
static get is(){return 'example1a-component'}
static get properties(){
return {
myFetchResult :{
type: String
}
}
}
}
customElements.define(Example1a.is, Example1a)
</script>
</dom-module>
The fetch class looks like:
class XtalFetch extends Polymer.Element {
static get is() { return 'xtal-fetch'; }
static get properties() {
return {
debounceTimeInMs: {
type: Number
},
reqInfo: {
type: Object,
},
reqInit: {
type: Object
},
reqUrl: {
type: String,
observer: 'loadNewUrl'
},
/**
* The expression for where to place the result.
*/
result: {
type: String,
notify: true,
readOnly: true
},
};
}
loadNewUrl() {
debugger;
}
ready() {
if (this.reqUrl) {
const _this = this;
fetch(this.reqUrl).then(resp => {
resp.text().then(txt => {
_this['_setResult'](txt);
_this['result'] = txt;
_this.notifyPath('result');
});
});
}
}
}
elements.XtalFetch = XtalFetch;
customElements.define(xtal.elements.XtalFetch.is, xtal.elements.XtalFetch);
Note that I am trying everything I can think of:
_this['_setResult'](txt);
_this['result'] = txt;
_this.notifyPath('result');
I see the result of the the fetch going into the result property of the fetch element, not into the parent.
Am I doing something wrong?
Yes, it does. Make sure to call super when you're overriding a method:
ready() {
super.ready(); // <-- important!
...
}
That's enough to make your code work (demo).
This is easy to forget, so the polymer-linter was recently updated to warn users about this.

polymer 2.0 two way binding

I am experimenting with Polymer 2.0 and have a simple class. It has an input text box that does not respond when changing its content. What is needed to reflect changes to text box to reflect as two way binding?
The code for the class follows.
<!-- Styles MUST be inside template -->
<style>
</style>
<div>
<input type="text" id="greeting" name="greeting" value="{{greeting}}"/>
<slot></slot>
{{greeting}}
</div>
// Extend Polymer.Element base class
class Polymer2Class extends Polymer.Element {
static get is() { return 'polymer-2-class' }
static get config() {
return {
properties: {
greeting: {
type: String,
value: "Hello",
notify: true
//observer: 'greetingChanged'
}
},
observers: [
'greetingChanged(greeting)'
]
}
}
constructor() {
super();
console.log('created');
}
connectedCallback() {
super.connectedCallback();
console.log('attached');
}
ready() {
this.addEventListener('click', (e)=>this.handleClick(e));
this._ensureAttribute('tabIndex', 0);
super.ready();
console.log('ready');
}
greetingChanged(greeting) {
if(greeting === undefined) {
console.log("greetingChanged: undefined");
} else {
console.log("greetingChanged: " + greeting);
}
}
handleClick(e) {
console.log("hamdleClick: " + e.type);
}
// Register custom element definition using standard platform API
customElements.define(Polymer2Class.is, Polymer2Class);
I assume you're expecting greeting to appear below the <input> exactly as you type it. You'll need to use two-way native binding on the <input>'s input event:
<input type="text" value="{{greeting::input}}">
codepen