Binding 'this' and getting this - javascript

$('.btn-delete').on('click', this.confirm.bind(this));
Above, on click it runs:
p.confirm = function(e) {
if(!$(this).hasClass('danger')){
$(this).addClass('danger');
$(this).bind('mouseleave',function(){
$(this).removeClass('danger');
$(this).unbind('mouseleave');
});
}
else{
this.delete();
}
};
I'm having trouble with this. I need this to get the button but I also need this to access another method (this.delete). I've tried bind but it faisl to work.
Any ideas?

Assuming I'm understanding your question correctly, you want to be able to pass the clicked element as this to the p.confirm function. You should be able to do this by using call, or by using p.confirm as the handler:
// using call
$('.btn-delete').on('click', function (e) {
p.confirm.call(this, e);
});
// as handler
$('.btn-delete').on('click', p.confirm);
Assuming that this.delete is actually p.delete, just use call in the handler to pass the clicked element as this to the delete method:
p.confirm = function (e) {
var self = $(this); // cache lookup, "this" is the clicked element
if (!self.hasClass('danger')) {
self.addClass('danger');
self.bind('mouseleave', function () {
self.removeClass('danger');
self.unbind('mouseleave');
});
} else {
p.delete.call(this); // pass clicked element to use as "this" in p.delete
}
};

Related

Calling functions in ES6 [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 4 years ago.
Trying to call the closeOpenNavDropdowns function within my toggleDropdownNavState function, but nothing is running and I am not getting errors. I've checked the compiled code and it's there.
EDIT: trying to call the fn like this.closeOpenNavDropdowns(); gives me Uncaught TypeError: this.closeOpenNavDropdowns is not a function
const aboutDropdownNav = {
setup() {
$('.nav__main__about-dropdown--js').click(this.toggleDropdownNavState);
// Handlers for when user clicks outside the dropdown to close
$(document).click(function(event) {
if ($('body').hasClass('about-dropdown--open') && !$(event.target).parents('.about-us-dropdown').length) {
$('body').removeClass('about-dropdown--open');
}
})
},
toggleDropdownNavState(e) {
e.stopPropagation();
e.preventDefault();
$('body').toggleClass('about-dropdown--open');
this.closeOpenNavDropdowns;
},
closeOpenNavDropdowns() {
console.log('closeOpenNavDropdowns in aboutDropdown.js');
$('body').removeClass('solutions-dropdown--open'); //close solution dropdown if its open
}
}
module.exports = aboutDropdownNav;
and the above code is called by this other file:
var aboutDropdownNav = require('./nav-about-dropdown');
module.exports = function() {
// About Dropdown Nav
aboutDropdownNav.setup();
}
The toggleDropdownNavState function is attached to an eventListener. Inside an event handler function, this is a reference to the event's current target. That's why closeOpenNavDropdowns is not a function in the object referenced by this.
There are many ways to solve that issue. One of them is to use Function.prototype.bind to force the binding between the closeOpenNavDropdowns function and your object.
const aboutDropdownNav = {
setup: function() {
$('.nav__main__about-dropdown--js').click(this.toggleDropdownNavState.bind(this));
// Handlers for when user clicks outside the dropdown to close
$(document).click(function(event) {
if ($('body').hasClass('about-dropdown--open') && !$(event.target).parents('.about-us-dropdown').length) {
$('body').removeClass('about-dropdown--open');
}
})
},
toggleDropdownNavState : function(e) {
e.stopPropagation();
e.preventDefault();
$('body').toggleClass('about-dropdown--open');
this.closeOpenNavDropdowns();
},
closeOpenNavDropdowns : function() {
console.log('closeOpenNavDropdowns in aboutDropdown.js');
$('body').removeClass('solutions-dropdown--open'); //close solution dropdown if its open
}
}
aboutDropdownNav.setup();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input class="nav__main__about-dropdown--js" value="Click"/>
The context, when calling this.toggleDropdownNavState is wrong, bind it to the proper context.
$('.nav__main__about-dropdown--js').click(this.toggleDropdownNavState.bind(this));
And you are missing the brackets () to call the function, you just referencing the function.
toggleDropdownNavState(e) {
e.stopPropagation();
e.preventDefault();
$('body').toggleClass('about-dropdown--open');
this.closeOpenNavDropdowns();
},

2 different on click events conflict?

I have one link:
link
And I have two different onclick function set to the two classes like this:
jQuery(".lorem").each(function(){
this.onclick = function() {
// stuff
}
});
and
jQuery(".hello").each(function(){
this.onclick = function() {
// stuff
}
});
This stops the top one to work. Why? And how can I make both functions work while being separated?
You can only assign one function to the onclick property. You should use normal jQuery event binding, it allows multiple handlers:
$(".lorem").click(function() {
// stuff
});
$(".hello").click(function() {
// stuff
});
If you want to do it with native Javascript, you can use addEventListener; as the name suggests, these are additive, they don't replace.
jQuery(".lorem").each(function(){
this.addEventListener("click", function() {
// stuff
})
});
jQuery(".hello").each(function(){
this.addEventListener("click", function() {
// stuff
})
});
When you are using query, why use .onclick on the DOM element (therefore overwriting the previous binding). Instead use jQuery's .on:
$('.lorem').on('click', function(){
// something
});
$('.hello').on('click', function(){
// something else
});

How to attach Event Listeners to only newly created elements?

When I fire a function I want it to apply listeners just to elements I pass, particular this jQuery element.
addEventListeners(this);
function addEventListeners(el) {
$(el).mouseenter(function() {
$(this).stop(true,true).switchClass("", "HIGHLIGHT", 400, "easeInOutQuad");
});
$(el).mouseleave(function() {
$(this).stop(true,true).switchClass("HIGHLIGHT", "", 400, "easeInOutQuad");
});
}
It fires from AJAX result:
$.post(url,{el:wartosc_inputa},function(returned) {
var data = $(returned).hide();
$("#listaElementow").prepend(data);
data.slideDown();
loading();
addEventListeners(this);
});
How to code it good? This code is not passing variables from addEventListeners(this); to function.
in the ajax callback function "this" will be the ajax object i think and no longer an element so you need to save "this" in a variable before the ajax starts.
that = this;
$.post(url,{el:wartosc_inputa},function(returned) {
var data = $(returned).hide();
$("#listaElementow").prepend(data);
data.slideDown();
loading();
addEventListeners(that);
});
Judging from the context of the rest of your success handler, I assume returned is the DOM element you're attempting to bind your handlers to. Assuming this is the case:
$.post(url,{el:wartosc_inputa},function(returned) {
var data = $(returned).hide();
$("#listaElementow").prepend(data);
data.slideDown();
loading();
addEventListeners(data[0]);
// change this ^^^^
// pass the DOM element here, or
// change the addEventListeners function to take a jquery element
});
this in that context is not what you expect it to be. Try this:
var self = this;
$.post(url,{el:wartosc_inputa},function(returned) {
var data = $(returned).hide();
$("#listaElementow").prepend(data);
data.slideDown();
loading();
addEventListeners(self);
});

jQuery: Call a function twice

I'm trying to run a function twice. Once when the page loads, and then again on click. Not sure what I'm doing wrong. Here is my code:
$('div').each(function truncate() {
$(this).addClass('closed').children().slice(0,2).show().find('.truncate').show();
});
$('.truncate').click(function() {
if ($(this).parent().hasClass('closed')) {
$(this).parent().removeClass('closed').addClass('open').children().show();
}
else if ($(this).parent().hasClass('open')) {
$(this).parent().removeClass('open').addClass('closed');
$('div').truncate();
$(this).show();
}
});
The problem is on line 13 where I call the truncate(); function a second time. Any idea why it's not working?
Edit jsFiddle here: http://jsfiddle.net/g6PLu/
That's a named function literal.
The name is only visible within the scope of the function.
Therefore, truncate doesn't exist outside of the handler.
Instead, create a normal function and pass it to each():
function truncate() { ...}
$('div').each(truncate);
What's the error message do you get?
You should create function and then call it as per requirement
Define the function
function truncate(){
$('div').each(function(){
});
}
Then call the function
truncate();
Another approach is to establish, then trigger, a custom event :
$('div').on('truncate', function() {
$(this).......;
}).trigger('truncate');
Then, wherever else you need the same action, trigger the event again.
To truncate all divs :
$('div').trigger('truncate');
Similarly you can truncate just one particular div :
$('div#myDiv').trigger('truncate');
The only prerequisite is that the custom event handler has been attached, so ...
$('p').trigger('truncate');
would do nothing because a truncate handler has not been established for p elements.
I know there's already an accepted answer, but I think the best solution would be a plugin http://jsfiddle.net/g6PLu/13/ It seems to be in the spirit of what the OP wants (to be able to call $('div').truncate). And makes for much cleaner code
(function($) {
$.fn.truncate = function() {
this.addClass('closed').children(":not('.truncate')").hide().slice(0,2).show();
};
$.fn.untruncate = function() {
this.removeClass('closed').children().show();
};
})(jQuery);
$('div').truncate();
$('.truncate').click(function() {
var $parent = $(this).parent();
if ($parent.hasClass('closed')) {
$parent.untruncate();
} else {
$parent.truncate();
}
});

Overwriting a Backbone Models Change Event

I think what I want to do is pretty simple I just don't know how to do it. I would like to fire my own event when one of my models attributes changes for the purpose of passing some data to the event handler (whether the change was an increase or decrease in value).
Basically I want my handler to do this in the view
handler: function(increased) {
if(increased) {
alert("the value increased")
}
else {
alert("the value decreased")
}
}
// ...
this.model.on("change:attr", this.handler, this);
Here you go: You basically listen for change:myvar. When a change occurs you use your model's previous() to get the old value. Depending on whether it increased or decreased you fire the appropriate event. You can listen to these events as shown in the initialize().
(function($){
window.MyModel = Backbone.Model.extend({
initialize: function () {
this.on('change:myvar', this.onMyVarChange);
this.on('increased:myvar', function () {
console.log('Increased');
});
this.on('decreased:myvar', function () {
console.log('Decreased');
});
},
onMyVarChange: function () {
if (this.get('myvar') > this.previous('myvar')) {
this.trigger('increased:myvar');
} else {
this.trigger('decreased:myvar');
}
}
});
window.mymodel = new MyModel({myvar: 1});
mymodel.set({myvar: 2});
mymodel.set({myvar: 3});
mymodel.set({myvar: 1});
})(jQuery);​
Running the above will print "Increased", "Increased", "Decreased" to your console.
Just look at previousAttributes()
You can then compare:
If(this.get(attr) > this.previousAttributes()[attr]){
console.log('bigger');
} else {
console.log('smaller');
}
If you use that in your change event handler you're all set. No need for a custom trigger or a ton of code.
EDIT
This is from my Backbone.Validators project and how I obtain the list of all attributes which have changed during the validation step:
var get_changed_attributes = function(previous, current){
var changedAttributes = [];
_(current).each(function(val, key){
if(!_(previous).has(key)){
changedAttributes.push(key);
} else if (!_.isEqual(val, previous[key])){
changedAttributes.push(key);
}
});
return changedAttributes;
};
This requires Underscore 1.3.1 because it's using _.has. If you can't upgrade that's an easy thing to replace though. In your case you'd passing this.previousAttributes() and this.attributes
What if you fire your own custom event after listening to the change event?
handler: function(increased) {
this.model.trigger('my-custom-event', stuff, you, want);
},
myHandler: function(stuff, you, want){
// Do it...
}
// ...
this.model.on("change:attr", this.handler, this);
this.model.on('my-custom-event, this.myHandler, this);

Categories