Handlers delegation in polymer 1.0 - javascript

UPDATE: The response and error events no longer bubble. https://github.com/PolymerElements/iron-ajax/releases/tag/v1.0.5
what a pity.
Original question:
I wanted to create custom ajax component based on iron-ajax to add couple of custom headers and handlers. While custom element inheritance is not yet implemented I just added iron-ajax to my-ajax and was going to delegate all api to the iron-ajax, this worked fine with generateRequest.
But when it got to handler methods I noticed that it works without any delegation. There is no on-response handler defined in my-ajax elt but handleResponse is still invoked.
As far as I understand, this happens because Polymer.Base._addFeature._createEventHandler (polymer.html:345)
uses 'this', which is top-level elt, as 'host' for handler methods definitions.
So the question is: is it bug or feature?
The example code:
<link rel="import" href="https://raw.githubusercontent.com/Polymer/polymer/master/polymer.html">
<link rel="import" href="https://raw.githubusercontent.com/PolymerElements/iron-ajax/master/iron-ajax.html">
<dom-module id="my-ajax">
<template>
<iron-ajax
id="ironAjax"
url="http://echo.jsontest.com/key/value/otherkey/othervalue"
handle-as="json"
debounce-duration="300"
>
</iron-ajax>
</template>
<script>
Polymer({
is: "my-ajax",
generateRequest: function(){
this.$.ironAjax.generateRequest();
}
});
</script>
</dom-module>
<dom-module id="my-elt">
<template>
<button on-click="buttonClick">Button</button>
<my-ajax
id="myAjax"
on-response="handleResponse">
</my-ajax>
</template>
<script>
Polymer({
is: "my-elt",
buttonClick: function(){
this.$.myAjax.generateRequest();
},
handleResponse: function(event) {
alert('got response');
}
});
</script>
</dom-module>
<my-elt></my-elt>

Most events bubble, so you are just seeing the response event bubble out of my-ajax to the my-elt scope via the handler placed on the my-ajax instance. This happens identically to a click event bubbling from a lower scope to an upper scope.
So answer is: "feature" (of the web platform, more than Polymer itself).

Related

How to send date from one component to another component by onclick function using observers on Polymer 1.0? (without using local-storage)

I want to send the 'categorylist' from 'submenu-list.html' to the component 'category.html' by the onclick function 'response' using observer. how can I do it (without using local-storage)? (Kindly show by editing the code)
/* submenu-list.html */
<link rel="import" href="../../bower_components/polymer/polymer.html">
<dom-module id="submenu-list">
<template>
<paper-menu>
<paper-item><a onclick="response">My Menu Items</a></paper-item>
</paper-menu>
</template>
<script>
Polymer({
is:'submenu-list',
properties: {
categorylist: {
type: Array,
value:[]
}
},
response: function() {
}
})
</script>
</dom-module>
/* category.html */
<link rel="import" href="../../bower_components/polymer/polymer.html">
<dom-module id="category">
<template>
</template>
<script>
Polymer({
is:'category',
})
</script>
</dom-module>
well the quick answer is you can`t. At least from the information you gave. Since these components seem not to be connected somehow there is no direct way to communicate between components. Possible Solutions are you write the Information into the Local Storage but as you stated you don´t want to do that. Other solutions might be redux or a rest Service but i guess thats also not an option. The last suggestion is that these both Components are siblings? then you could just use Polymer default databinding? for instance:
<submenu-list categorylist="{{categorylist}}"></submenu-list>
<category categorylist="{{categorylist}}"></category>
and then in both components add:
categorylist: {
type: Array,
value:[],
notify:true,
observer: '_categorylistChanged'
}
Now you have to implement the _categorylistChanged function which will be called when categorylist was changed.
_categorylistChanged: function(newValue, oldValue){
//do something
}
Dont´t forget when you want to change categorylist to call
this.set('categorylist', //your new value)
Otherwise the observers won´t be triggered.

Using third-party dependencies in polymer (pikadate)

I'm creating a polymer datepicker using pikaday. Sadly it seems like I got something wrong.
I'd like to import pikaday.js and pikaday.css the right way.
At first I had a simple script-tag below my closing dom-module-tag, like
</dom-module>
<script src="../../pikaday/pikaday.js"></script>
<script>
Polymer({
//....
This way, the datepicker was created as expected. But after reading this SO-Thread I was under the impression I was supposed to import the js-file like this:
<link rel="import" href="../../paper-input/paper-input-behavior.html">
<link rel="import" href="../../paper-input/paper-input-error.html">
<link rel="import" href="../../pikaday/pikaday.js">
//more imports....
But after "fixing" my import, the file pikaday.js seems not to be visible from inside my component:
Uncaught ReferenceError: Pikaday is not defined
Furthermore I'm confused about using external css. After reading this guide it seems like I was supposed to copy & paste the contents of the provided css-file into a my-datepicker-style.html and to import it into my template like this:
<dom-module id="my-datepicker">
<template>
<style include="my-datepicker-style"></style>
<style>
:host {
//more css
I'm confused about the need to copy & paste existing code.
Until ES6 imports are more common, you need some kind of workaround for referencing dependencies.
The problem with <script> tag is that when it appears multiple times, it will be processed multiple times. This is not true for <link rel="import">. Same href will be processed only once.
You cannot, however, import javascript directly. The trick is to create pikaday-import.html file with the script reference
<script src="../../pikaday/pikaday.js"></script>
You then import that in your element's html
<link rel="import" href="pikaday-import.html" />
<dom-module id="my-datepicker"></dom-module>
This is the technique for example the <marked-element> uses.
This way instances of <my-datepicker> load pickaday only once. Unfortunately, if there are other components which reference it, you could end up loading the dependency multiple times.

Providing data to Polymer elements

I want to have a single source provide all of my data. A model if you will, and I want my elements to be able to utilize that data, but never change it (one way data-binding). How can I go about this? Should I add the data as a behavior?
I tried doing this in my document:
<script type="text/javascript" src="/data.js"></script> <!-- defines a global object named DATA -->
<my-element data="{{DATA}}"></my-element>
And this inside my-element.html
<dom-module id="my-element">
<template></template>
<script>
Polymer({
is: 'my-element',
properties: {
data: Object
},
ready: function () {
console.log(this.data);
}
});
</script>
</my-element>
but it doesn't seem to work, the value of this.data is literally "{{data}}".
I am looking for a better solution than wrapping the element declaration inside a dom-bind template
To use data binding, you either need to use it inside a polymer element, or inside a dom-bind element. See the explanation here. If you use dom-bind, it's only a case of using the js to set DATA to a property on the dom-bind template element, 'data' maybe, which would be little code.
Essentially, you can't set a global and expect data binding to know about it. You need to either tell dom-bind about it, or the element about it, by setting a property on the element, perhaps using behaviour, as you suggested, or using Mowzer's approach.
An example of using a behaviour would be:
<link rel="import" href="databehaviour.html">
<link rel="import" href="bower_components/polymer/polymer.html">
<dom-module id="an-ele">
<style>
</style>
<template>
<div>{{data.sth}}</div>
</template>
<script>
Polymer({
is: "an-ele",
behaviors: [DataBehaviour]
});
</script>
</dom-module>
With the behaviour being:
<script>
DataBehaviour = {
ready: function() {
this.data = {'sth':'A thing! A glorious thing!'};
}
}
</script>
But in your case, this.data would be set to your DATA global.
Use <iron-meta> [link] or <iron-localstorage>] [link] to share variables between elements or the main document.

Using Bootstrap's Tooltip within Polymer

I'm using a simple Polymer object with Bootstrap and I want to use the tooltip (as described here) within the Polymer object.
Let's say this is my polymer:
<link rel="import" href="../components/bower_components/polymer/polymer.html">
<polymer-element name="my-polymer">
<template>
<div data-toggle="tooltip" tooltip="with a tooltip">I am a simple Polymer</div>
</template>
<script>
Polymer({
domready: function() {
//$((this.shadowRoot || this).querySelector('[data-toggle="tooltip"]')).tooltip(); // not wotking
//$("[data-toggle='tooltip']").tooltip(); // not wotking
}
});
</script>
</polymer-element>
By design, in order to get the tooltip wotking we need to execute this command:
$("[data-toggle='tooltip']").tooltip();
But because of the shadow DOM I can't execute this command.
How can I get this code to work with the Bootstrap tooltip?
I know this doesn't answer your question directly but more giving you a "Polymer" alternative. Polymer 0.5 has a tooltip element (they look a lot like the example tooltips on the link you posted)
https://www.polymer-project.org/0.5/docs/elements/core-tooltip.html

polymer - loading core ajax inside an element

After checking core-ajax usage in the polymer website I decided to add ajax functionality using core-ajax inside my element/widget.
test-view.html
<link rel="import" href="bower_components/polymer/polymer.html">
<link rel="import" href="bower_components/core-ajax/core-ajax.html">
<polymer-element name="test-view" attributes="url">
<core-ajax id="elemAjax" url="{{url}}" handleAs="json"></core-ajax>
<template>
<div id="body"></div>
</template>
<script>
Polymer('test-view', {
ready: function() {
var ajax = this.$.elemAjax; // this line
ajax.addEventListener('core-response', function() {
console.log(this.response);
});
}
});
</script>
</polymer-element>
Unfortunately, the "ajax" variable in my script returns "undefined". How can I load ajax inside an element using core-ajax?
Side Question: Is the "id" attribute inside a polymer element only accessible inside the polymer element?
Three main problems:
The core-ajax must go inside the template, so it's part of each instance's DOM (this is why ajax was undefined).
You need the auto attribute on the core-ajax (otherwise, you must call the go() method on the core-ajax to send the request).
Your event handler uses this but is not bound to the element scope. Suggest you use event delegation instead of addEventListener.
See the new example below. The other (less important) tweaks I made:
Remove id from core-ajax, we don't need to reference it anymore.
Remove the polymer.html import, core-ajax already imports it.
Remove the test-view parameter to Polymer(), it's not necessary when defining an element inside an import.
Modified example:
<link rel="import" href="bower_components/core-ajax/core-ajax.html">
<polymer-element name="test-view" attributes="url">
<template>
<core-ajax auto url="{{url}}" handleAs="json" on-core-response="{{ajaxResponse}}"></core-ajax>
<div id="body"></div>
</template>
<script>
Polymer({
ajaxResponse: function(event, response) {
console.log(response);
}
});
</script>
</polymer-element>
Even better is to avoid events altogether and data-bind directly to the response data. Example:
<link rel="import" href="bower_components/core-ajax/core-ajax.html">
<polymer-element name="test-view" attributes="url">
<template>
<core-ajax auto url="{{url}}" handleAs="json" response="{{response}}"></core-ajax>
<div id="body"></div>
</template>
<script>
Polymer({
responseChanged: function(oldValue) {
console.log(this.response);
}
});
</script>
</polymer-element>

Categories

Resources