Polymer callback as an attribute - polymer

Not so long ago I noticed that iron-ajax uses an attribut on-response="callbackFn" to execute once a response is received.
My question is simply how does this work?
I have a similar situation where I would like create a component that is able to take a callback as an attribute but I can't figure out how to do it.
Two things I noticed
When triggered the function is correctly bound to the Polymer element from which it came.
"callbackFn" is the name of a function. Not a polymer binding.
So I assumed iron-ajax must be doing some trickery in the background to bind the given function referenced by function name. When I looked at the source code though I don't see any handling of the 'on-response' attribute. none, zilch, nada. what gives?
I can see that there is a _boundedHandleResponse but that property does not seem to be bound to the on-response function at any point.
source

_boundedHandleResponse is a function which is value depends upon the _handleResponse function.
_boundHandleResponse: {
type: Function,
value: function () {
return this._handleResponse.bind(this);
}
}
So, if you check the _handleResponse function there is a 'response' event which is dispatched using the code :
this.fire('response', request, {
bubbles: this.bubbles,
composed: true
});
In polymer element we add event listeners using on-event annotations. For example on-tap, on-click. So, every time response is dispatched it will call the function defined as on on-response="callbackFn" which will call the "callbackFn" function.

Related

How to compare the value of a tagName and a string in Angular?

I try to find out when the tagname is "MAIN" an then to trigger some functions but unfortunately I steadily receive the error
This condition will always return true since the types "Event" and "Main" have no overlaps.
onMouseWheel(evt) {
event = evt.target.tagName;
while(event != 'MAIN')
event = evt.target.parentNode.tagName;
}
Any ideas how I could achieve this?
The angular approach to this is to attach the angular (wheel) directive to the element you're interested in and handle it that way.
<main (wheel)="onMouseWheel($event)"></main>
This way the wheel event is only triggering the handler when it occurs on elements you're interested in.

Stub Element Is Not Effective In The Ready Function

With Polymer 1.* and WCT, when testing my element <sp-veteran></sp-veteran> I am not able to stub out the methods ._getSpComboBox() and ._getItems() in the ready function. I get Error thrown outside of test function: this._getSpComboBox(...)._getItems is not a function.
Since it is in the ready function, I need to use the WCT api stub instead of sinon.stub since the later requires me to grab the element which I can not do before fixture().
Any suggestions?
original code:
_getSpComboBox: function() {
return Polymer.dom(this.$.veteran.root).querySelector('sp-combo-box');
},
ready: function() {
if (this.editMode) {
this._getSpComboBox()._getItems();
}
this.$.veteranNoAjax.read();
this._setStyle();
}
test:
<test-fixture id="sp-veteran">
<template>
<h2>edit veteran in edit mode</h2>
<sp-app>
<sp-toast></sp-toast>
<sp-veteran edit-mode></sp-veteran>
</sp-app>
</template>
</test-fixture>
before(() => {
replace('sp-app').with('fake-sp-app');
stub('sp-ajax', {read: ()=> entitiesMock});
const _getItems = ()=> entitiesMock;
stub('sp-veteran', {_getSpComboBox: ()=> _getItems});
Unfortunately testing ready in Polymer1 is kind of a pain, or at least I haven't found an easy way that doesn't have odd side-effects. Calling the ready method after you've attached your stubs/spies is always an option but as I mentioned it can cause some odd issues. This was alleviated in Polymer2 as ready is called by the first call of connectedCallback for your element, so you can create the element then bind your spies and manually add to trigger it, just don't forget to remove after.
In the case of DOM manipulation in a Polymer element, you should be using the attached lifecycle instead, this will solve your issue as I mentioned above for testing, but it also saves you a weird potential usage case in the future. Since ready only runs once for an instance of an element, any logic in your ready statement won't get re-run if that element is re-used later, instead if you put the logic in your attached lifecycle if that element is removed from the DOM then added again later in another location it will rerun it's logic to fetch it's new children.

How to use Polymer lifecycle hooks

I have a component that contains video. My component is nested in a dom-if and can disappear. When this happens the video (and it sound) keep playing.
Is there a way in which my component can detect that is has disappeared from the DOM? I have tried to use the 'detached' callback as described here: https://www.polymer-project.org/1.0/docs/devguide/registering-elements
Polymer({
is: 'my-component-with-video',
properties: {
// some properties
},
detached: function() {
console.log('Component detached');
// more code to stop video
},
but when my element is removed by the dom-if nothing happens, I don't see the console.log message. What am I doing wrong?
There are two scenarios possible here:
You want your element to be discarded and recreated fresh when the condition changes.
You want to keep it in the dom but freeze it.
In the first case you need to add the restamp attribute to the dom-if to make sure the template DOM is destroyed, not hidden. By default the dom-if stamps the template at first initialization and then hides it from the view if the condition becomes falsy.
In the second case, the suggestion given by Intervalia will not work, because the dom-if in "hide" mode does not detach anything from the DOM. Setting restamp attribute will make the detached callback run but then no point in pausing anything since the element will be discarded.
If you want to keep it in the DOM and freeze it's state you need to listen to dom-change event on the dom-if and run the .pause() accordingly.
No need for any workaround other than simply using your dom-if and rather than
<dom-if if="[[condietionBoolean]]">
<your-video-element id="giveanId"></your-video-element>
</dom-if>
write the if statement like below and so each time your condition changes, you check and make sure the video is paused if when you like. See below.
...
<dom-if if="[[_shouldShowVideo(conditionBoolean)]]">
<your-video-element id="giveanId"></your-video-element>
</dom-if>
...
Polymer({
is: 'my-component-with-video',
properties: {
conditionBoolean : {
type: Boolean,
},
},
_shouldShowVideo: function(conditionBoolean ) {
if (!conditionBoolean) this.$$(#yourVideoElementId).pause();
return conditionBoolean ;
}
});
In your detached function you need to get the Video Element and call .pause() on it.
You will probably also need to call .pause() when your condition changes that would cause the dom-if to remove the player.

Polymer: Determining when properties have loaded?

I know the attached function doesn't guarantee that properties will be loaded.
Right now, I've been using a computed Function that depends on properties but it's very clunky.
I've also used async but I find it to be inconsistent and arbitrary (just picking a random time to delay by).
I can't find anything about the correct way to deal with this problem.
You can use observers.
for example you
properties:{
someproperty:{type:Number,observer:'change'}
},
change:function(){
//this function called when the property changes.
}
for more information look at https://www.polymer-project.org/1.0/docs/devguide/properties.html
In addition to Alon's answer: if you want to observe several properties, then you can use something like this:
properties:{
someproperty1:{
type: Number,
}
someProperty2:{
type: Number,
}
},
observers: ['change(someproperty1, someproperty2)'],
change:function(property1, property2){
//this function called when the property changes.
},
Note, when using single observers, they will fire in the order they are set. So if someproperty1 and someproperty2 had specific observers binded to them, then the method that someproperty1 had will be executed first.
To read more about observers, read here:
https://www.polymer-project.org/1.0/docs/devguide/observers#multi-property-observers

Difference between HTML event and JavaScript events

There are many ways by which we can attach an event on an HTML element.
The first way is: HTML attribute
<div id="foo" onclick="print2()> My event is attached as HTML attribute</div>
The second way is using some library (say jQuery)
<div id="bar"> My event is attached using jQuery </div>
<script>
$("#bar").click(function() {
alert("Hi this is Bar");
}
</script>
I earlier thought that jQuery might be internally converting the event to corresponding HTML attribute but this does not happen. Check this http://jsfiddle.net/blunderboy/wp4RU/3/
I am logging all the attributes of foo and bar and see bar does not have onclick attribute.
Please explain.
There is nothing called HTML Event! The two types of events you have described are, inline events and unobtrusive events, and both are javascript events.
Inline Events
When you declare javascript code on the elements itself, then it becomes an inline event. You have a few common events (as attributes to HTML Elements) like onclick, onkeydown, onkeypress, onkeyup, and all of them start with on. One such example is:
Click Me!
Unobtrusive Events
We need to assign something to be performed when the event is triggered. The = symbol is always used in JavaScript to assign the value on the right to the method or property on the left.
The window is not the only object we can attach events to. We can attach events to any object within the web page provided that we have a way of uniquely identifying that object. One way of identifying an object is by giving it an ID and referencing it by document.getElementById("id_of_the_element").
Lets take the same example.
Click Me!
Instead of the onclick attribute, I have an ID in the same place, which uniquely identifies the HTML element <a>. Now I can get the ID inside javascript this way:
document.getElementById('clickme');
For this, I can attach an event handler, which doesn't differ much from the way we use the attributes. It just doesn't have the on in the front. In our previous example, we used onclick, but now we are just going to use click.
document.getElementById('clickme').click = functionName;
Here, the functionName refers to any javascript's function name, or an anonymous function. So, for the alert, if we create a function named alertme(), we can define this way:
function alertme()
{
alert('You clicked me!');
}
Now to attach the function to the element can be done this way:
document.getElementById('clickme').click = alertme;
Still feeling lazy, you can do it using the anonymous function way, which takes no name:
document.getElementById('clickme').click = function () {
alert('You clicked me!');
}
Hope you understood. :) Let me know for further clarification.