I am dynamically creating objects which construct a view and bind events to the constructed view when clicked. However, the click event is always attaching itself to the last created object. I do want to have the same click event for each object, but the data that I am passing to a new class is unique per instance.
Object creation:
$.each(data,function(i,json)
{
var channelWrapper = new ChannelDisplayView(that.channelContainer, json);
that.channelContainer.append(channelWrapper.createView());
});
ChannelDisplayView.js
function ChannelDisplayView(parent, data){
this.parent = parent;
this.data = data;
}
ChannelDisplayView.prototype.createView = function(){
this.channelWrapper = $("<div/>").addClass("channelDisplay").attr("id", this.data.fullName);
this.channelTitle = $("<div/>").addClass("channelTitle").html(this.data.fullName);
this.channelSource = $("<div/>").addClass("sourceType").html(this.data.sourceType);
this.channelWrapper.append(this.channelTitle);
this.channelWrapper.append(this.channelSource);
that = this;
this.channelWrapper.unbind().on("click",function(event){
ControllersSingleton.getInstance().getProgramController().setupPage(that.data);
});
return this.channelWrapper;
}
As you can see each class will hold its own JSON data and this should be used to pass to an instance of another controller if the "div" is clicked. The data being sent no matter what div I click is always from the last created object.
Am I missing something obvious here?
It looks like you have created a global that which on each loop iteration is being overwrote with that = this.
Instead of calling append on that.channelContainer try using the instance you have created like channelWrapper.channelContainer.append.... channelWrapper is scoped to the loop iteration.
You can bind an event handler to your whole document and listen for all events of a certain type, responding with a callback if the event target matches a certain selector. For instance:
$(document).on('click', '.some-class', function(e){
console.log('.some-class element clicked.');
});
That code will listen for any clicks on the document, and if the target matches the selector in the second parameter, it will execute the callback function in the third parameter.
I often find it best to use a method like this when I am dynamically adding elements to the DOM.
Related
How do I get a reference to the HTML DOM element inside its event handler that I am wiring up?
var dashboard =
{
WireHandlers : function()
{
$(".approveButton")
.unbind("click")
.click(dashboard.approve)
},
approve : function()
{
// In here, I would like a reference
// to the HTML DOM element that was clicked
// Also, I would like its id
}
}
Simply add an argument to your approve function (typically named event) and call currentTarget on it:
approve : function(event) {
// In here, I would like a reference
// to the HTML DOM element that was clicked
event.currentTarget
// Also, I would like its id
event.currentTarget.id
}
Note that you can also use this within the approve method to reference the clicked element.
approve : function() {
this // or $(this) if you want to use jQuery
}
Note that in this case target and currentTarget are interchangeable. However, in more complex scenarios, there are important differences between the two.
$(this)
is the jQuery element (this is the DOM element)
this will not be bound to dashboard (as you're just providing the function as a callback, you'll have to use eg dashboard.WireHandlers)
From the jquery documentation here:
https://api.jquery.com/click/
you can access the acted upon element through the "this" variable:
approve : function()
{
var elem = this;
var id = elem.id;
}
Inside an event listener, I need a reference to the element that was the event source. How do I get that?
This should be a no-brainer for anyone doing JavaScript for some time.
All the functions including the event handler are in global scope, and therefore, implicitly made a part of the DOM window object.
function WireHandlers() {
$('.updateResourceImageButton').click(UpdateResourceLinkClickedHandler);
}
function UpdateResourceLinkClickedHandler() {
// I would like a reference to the hyperlink/anchor
// that was actually clicked, i.e. the hyperlink that
// was the source of this event
// would the keyword 'this' evaluate to the element I need?
// or will it evaluate to the HTML DOM 'window' object
// in this context?
}
$(document).ready(function () { WireHandlers(); });
When you pass the function by reference you still get access to the parameters as normal. As such event.target or this will be the clicked element within the UpdateResourceLinkClickedHandler function:
function UpdateResourceLinkClickedHandler(e) {
// clicked element as a native DOM element
var foo = e.target;
var bar = this;
// jQuery object containing clicked element
var $foo = $(this);
}
Note, both foo and bar in this example will contain the same value.
I think you can do it like this
$(this)
also this is from jquery documentation
var target = $( event.target );
as in this page http://api.jquery.com/event.target/ and look at this article for more information http://www.pkshiu.com/loft/archive/2009/01/understanding-this-this-and-event-in-a-jquery-callback-function
So I have a newly created Javascript object called EditableObject in my custom .js file
function EditableObject(e, dv, i) {
this.element = e;
this.default_value = dv;
this.set = 0;
this.id = i;
alert(this.element.html());
this.element.click(function (event) {
alert(this.element.html());
});
}
In my main page, I have a div called "field" that has the text "yeah" in it like such:
<div id="field">yeah</div>
In the script portion of my main page, I've got:
var t = new EditableObject($("#field"), "value", 1);
When the page loads, there is an alert box that says "yeah". But when I click on the div, I get an error saying that "this.element is undefined". Why is this happening?
Inside your click handler, this refers to a different scope (depending on browser, it'll be the event object or the current function). You need a closure to access parent scope's this:
var self = this;
this.element.click(function (event) {
alert(self.element.html());
});
The thing with this is that it differs in each function depending on the context. In jQuery bind functions, it is the element itself so the most straight-forward solution is:
this.element.click(function (event) {
alert($(this).html());
// this is element, $(this) is jQuery object containing element
});
So currently, this refers to the element, which differs from e.g. the line
this.id = i;
where it refers to the instance of EditableObject, because there you use this in a different function.
The this in your click function refers only to the click itself. I believe you can use
e.html();
there instead
this inside of your click handler refers to the DOM object, not the instance of EditableObject.
You could modify it like this:
this.element.click(function (event) {
alert($(this).html());
});
I have what seems to be a very tricky situation. I would like to pass an instance of an object to the event listener of a DOM element that was created by that same object instance (if that makes sense).
function Object(callback){
this.callback = callback;
this.node = document.createElement('div');
this.send = function(){
document.getElementById('list').appendChild(this.node);
}
this.node.addEventListener('click',function(){/*this.callback() of Object instance needs to go here*/},true);
}
I know that using callback() would work inside the event listener, but thats not what I need because I will be using variables from the instance that are not passed from the construct later on.
How can I solve this?
The anonymous function changes the meaning of this. To be able to use it within the handler, use another var, or don't create another function:
var elem = this;
this.node.addEventListener('click',function(){ elem.callback(); },true);
or
this.node.addEventListener('click', this.callback, true);
Say, I have two HTML elements - an input field and a button.
The code for both is generated programatically.
After I generate the code, I have a function that binds event handlers to those elements.
//Locate add to order button and bind event handler to it
this.input_add = document.getElementById("add_to_order");
this.input_add.onclick =
function () {
return controller.addToOrder.call(controller);
};
// Locate quantity input and bind event handler to it
this.input_quantity = document.getElementById("form_quantity");
this.input_quantity.onkeyup =
function () {
return controller.changeQuantity.call(controller, this);
};
Here's the puzzle - controller.changeQuantity requires a reference to this.input_add.
As far as I can tell, I can't pass this.input_add into the call parameter list for controller.changeQuantity.
I've found only one solution - putting a reference to this.input_add in the this.input_quantity object.
this.input_quantity.addButton = this.input_add
Are there any alternatives? Is this a good practice? I'm trying to keep my application as decoupled as possible.
Add your DOM objects to your "controller", and set up your event handlers as part of that object, something like:
var controller = { ... };
controller.input_add = document.getElementById("add_to_order");
controller.input_quantity = document.getElementById("form_quantity");
controller.input_add.onclick = function() { controller.addToOrder.call(controller, this);}
Then you can reference these DOM elements from within your controller object at any point.
I often set up references to DOM elements, register event handlers, etc. in the setup code for my main Javascript controller object.