Using $(this) does not work - javascript

I am trying to get a script running that adds some events to a class.
I want these events only to be added to one specific DIV among this class. I am using pep.js:
$( ".drag" ).pep({
start: function() {
$(".drag").addClass('color');
$('.drag').next(".text").fadeIn("slow");
$(".text-video").fadeOut("fast");
},
stop: function() {
$('.drag').removeClass('color');
$('.drag').next(".text").fadeOut("slow");
}
});
This works, but it triggers all .drag items at onceā€¦ And I want only the one I am dragging to have added all the events.
I tried to write it with:
$(".drag", this).addClass('color');
or:
$(this).addClass('color');
or:
$(this.element).addClass('color');
But it all didn't work.
Does someone have an idea?
UPDATE:
I made a JSFiddle that hopefully explains my problem.
https://jsfiddle.net/ke6d5r1h/
As you see, the .color class for example is not only added to the DIV that is dragged, but also to the other. This is what I want to change.

Using console.log(arguments) in the event handlers, I was able to determine that the handlers are passed two arguments: the event object, and an object containing context. The context has a property $el, which is a jQuery object for the event target.
start: function(e,a) {
a.$el.addClass('color');
a.$el.next(".text").fadeIn("slow");
$(".text-video").fadeOut("fast");
},
https://jsfiddle.net/85tffqhL/
e.target would also give you a reference to the element.

Related

JavaScript: Get all elements which have an event bind to them

Is there a way in JavaScript to get all elements on the page which have an event bind to them.
I know you can get all events an a particular event, but is there a way the all elements?
Thank you all for your help. I found this great snippet which loops over all elements on page and adds each elements which has an event bind to it to an array.
var items = Array.prototype.slice.call(
document.querySelectorAll('*')
).map(function(element) {
var listeners = getEventListeners(element);
return {
element: element,
listeners: Object.keys(listeners).map(function(k) {
return { event: k, listeners: listeners[k] };
})
};
}).filter(function(item) {
return item.listeners.length;
});
Full credit to Dan: https://gist.github.com/danburzo/9254630
As suggested in the comments, you can use getEventListeners(document) on chrome dev tools, but if you want to use this inside your code, a possible solution is using a custon function to register the events and mantaining a list of elements that have events atached.
Code not ready to use, just an example
let elements = [];
function addEventListener(elem, event, cb) {
elem.addEventListener(event, cb);
elements.push(elem);
}
You will of course need to remove the element when the event is removed.
If you don't have control over all code that register events (which is quite common) you can monkey path the Node.prototype.addEventListener function. Which is not recomended (you can read more here). But it is a possibility...

why doesn't my jquery click function work after changing element values?

So I'm making a small quiz app with object oriented JS using Object.create cloning method. I have an ol, and a function called showVals() that populates it with lis. That seems to be working fine. What I'm having trouble with is: my li click function to give the attr of ".selected' class seems to work intitially, but after I click to proceed and qn2.showVals() is called it is no longer giving the lis a class of selected when clicked.
The data for qn2 is there. Everything looks normal, except for the click function no longer working (giving the lis the class).
$(document).ready(function(){
qn1.showVals();
qn1.setAns(1); // calling question1 answer for now
$('li').click(function(){
$('li').removeAttr("class");
$(this).attr({"class": "selected"});
});
$('.proceed').click(function(e){
e.preventDefault();
if ($('.selected').html() == qn1.ctAns) {
if (confirm("You are correct")){
qn2.showVals();
qn2.setAns(3);
};
};
});
});
var qn1 = {
title:"The Mouth of Sauron",
qn: "How did 'The mouth of Sauron' meet his demise?",
img: "images/mouth-sauron.gif",
ans: ["Shot in the back", "Beheaded", "Drowned in a swamp", "Sacrificed"],
setAns: function(x) {
this.ctAns = this.ans[x]; //setting correct answer
},
showVals: function(){
$('#slide-title').text(this.title);
$('.question-box > p').text(this.qn);
$('#obj-img').attr("src", this.img);
$('ol').html('<li>'+this.ans[0]+'</li>'+'<li>'+this.ans[1]+'</li>'+
'<li>'+this.ans[2]+'</li>'+'<li>'+this.ans[3]+'</li>')
}
}
var qn2 = Object.create(qn1);
qn2.title = "Golemn";
qn2.qn = "What this dude's name?";
qn2.ans= ["Golemn", "Gimli", "Goober", "Poop"]
qn2.img = "images/golemn.gif";
This is likely because your li elements are dynamically added.
You should try using jQuery on(), which allows you to bind an event handler to the parent element which must already exists in your DOM, and then you can specify the child/descendant selector that will call the event handler. This child element may still be non-existent at the time you do the event binding. In such a case, you call on() like:
$('ol').on('click', 'li', function () {...});
where ol already exists.
Alternatively, you could always bind your click handler to your dynamically generated li elements after you have added them to your DOM. Although I think that is more processor-time consuming as I assume you have to do this for all quiz questions you ask your user.

Undelegate single event

I am having trouble stopping a click event on a dom element in a UL, essentially in the itemClicked method I want to undelegate the click event on the single element. When an item in a list is clicked, however that item still fires a click event despite have the none value. Is there a way to use undelegate for just the individual element clicked? I am at a loss as to why and any help is greatly appreciated.
App.Views.AttributeSelectorView = Backbone.View.extend({
itemClicked: function (event) {
var $target = $(event.target);
this.trigger('itemClicked', $target.data('attr'), $target.text());
this.undelegateEvents();
},
events: {
'click [role=menuitem]': 'itemClicked'
}
});
attributeSelectorView.on('itemClicked', function(attribute, display){
// .remove attribute
query.add({
attribute: attribute,
display: display
}, {
merge: true
});
});
try using stopListening, it Tell an object to stop listening to events.
itemClicked: function (event) {
var $target = $(event.target);
this.trigger('itemClicked', $target.data('attr'), $target.text());
this.stopListening();
}
You are setting the pointer-events attribute in the click handler itself. The click event has already happened by the time you change its target element's style.
You need to set the property before a click occurs for it to take effect.
Or, if you know which elements you want to ignore clicks on, you could add logic in your click handler:
itemClicked: function(e) {
if(!shouldIgnoreThisTarget) {
this.trigger('...')
}
}
In many ways this is better. It brings the click behaviour into one place and reduces coupling between your CSS and JavaScript.
pointer-events only effects style - so it won't affect the functionality of an element (ie. javascript events).
If you want to prevent the default click behavior in javascript, you can return false from the click handler, or set event.preventDefault to true

.class selector not working

I'm working in a card game system that the player can select the card by clicking on it and then select the place to put it on. My problem is that when the player click on the target place, nothing happens.
This is my try: http://jsfiddle.net/5qMHz/
And this is my code:
function target() {
$(".target").on("click", function() {
$("#"+x).appendTo(this);
console.log(x);
});
};
What's wrong?
Try binding with document, since you change the class during document ready and there was no element with the class target initially
$(document).on("click",".target", function() {
$("#" + x).appendTo(this);
console.log(x);
}
WORKING FIDDLE
Firstly, your practice of putting function references in to jQuery objects is rather odd. The problem however is that because the .target class is applied after DOM load you need to use a delegate selector. Try this:
var $card
$(".card").on("click", function () {
$card = $(this);
if ($(".myslot").length) {
if ($(".myslot").is(':empty')) {
$(".myslot:empty").addClass("target");
} else {
alert('No empty slots');
}
}
});
$('.field').on('click', ".target", function () {
$card.appendTo(this);
$card = $();
});
Example fiddle
At the moment you are trying to bind the event handler, the elements don't have a class target yet. From the documentation:
Event handlers are bound only to the currently selected elements; they must exist on the page at the time your code makes the call to .on().
(Technically the elements exist, but they are not (yet) addressable by the class target)
You have three options to solve this:
Add the class to your HTML markup.
Bind the handler after you added the class to the elements.
Use event delegation.
The first two don't really fit to your use case, since your are adding the class target in response to an other event and the number of elements with the class target changes over time. This is a good use case for event delegation though:
$('.field').on('click', '.target', function() {
// ...
});

Issue with selectors & .html() in jquery?

The function associated with the selector stops working when I replace it's contents using .html(). Since I cannot post my original code I've created an example to show what I mean...
Jquery
$(document).ready(function () {
$("#pg_display span").click(function () {
var pageno = $(this).attr("id");
alert(pageno);
var data = "<span id='page1'>1</span><span id='page2'> 2</span><span id='page3'> 3</span>";
$("#pg_display").html(data);
});
});
HTML
<div id="pg_display">
<span id="page1">1</span>
<span id="page2">2</span>
<span id="page3">3</span>
</div>
Is there any way to fix this??...Thanks
Not sure I understand you completely, but if you're asking why .click() functions aren't working on spans that are added later, you'll need to use .live(),
$("#someSelector span").live("click", function(){
# do stuff to spans currently existing
# and those that will exist in the future
});
This will add functionality to any element currently on the page, and any element that is later created. It keeps you have having to re-attach handlers when new elements are created.
You have to re-bind the event after you replace the HTML, because the original DOM element will have disappeared. To allow this, you have to create a named function instead of an anonymous function:
function pgClick() {
var pageno = $(this).attr("id");
alert(pageno);
var data="<span id='page1'>1</span><span id='page2'> 2</span><span id='page3'> 3</span>";
$("#pg_display").html(data);
$("#pg_display span").click(pgClick);
}
$(document).ready(function(){
$("#pg_display span").click(pgClick);
});
That's to be expected, since the DOM elements that had your click handler attached have been replaced with new ones.
The easiest remedy is to use 1.3's new "live" events.
In your situation, you can use 'Event delegation' concept and get it to work.
Event delegation uses the fact that an event generated on a element will keep bubbling up to its parent unless there are no more parents. So instead of binding click event to span, you will find the click event on your #pg_display div.
$(document).ready(
function()
{
$("#pg_display").click(
function(ev)
{
//As we are binding click event to the DIV, we need to find out the
//'target' which was clicked.
var target = $(ev.target);
//If it's not span, don't do anything.
if(!target.is('span'))
return;
alert('page #' + ev.target.id);
var data="<span id='page1'>1</span><span id='page2'>2</span><span id='page3'>3</span>";
$("#pg_display").html(data);
}
);
}
);
Working demo: http://jsbin.com/imuye
Code: http://jsbin.com/imuye/edit
The above code has additional advantage that instead of binding 3 event handlers, it only binds one.
Use the $("#pg_display span").live('click', function....) method instead of .click. Live (available in JQuery 1.3.2) will bind to existing and FUTURE matches whereas the click (as well as .bind) function is only being bound to existing objects and not any new ones. You'll also need (maybe?) to separate the data from the function or you will always add new span tags on each click.
http://docs.jquery.com/Events/live#typefn

Categories

Resources