routing events with Polymer - javascript

I'm trying to wrap a button using polymer.
HTML:
<polymer-element name="sp-button" attributes="active">
<template>
<link rel="stylesheet" href="sp-button.css">
<button type="button"><content></content></button>
</template>
<script src="sp-button.js"></script>
</polymer-element>
JS:
Polymer('sp-button', {
active: false,
activeChanged: function() {
console.log('active ' + this.active);
}
});
I'm not sure how to allow user of that polymer element to listen to click events or hover events.
Also, in the case where two buttons are wrapped in that polymer element.

Users of your element can setup listeners like any normal HTML elements:
var button = document.querySelector('sp-button');
button.addEventListener('click', function(e) {
alert('from outside');
});
In a polymer-element, you can also capture the click event on the button using on-click, do something interesting with it, and/or fire another event:
<button on-click="clickHandler"><content>Button text</content></button>
...
clickHandler: function(e, detail, sender) {
alert('from inside');
this.fire('insideclick', {msg: 'from inside'});
}
Full demo: http://jsbin.com/uqubAGO/1/edit

The two-button case would look something like this:
<polymer-element name="sp-button" attributes="active">
<template>
<link rel="stylesheet" href="sp-button.css">
<button type="button" on-click="onSendClick">Send</button>
<button type="button" on-click="onReceiveClick">Receive</button>
</template>
<script src="sp-button.js"></script>
</polymer-element>
JS:
Polymer('sp-button', {
//...
onSendClick: function() {
this.fire('send');
},
onReceiveClick: function() {
this.fire('receive');
}
});
And then you could listen for those domain-specific events from the outside using addEventListener:
var button = document.querySelector('sp-button');
button.addEventListener('send', function(e) {
//...
});
button.addEventListener('receive', function(e) {
//...
});
The benefit to this method is that it hides away the implementation detail that the user clicked a button to cause the send event to occur. As far as the user of the sp-button element is concerned, it could have been a button click, a dropdown selection, a mouse hover, or any number of things that caused it. All the user cares about is your public API: that your element will fire a send event and a receive event when it wants the outside world to take those respective actions.

You'd probably want to stop the propagation of the click event if you were going to catch it and dispatch something new.

Related

Can you stop the jQuery focusout from firing when losing focus?

I've got an input box that I want to have save its value when it loses focus.
Pretty straightforward stuff and I'm able to get that done via jQuery's focusout event.
The problem however, is that I want to NOT fire the focusout event when the user clicks on an "X" icon next to the input box (example shown below)
So when the user tabs out of this input box, or clicks outside of the box or they click the green checkbox it should fire the focusout event... but if they click the red "X", it should NOT fire the focusout.
Is this possible to do with JavaScript / jQuery?
EDIT:
Some of you have recommended using event.relatedTarget, but it seems like that's returning null. I'll include my code in question for clarity:
// This is the cancel button with the red X
$("body").on("click", "span[id*='Cancel']", function(e)
{
showLabel($(this));
});
// this is the code to trigger the blur / focusout event
// trouble is that the "e.relatedTarget" is null
$("body").on("focusout", "input, textarea", function (e) {
if($(e.relatedTarget).is("span[id*='Cancel']")){
return false;
}
$(this).siblings("span[id*='OK']").trigger("click");
return false;
});
Here's a screen grab of me debugging this in JS (you'll see that the $(e.relatedTarget) selector returns nothing):
You can cancel de event returning the focus to previous element.
$('#inputText').focusout(function(event) {
setTimeout(function(){
if (document.activeElement.id == "btnCancel") {
$(event.target).focus();
return false;
}
},1);
});
This jsFiddle shows how to do it: https://jsfiddle.net/mpervh3t/
Hope it helps
You must use relatedTarget like this :
$(document).ready(function(){
$(".btn").on("focusout",function(e){
if($(e.relatedTarget).hasClass("red")) {
alert("You clicked on X button");
}
else {
alert("Fire Focus out")
}
})
})
Final code :
<!DOCTYPE html>
<html>
<head>
<style>
.gr {
color: green;
}
.red {
color: red;
}
</style>
</head>
<body>
<input type="text" class="btn"><button class="gr">Ok</button><button class="red">X</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script>
$(document).ready(function(){
$(".btn").on("focusout",function(e){
if($(e.relatedTarget).hasClass("red")) {
alert("You clicked on X button");
}
else {
alert("Fire Focus out")
}
})
})
</script>
</body>
</html>
As per my comment:
"I have had to do a similar type of thing with a blur event. Basically what I had to do was call a setTimeout on the blur to execute my function to save the data, and then on the click event of the X, cancel the timeout. That way, unless the X is clicked, the save function will fire. The delay can be pretty negligable, too."
I found the relevant code
var sliderTimeout = null;
$(".slider-trigger").on("blur", function () {
sliderTimeout = setTimeout(function () {
$(".slider").hide();
}, 100);
});
$(".ui-slider-handle").on("focus", function () {
clearTimeout(sliderTimeout);
});
Here is the full demo of the code in action. It does much more than demonstrate this, but if you examine the behavior of focusing/blur on the "margin" input, you will see that if you blur the margin input, the slider hides, but if you click on the slider, it cancels the hide and stays shown. It's the exact same concept, just a slightly different application.
Here, I did the thing.
https://jsfiddle.net/kowmLf2a/1/
In the blur event I target the related target. See if that related target is the item that I don't want to blur with. If it is then return false.
Code for reference:
$('#input').blur(function(event){
if($(event.relatedTarget).is('#bt2')){
return false;
}
alert($(this).val());
});

Polymer 1.0: How to pass an event to a child-node element without using <iron-signals>?

This Stack Overflow answer suggests using <iron-signals> to broadcast an event down the DOM tree to a custom element.
Below, I ask a different question.
Question
How do I:
pass an event down to a direct child node (custom element)
from a parent (custom element)
without using <iron-signals>?
Code
This is what I have so far. But it doesn't work.
parent-element.html
<dom-module id="parenet-element">
<template is="dom-bind">
<child-element></child-element>
<paper-button on-tap="_handleTap"></paper-button>
</template>
</dom-module>
<script>
(function(){
Polymer({
is: 'parenet-element',
_handleTap: function() {
this.fire("my-event");
}
});
})();
</script>
child-element.html
<dom-module id="child-element">
...
</dom-module>
<script>
(function(){
Polymer({
is: 'child-element',
listeners: {
"my-event": "foo"
},
foo: function(){
// Do stuff
}
});
})();
</script>
You definitely can. Without iron-signals you've got three options (that I currently know of):
Get the parent and have the child attach an event listener to the parent
The parent can have the child fire the same event
You mentioned that events only go up. You can then make the child element listen to the document firing that event (but I think this is bad)
Here's an example
<!doctype html>
<html>
<head>
<base href="http://polygit.org/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link href="polymer/polymer.html" rel="import">
</head>
<body>
<dom-module id="parent-element">
<template>
<child-element></child-element>
<button id="btn" on-tap="_fireParentEvent1">Fire 1!</button>
<button id="btn" on-tap="_fireParentEvent2">Fire 2!</button>
<button id="btn" on-tap="_fireParentEvent3">Fire 3!</button>
</template>
</dom-module>
<dom-module id="child-element">
<template>
<style>
:host {
display: block;
}
</style>
<span id="changeMe">Message</span>
</template>
</dom-module>
<parent-element></parent-element>
<script>
(function registerElements() {
Polymer({
is: 'parent-element',
listeners: {
'event-two': '_attachToChild'
},
_attachToChild: function(e) {
// the parent makes the child fire an event
var childElement = Polymer.dom(this.root).querySelector('child-element');
childElement.fire('event-two', e.detail);
},
_fireParentEvent1: function(e) {
// the parent fires an event
this.fire('event-one', {
message: 'hello'
});
},
_fireParentEvent2: function(e) {
this.fire('event-two', {
message: 'goodbye'
});
},
_fireParentEvent3: function(e) {
// the parent fires an event
this.fire('event-three', {
message: 'game over'
});
}
});
Polymer({
is: 'child-element',
listeners: {
'event-two': '_handleEventTwo'
},
ready: function() {
var parent = this.parentNode;
// the child listens to the parent's event
parent.addEventListener('event-one', function(e) {
this.$.changeMe.innerHTML = e.detail.message;
}.bind(this));
// listen to the document level event (since events travel up)
// but this option is difficult to control
document.addEventListener('event-three', function(e) {
this.$.changeMe.innerHTML = e.detail.message;
}.bind(this));
},
_handleEventTwo: function(e) {
this.$.changeMe.innerHTML = e.detail.message;
}
});
})();
</script>
</body>
</html>
With Polymer 1.2.4 as documented here we can use fire method options and force a child node (while still inside a parent element) to fire (and listen first of course) an event:
this.fire('test', {
user: {
name: 'Marios',
gender: 'male'
}
}, {
node: Polymer.dom(this.root).querySelectorAll('my-child-element'),
bubbles: false
});
We fired a custom event from an element but the emitter is the my-child-element so in there we can attach a listener in the listeners object. We also prevent the event bubbling so this event won't move upwards following the parents elements path. A typical listener could be:
Polymer({
is: 'my-child-element',
properties: {
...
},
listeners: {
'test': '_myHandler'
},
_myHandler: function(e) {
var user = e.detail.user;
...
}
});
#arthur in the Polymer Slack site says:
Events tend to go up the DOM tree. Going down, you can use a data binding or invoke a method.
Polymer Slack Site

Jquery.Change not working

I am having some trouble with $.change in jQuery.
HTML
<button class="btn">Reset</button>
<p id="chg" class="change">Click Me</p>
<div class="onchange"></div>
JS
$('.btn').on('click', function() {
$('.change').text('Click Me');
$('.onchange').text('');
});
$('.change').on('click', function() {
$('.change').text('Nearly There');
});
$('.change').on('change', function() {
$('.onchange').text("Nice One");
});
Here is the link to Codepen
Basically what should happen is when "Click Me" is clicked the text will change to "Nearly There" then straight after "Nice One" should appear below.
However this isn't happening, I've tried both
$('.change').on('change', function() {});
$('.change').change(function() {});
And neither work.
Note
The code I have supplied is my test code, and is all relevant to what I'm trying to achieve.
Update
I wasn't aware the .change only worked for form controls, which would explain why it wasn't working.
Solution
CreMedian - Suggested the solution that I was looking for.
$('.change').on('DOMSubtreeModified', function() { });
I have updated the CodePen for future reference.
As indicated in the comments, the .change() event does not work with div elements.
One way you could get the same effect is with the following code:
$('.change').bind("DOMSubtreeModified",function(){
//action you want when the '.change' object changes
});
Javascript MutationEvent is not widely supported, so be careful if implementing this in production code.
Reference Link: http://help.dottoro.com/ljrmcldi.php
$('.change').on('change', function() {
in your example, .change is a div, and divs dont raise change events when clicked.
You probably wanted to just update both elements from the click event
$('.btn').on('click', function() {
$('.change').text('Click Me');
$('.onchange').text('');
});
$('.change').on('click', function() {
$('.change').text('Nearly There');
$('.onchange').text("Nice One");
});
Try with DOMSubtreeModified event.
$('.btn').on('click', function() {
$('.change').text('Click Me');
$('.onchange').text('');
});
$('.change').on('click', function() {
$('.change').text('Nearly There');
});
$('.change').on('DOMSubtreeModified', function() {
$('.onchange').text("Nice One");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<button class="btn">Reset</button>
<p id="chg" class="change">Click Me</p>
<div class="onchange"></div>
Note: It will not supported by IE8 and older.
Demo in CodePen
The browser only fires change events for textbox, check/radio box and select list - all form elements. When something changes within your <div> or <p>, the browser does nothing to notify your javascript. Therefore, the listener .on('change' is not going to ever fire.
Here is a short lists of for elements that raise the event:
TextBox When Enter key is pressed
Radio/Check Box When the state is changed
Select List When the selected item is changed
Here is more on the event: Mozilla MDN onchange
do it like this
$('.change').text('Nearly There').trigger('change');
example
$('.btn').on('click', function() {
$('.change').text('Click Me');
$('.onchange').text('');
});
$('.change').on('click', function() {
$('.change').text('Nearly There').trigger('change');
});
$('.change').on('change', function() {
$('.onchange').text("Nice One");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<button class="btn">Reset</button>
<p id="chg" class="change">Click Me</p>
<div class="onchange"></div>

How to catch click on alertify.js notification

I need to catch the click (or hide) event of a alertify.js event. I set up the time to 0 in order to wait to the user for click in the message. Is there any way to attach a function to this event?
<link rel="stylesheet" href="alertify.js-0.3.11/themes/alertify.core.css" />
<link rel="stylesheet" href="jalertify.js-0.3.11/themes/alertify.default.css" id="toggleCSS" />
<script src="alertify.js-0.3.11/lib/alertify.min.js"></script>
<script>
alertify.log('test','',0);
</script>
You can attach an event to the document, and see if the element clicked on has a class that matches the class names attached to alertify logs (alertify-log).
For example, you could use code like this:
document.body.addEventListener('click', function (e) {
if(e.target.className.indexOf('alertify-log') > -1) {
console.log('Clicked on a log');
}
}, false);
Demo
Try
alertify.log('test',function(){
//function here
});

Capturing an event with jquery

I got a double event to manage. The two events are both "click" and they're handled with jquery. The html is the following:
<div class="siteMap" style="width:23%;">
<h5>Divisione Anticontraffazione</h5>
<span class="menufooter">
<span class="link1">Introduzione</span><br>
<span class="link2">Filosofia</span><br>
<span class="link3">Negozio online</span></span><br>
</div>
Then i have my click events which fires inside the menufooter span and inside every single link span. The code is like this:
$(document).ready(function() {
$('span.menufooter').click(function() {
//my code here
});
$("span.link1").click(function() {
//my code here
});
});
I need an event capturing action, the click on the span menufooter has to fire the event before the click on the span link1 fires. At this point, none of the two events is firing. Any hint?
How about only fire event on .menufooter
$(document).ready(function() {
$('span.menufooter').click(function(e) {
//my code here 1
// Capture Event Propagation
if ( $("span .link1").find(e.target).length>0 ){
//my code here 2
};
});
});
http://jsfiddle.net/9QLtG/
You could prevent the click from bubbling, and then trigger the click on the parent element so whatever is in that handler executes first (unless it's async)
$(document).ready(function () {
$('.menufooter').click(function () {
// fires before ....
});
$("span.link1").click(function (e) {
e.stopPropagation();
$('.menufooter').trigger('click');
// .... this fires, as it's triggered above
});
});
FIDDLE
I would have 1 click listener that listens to the wrapper. You can check the event's target to see if they actually clicked on a link and run code accordingly.
For example:
$(document).ready(function() {
$('.container').click(function(e) {
// Perform action when they clicked in the main wrapper,
// regardless of whether or not it was a link.
console.log("I clicked in the wrapper...");
if ($(e.target).hasClass('link')) {
// Perform action if they clicked on a link.
console.log("...but more specifically, on a link.");
}
});
});
Here's a fiddle that demonstrates this: http://jsfiddle.net/WaYFr/
Try this event.stopPropagation();
$("span.link1").click(function(event) {
event.stopPropagation();
...
});

Categories

Resources