How can I pass a Polymer Object beetwen 2 custom elements - html

I'm building a new webapp and I need to know how can I pass an object between 2 custom elements in polymer.
In the code below, I set the value of mydata in "my-child-element-1" and I need to see this value in "my-child-element-2"...I think that it's not very hard to do but i'm loosing my mind to find a good solution...
In my opinion, i should create a temporary object in "my-host-element" to share the value but i'm not convinced about this...
This is my code:
<dom-module id="my-host-element">
<template>
<my-child-element-1 mydata="{{mydata}}"></my-child-element-1>
<my-child-element-2 mydata="{{mydata}}"></my-child-element-2>
</template>
<script>
Polymer({
is: "my-host-element",
properties:
{
mydata: {
type: Object
}
}
});
</script>
</dom-module>
Thank you!!

Your example looks like it should work without the host element needing a property, if the property on the child elements are set up correctly. Remember that Polymer's data binding syntax is basically syntactic sugar around firing and handling custom events. So take a look in child element 1 and make sure that you've set the property to notify when changed. For example:
Polymer({
is: "my-child-element-1",
properties: {
mydata: {
type: Object,
notify: true // fire mydata-change CustomEvent on change
}
}
});

Yes, afaik it is correct to have the parent element act as the mediator between the children, which means it needs to have its own property even if its only used for that purpose.

Related

Polymer properties from chrome console

This is a very newbie question, but how can I reference a polymer property from Chrome's console? I know I can output (console.log) from javascript in my application with a reference to this.myProperty, but how do I get a reference to it straight from the console?
You get a reference to the element by some method, I use querySelector so if you have a paper-input with the class username-input you can do something like this
document.querySelector('paper-input.username-input').myProperty
and that would be the same as doing a this.myProperty from inside the element.
During development only I create a property on window that references my
element.
Polymer({
is: 'nav-bar',
properties: {
foo: {
type: String,
value: 'foo'
}
},
attached: function() {
// #TODO remove before merge.
window.navBar = this
}
})
And in your console:
// log property
navBar.foo
// call methods
navbar.doSomething()
to check properties or call methods on my element.
Granted, this pollutes the global scope but I do this only during development.
You can also select the element via querySelector('nav-bar') but it's tedious
to do so and you lose console autocompletion. Time is money.

Data Bindings across template tags

I'm wondering, is there a possibility to have databindings "out of" a template? Say I have a <template/>-Tag somewhere which I put into the slot of a different component - that component stamps it to its context. Then I want to bind data from the root element to the <template/>-Tag. Also, event bindings (on-x-changed) don't work, because you can't assign a function which is defined in the hosting component. Any ideas?
Example:
... host
{{boundData}}
<binding-component>
<template>
{{boundData}}
</template>
</binding-component>
I don't see changes when I observe boundData in the hosting component. Is there a way to get around this? Or is firing a custom event my only chance?
If you are looking for binding a property outside of polymer something like from index.html you may bind value with element. an example ; index.html
<dom-bind>
<template>
<binding-component bound-data="{{boundData}}"></binding-component>
</template>
</dom-bind>
<script>
// set a value a string, Number or Object etc.
// Optionally wrap this code into a listener ie;
// window.addEventListener('load', e=> { ...below code ... })
var boundData= document.querySelector('dom-bind');
boundData = {} //
</script>
Now in your binding-component element has a property as boundData
hope its helps or provide more code to understand better.
I've made it work the way dom-if does it, too. Like in dom-if (reference), I'm creating a Templatize-instance which then uses forwardHostProp to handle the "inside"-properties
this.__ctor = Templatize.templatize(template, this, {
mutableData: true,
forwardHostProp(prop, value) {
// handling item updates, item being the only property
// from within the binding component
// everything else is automatically bound by templatize
this.set(prop, value);
this.update(this.item);
},
});
this.__instance = new this.__ctor();
this.root.appendChild(this.__instance.root);
This all happens in connectedCallback.
Because the Templatize-instance is passed this, it's bound to the current context as well.
Good luck!

Data Binding - Host properties exist without declaration

I am reviewing polycasts ep 47 app code for blog-pages.html, specifically the data binding.
In blog-pages.html, the host properties isLoading, postsActive, and postsData were not declared as blog-pages host properties. How was this possible since they are blog-pages host properties?
<app-route route="{{route}}"
pattern="/posts/:slug"
active="{{postsActive}}"
data="{{postsData}}"></app-route>
<list-page category="{{category}}"
active={{listActive}}
loading="{{isLoading}}"></list-page>
<post-page post="{{postsData.slug}}"
active="{{postsActive}}"
loading="{{isLoading}}"></post-page>
<div class="overlay" hidden$="[[!isLoading]]">
<paper-spinner active="[[isLoading]]"></paper-spinner>
</div>
</template>
<script>
Polymer({
is: 'blog-pages',
observers: [
'_lockScroll(isLoading)'
],
_lockScroll: function(isLoading) {
if (isLoading) {
document.body.style.overflow = 'hidden';
} else {
document.body.style.overflow = 'visible';
}
}
});
</script>
</dom-module>
This is not best example of how polymer works.. For beginners it might be confusing. All these variables you wrote are defined by some polymer's elements.
For example in blog-app.html you can see app-route which has property data, tail and pattern. When you look inside app-route.html file, you can see that property tail has notify: true option. Which means, that it will propagate this property to parent element. So when you define binding in app-route like: <app-route tail="{{someProp}}"></app-route> then in your element there will be existing someProp property.
The same is in other files. For example take a look at isLoading. In blog-pages.html you can see there is binding to isLoading but it is nowhere defined. Well it is. In child element. So open list-page.html and take a look at <iron-ajax> where you can see loading="{{loading}}". And again the same. take a look inside iron-ajax.html and find property loading. What you see? again notify: true option. Which means, it get propagated to parent (list-page.html) and in list-page.html you can see there is also defined loading property which has notify:true so it gets propagated once more to parent (blog-pages.html) And because in blog-pages.html we have binding loading="{{isLoading}}" then it's saved into isLoading property
And this is how polymer works.. This example of some project is really hard to udnerstand and for beginners it's impossible. I hope that my explanation helped you a little bit, but I think you are now much more confused :-D.
If you have more questions, then ask. It's no problem to explain something

Pass data to another Polymer component

I am working on a dashboard, in which I have a search panel at the top (let's call it component A), where users can enter a query. The value of this input will change a lot of other components in the dashboard (not only components that are its direct descendants or siblings). I want to send the search value from component A to component B, which should then respond by performing some action with the input value.
I have tried a few things:
Directly calling the function in component B. Haven't been able to get that to work at all.
Manually setting B's local property value and using an observer to trigger a function call. I manager to set the value, but the observer does not trigger.
Using a global variable, which I can easily access across components, but I still can't trigger functions in specific components.
How can I best do this?
I'm relatively new to Polymer, so forgive me if my ideas aren't completely 'Polymerised' :)
Approach 1
<dom-module id="component-B">
<template>
</template>
<script>
Polymer({
is: 'component-B',
properties: {
id: '',
observer: '_idUpdate'
},
_idUpdate: function(){
console.log("HELLO");
}
});
</script>
</dom-module>
<dom-module id="component-A">
<template>
</template>
<script>
Polymer({
is: 'component-A',
idSearch: function() {
var id = this.$.search.value;
document.querySelector('component-B').properties.id = id;
},
});
</script>
</dom-module>
As you want to send data to multiple elements (which might not be siblings of the firing element) you can use any of these two methods
Use iron-signal to fire the signal and then in all the elements where you want the data use iron-signal tag to listen to the signal
<iron-signals on-iron-signal-<signal-name>="<function>"></iron-signals>
You can also use standard HTML method dispatchEvent to fire a signal and then add eventListeners in all the element where you want data.

Initializing dynamic default values for sub-elements on creation

I'm trying to work out how to make dynamic values available to sub-elements before the local DOM is initialised. I've created a custom element with a Google Map element embedded in it:
<dom-module id="place-picker">
<template>
<google-map api-key="..." />
</template>
</dom-module>
Polymer({
is: "place-picker",
created: function() {
this.apiKey = someFunctionToRetreiveApiKey()
}
})
I want to provide the API key to the google-map element immediately. It needs to be before the DOM is initialised because the google-map element attempts to load immediately. But Polymer's properties are not evaluated . Using data binding api-key="[[apiKey]]" doesn't work because I haven't declared it as a property.
I worked it out in a slightly hacky fashion. The context of the created callback is a raw HTML element, so you can simply set its attribute, which for some reason is evaluated as a property before local DOM creation. I ended up with:
# CoffeeScript
Polymer
is: "place-picker"
properties:
googleWebApiKey:
type: String
created: ->
#setAttribute("google-web-api-key", functionToRetrieveApiKey())
# Slim HTML
template
google-map api-key="[[googleWebApiKey]]"
I prefer to use the "value" key of the properties object to set the value, but is should work similar to the created function mentioned above, you could also you the computed key.
<dom-module id="place-picker">
<template>
<google-map api-key="[[apiKey]]" />
</template>
</dom-module>
Polymer({
is: "place-picker",
properties : {
apiKey : {
type: String,
value: functionToRetrieveApiKey()
}
}
})