Using datalist from local DOM in polymer - javascript

My custom component 'autocomplete-input' should provide an autocomplete functionality. I am using the 'list' attribute of 'paper-input'. The value of the 'list' attribute has to be the 'id' of a 'datalist'.
This works fine, as long as I instantiate only one 'autocomplete-input' element. If there are multiple instances of the 'autocomplete-input' element, they all show the same autocomplete proposals. I guess this is because the 'list' attribute does not use the local DOM and therefore uses the first 'datalist' with that particular 'id'. How can I avoid this?
The 'autocomplete-input' element:
<dom-module id="autocomplete-input">
<template>
<datalist id="autocomplete">
<template is="dom-repeat" items="{{proposals}}">
<option data-value$="{{item.value}}">{{item.content}}</option>
</template>
</datalist>
<paper-input id="input" list="autocomplete" label="{{header}}" value="{{content::input}}"></paper-input>
</template>
<script>
Polymer({
is: 'autocomplete-input',
properties: {
header: String,
content: String,
proposals: Array
}
});
</script>
</dom-module>

Use a global counter and add it to your id
<dom-module id="autocomplete-input">
<template>
<datalist id$="[[autocompleteId]]">
<template is="dom-repeat" items="{{proposals}}">
<option data-value$="{{item.value}}">{{item.content}}</option>
</template>
</datalist>
<paper-input id="input" list$="[[autocompleteId]]" label="{{header}}" value="{{content::input}}"></paper-input>
</template>
<script>
Polymer({
is: 'autocomplete-input',
properties: {
header: String,
content: String,
proposals: Array,
}
}),
autoCompleteId: function() {
return this.autocompleteId = this.autocompleteId || ++globalId;
// see linke below to figure out how to use globals
}
</script>
</dom-module>
See Polymer 1.0 Global Variables for more details about globals in Polymer (My JS isn't good enough because I use Polymer only from Dart)

Related

vue.js and slot in attribute

I'm trying to build a vue.js template that implements following:
<MyComponent></MyComponent> generates <div class="a"></div>
<MyComponent>b</MyComponent> generates <div class="a" data-text="b"></div>.
Is such a thing possible?
EDIT
Here is the best I can reach:
props: {
text: {
type: [Boolean, String],
default: false
}
},
and template
<template>
<div :class="classes()" :data-text="text">
<slot v-bind:text="text"></slot>
</div>
</template>
but the binding does not work, text always contains false.
You can use the mounted() method to get text using $slot.default property of the component to get the enclosing text. Create a text field in data and update inside mounted() method like this :
Vue.component('mycomponent', {
data: () => ({
text: ""
}),
template: '<div class="a" :data-text=text></div>',
mounted(){
let slot = this.$slots.default[0];
this.text=slot.text;
}
});
Note: It will only work for text, not for Html tags or components.
You're mixing slots and properties here. You'll have to pass whatever you want to end up as your data-text attribute as a prop to your component.
<MyComponent text="'b'"></MyComponent>
And in your template you can remove the slot
<template>
<div :class="classes()" :data-text="text"></div>
</template>
Another thing: it looks like your binding your classes via a method. This could be done via computed properties, take a look if you're not familiar.
You can try this.
<template>
<div :class="classes()">
<slot name="body" v-bind:text="text" v-if="hasDefaultSlot">
</slot>
</div>
</template>
computed: {
hasDefaultSlot() {
console.log(this)
return this.$scopedSlots.hasOwnProperty("body");
},
}
Calling
<MyComponent>
<template v-slot:body="props">
b
</template>
</MyComponent>

PolymerJS simple databinding. How to output properties on screen?

I'd like to output the value I have saved in my properties.
Plunker Link
This is a simple demo-element.html. And I want to just show the title.
But neither {{title}} nor {{this.title}} works.
<dom-module id="demo-element">
<template>
<style>
:host {
display: block;
}
</style>
<h1>'title' in properties not showing</h1>
<h2>{{this.title}}</h2>
</template>
<script>
Polymer({
is: 'demo-element',
properties: {
title: 'This is a regular Demo Title'
}
});
</script>
</dom-module>
How do I output my properties on the screen?
I am searching for the equivalent of vue's {{ $data | json }}
Plunker Link Again
this is implied when data-binding. So this
<h2>{{this.title}}</h2>
becomes this
<h2>{{title}}</h2>
One possible solution is to assign a value property to my title property like this:
<dom-module id="demo-element">
<template>
<h1>'title' in properties not showing</h1>
<h2>{{this.title}}</h2>
</template>
<script>
Polymer({
is: 'demo-element',
properties: {
title: {
type: String,
value: 'This is a regular Demo Title'
}
}
});
</script>
And then output the value referencing just the title, without the this, like this:
<h2>{{ Title }}</h2>
Here is the working Plunker:
Plunker Link
I still wonder if there is an alternative to vue's {{ $data | json }} method?

Event Handling between parent and child page in polymer 1.0

I have a parent polymer element called parent-page and a child element called child-page.
parent-page calls child page and passes an array with it. for e.g, in parent page:
<child-page items={{itemsArray}}></child-page>
Now, on the basis of certain activity child page fires an event with a new array.
eg, in child page:
this.fire('eventPerformed', newArray);
This array is being listened by the parent page and received with expected values.
Now, I want to pass that new array to the child page such that the child-page is rendered according to the new array.
How to achieve it?
Edit: my child page looks like this.
<dom-module id="child-page">
<style>
</style>
<template>
<template is="dom-repeat" items="{{itemArray}}" as="fooditem">
<div class="horizontal layout">
<div>{{fooditem.quantity}}</div>
<div>{{fooditem.name}}</div>
</div>
</template>
<paper-button on-click"changeArray"> ChangeArray</paper-button>
</template>
<script type="text/javascript">
Polymer({
is:'child-page',
properties:{
itemArray:Array
},
changeArray:function(){
this.itemArray=<<Some new Array>>
this.fire('eventPerformed',newArray);
}
});
</script>
</dom-module>
Is there any way I can call the template repeat with the new array in the same child page? Or do I have to fire an event to the parent-page and call the child page again? How to achieve it either way?
The child-page re-renders its template is="dom-repeat" items="[[itemArray]]" automatically whenever its itemArray property was updated.
Just add notify: true to the itemArray property in child-page to enable two-way-binding with the parent-page element. Then the parent-page is also notified whenever the item-array of child-page has changed (see the Polymer documentation on this topic).
Here is a small complete example:
<dom-module id="child-page">
<template>
<template is="dom-repeat" items="[[itemArray]]">
<div>[[item]]</div>
</template>
<div on-click="_changeArray">Change</div>
</template>
<script>
Polymer({
is: 'child-page',
properties: {
itemArray: {type: Array, notify: true}
},
_changeArray: function() {
this.itemArray = [4,5,6,7,8,9];
}
})
</script>
</dom-module>
<dom-module id="parent-page">
<template>
<span>Item count: </span><span>[[itemArray.length]]</span>
<child-page item-array="{{itemArray}}"></child-page>
</template>
<script>
Polymer({
is: 'parent-page',
properties: {
itemArray: {type: Array, value: [1,2,3]}
}
})
</script>
</dom-module>
<parent-page></parent-page>
Btw. note my usage of {{...}} and [[...]]. Use curly braces for two-way bindings and square brackets for one-way bindings.

Bind a value between a parent and a child element where child element is created using javascript

Using Polymer, does anyone know how to bind a value between a parent and a child element?
Below is my attempt however it doesn't work.
Note: child-component needs to be created using JavaScript.
<dom-module id="host-component">
<template>
<div>{{sharedValue}}</div>
<div id="childComponentContainer">
<!-- CHILD-COMPONENT GETS CREATED HERE -->
</div>
</template>
<script>
Polymer({is:'host-component',
properties:{
sharedValue:{
type: String,
notify:true,
observer: 'sharedValueChanged'
}
},
attached: function(){
var newElement = document.createElement('child-component');
Polymer.dom(this.$.childComponentContainer).appendChild(newElement);
},
sharedValueChanged:function(d){
console.log(d, ", said the child");
}
});
</script>
</dom-module>
<dom-module id="child-component">
<template>
<input is="iron-input" bind-value="{{sharedValue}}" />
</template>
<script>
Polymer({is:'child-component',
properties:{
sharedValue:{
type: String,
notify:true,
reflectToAttribute:true,
}
},
});
</script>
</dom-module>
Thanks :)
After re-reading Polymer's documentation (many times) I found a section about how Two-way data-binding events work where by on each change Polymer fires a DOM event. From this I came up with the work around below.
You'll notice this version also has two way binding so the host can change the child's value and the child can change the host's value!
<dom-module id="host-component">
<template>
<div>Host: <span>{{sharedValue}}</span></div>
<div>Host: <span><input is="iron-input" bind-value="{{sharedValue}}" /></span></div>
<div id="childComponentContainer">
<!-- CHILD-COMPONENT GETS CREATED HERE -->
</div>
</template>
<script>
Polymer({is:'host-component',
properties:{
sharedValue:{
type: String,
notify:true,
value: "Unchanged",
observer: 'sharedValueChanged'
}
},
attached: function(){
this.$.childComponent = document.createElement('child-component');
var host = this;
//Listens to the child's sharedValue. When changed it will update host's sharedValue.
this.$.childComponent.addEventListener("shared-value-changed", function(e){
host.sharedValue = this.sharedValue;
});
Polymer.dom(this.$.childComponentContainer).appendChild(this.$.childComponent);
},
//Observes the hosts's sharedValue. When changed it will update child's sharedValue.
sharedValueChanged: function(value){
if (this.$.childComponent) {
this.$.childComponent.sharedValue = value;
}
}
});
</script>
</dom-module>
<dom-module id="child-component">
<template>
<div>Child: <span>{{sharedValue}}</span></div>
<div>Child: <span><input is="iron-input" bind-value="{{sharedValue}}" /></span></div>
</template>
<script>
Polymer({is:'child-component',
properties:{
sharedValue:{
type: String,
notify:true,
value:"Unchanged",
reflectToAttribute:true,
}
}
});
</script>
</dom-module>

How to get composed DOM of Polymer Web Component?

I'm using Polymer 0.8-preview.
For example, I have the following component:
<dom-module name="greeting-tag">
<template>
<ul>
<template repeat="{{s in salutations}}">
<li>{{s.what}}: <input type="text" value="{{s.who}}"></li>
</template>
</ul>
</template>
</dom-module>
<script>
Polymer({
is: 'greeting-tag',
ready: function () {
this.salutations = [
{what: 'Hello', who: 'World'},
{what: 'GoodBye', who: 'DOM APIs'}
];
}
});
</script>
Is it possible to get the composed DOM (as JS object or text) at some point of the component life cycle?
For the example above I would like to get
<ul>
<li>Hello: <input type="text" value="World"></li>
<li>GoodBye: <input type="text" value="DOM APIs"></li>
</ul>
In other words, I need the result of processed template.
Polymer 0.8 is not yet released. Furthermore, there is clearly stated in the documentation draft, that array notification is in high flux.
The code you provided has a bundle of glitches:
dom-module should be identified by id, not by name.
template repeat is gone. One should use <template is='x-repeat'
items="{{salutations}}"> instead. Since array reflection is not yet released/frozen, I eliminated it from the example code below.
Putting everything together:
<dom-module id="greeting-tag">
<template>
<p>{{caption}}</p>
</template>
</dom-module>
<script>
Polymer({
is: 'greeting-tag',
properties: {
caption: {
type: String,
reflect: true
}
},
ready: function () {
this.caption = 'Welcome here',
console.log(this.innerHTML);
}
});
</script>
The latter will print:
//⇒ <p style-scope="greeting-tag">Welcome here</p>
AFAIK, there is no ready-to-use method to do the same with arrays yet.

Categories

Resources