Cloning $(this) in a javascript object? - javascript

I'm learning how to use objects to help organize my code and give it some structure but I've run into a problem. I don't understand how to set the $(this) from inside of one function to the $(this) of another function.
I'm researching call and apply but I can't seem to grasp how it works in this scenario.
cloneCard and clickCard is where I'm having the problem. I want to pass the $(this) that is referenced when I click the card to the cloneCard function.
Here is my code so far (updated to reflect the answer):
var Modal = {
init: function(config) {
this.config = config;
this.clickCard();
this.removeModal();
this.clickOutside();
this.createClose();
},
clickCard: function() {
$this = this;
this.config.boardOutput.on('click', '.card', function(event) {
$this.showOverlay();
$this.cloneCard.call($(this));
$this.createClose();
});
},
cloneCard: function() {
this.clone()
.replaceWith($('<div/>').html(this.html()))
.removeClass('card')
.addClass('modal')
.css("margin-top", $(window).scrollTop())
.prependTo('body');
},
showOverlay: function() {
this.config.overlay.show();
},
removeModal: function() {
$('.modal').remove();
$('.overlay').hide();
},
clickOutside: function() {
this.config.overlay.on('click', this.removeModal);
},
createClose: function() {
$('<span class="close">X</span>')
.prependTo('.modal')
.on('click', this.removeModal);
}
};
Modal.init({
boardOutput: $('#board-output'),
overlay: $('.overlay')
});

For what you need, calling self.cloneCard.call($(this)); instead of self.cloneCard($(this));
should work. What you're doing is, calling cloneCard passing it the element in which the the clickCard event occured.
If this doesn't work, i think we'll need more information to sovle your problem.

Related

jQuery click event not working while using "Module Pattern"

I'm an intermediate front-end JS developer and I'm trying the Module Pattern outlined by Chris Coyyer here.
But when I store a jQuery selector in the settings, I'm unable to use it to trigger a click event. See the below code with my comments... Any help is greatly appreciated!
var s,
TestWidget = {
settings: {
testButton: $("#testing")
},
init: function() {
s = this.settings;
this.bindUIActions();
},
bindUIActions: function() {
console.log(s.testButton); // This works: [context: document, selector: "#testing", constructor: function, init: function, selector: ""…]
//This doesn't work - why?????
s.testButton.click(function() {
//Why isn't this triggered?
alert('testButton clicked');
});
/*This works, obviously:
$('#testing').click(function() {
alert('testButton clicked');
});
*/
}
};
$(document).ready(function() {
TestWidget.init();
});
The problem is that you initialize $("#testing") before the DOM is ready, so this jQuery object is empty.
A simple solution is to put all your code in the ready callback.
Another one would be to replace
settings: {
testButton: $("#testing")
},
init: function() {
s = this.settings;
this.bindUIActions();
},
with
settings: {
},
init: function() {
s = this.settings;
s.testButton = $("#testing");
this.bindUIActions();
},
But it's hard to get why you use so much code for such a simple thing. You might be overusing the pattern here and it's not really clean as you have two global variables s and TestWidget when one would already be a lot.
Here's a slight variation of your code which would be, in my opinion, cleaner, while still using modules (IIFE variant) :
TestWidget = (function(){
var settings = {};
return {
init: function() {
settings.testButton = $("#testing");
this.bindUIActions();
},
bindUIActions: function() {
console.log(settings.testButton);
settings.testButton.click(function() {
alert('testButton clicked');
});
}
}
})();
$(document).ready(function() {
TestWidget.init();
});
settings is kept in the closure and doesn't leak in the global namespace. Note that even this version doesn't make sense if you don't do more with the module.

Function being run when bind in jquery document ready

I'm trying to bind a click event to the function below, however the entire function is currently being run when being binded in the document ready.
Is it possible to run it solely on the click event? Possibly it has something to do with the way my method is composed?
Thanks in advance
$(function() {
$("#expand-search").on("click", search.resize());
});
var search = {
element: $('#search_advanced'),
resize: function() {
search.element.slideToggle(400, 'swing', search.buttonState());
},
buttonState: function() {
if(search.element.is(':hidden')) {
console.log('hidden');
} else {
console.log('visible');
}
}
};
You are calling the function (handler) instead of passing the reference (name) of function (handler) to on().
Change
$("#expand-search").on("click", search.resize());
To
$("#expand-search").on("click", search.resize);
No parenthesis to event handlers! You want to pass the function-to-be-executed, not the result from executing it. Also, you will need to move your search object inside the ready handler since you use selectors for its initialisation.
$(function() {
var search = {
element: $('#search_advanced'),
resize: function() {
search.element.slideToggle(400, 'swing', search.buttonState);
},
buttonState: function() {
if(search.element.is(':hidden')) {
console.log('hidden');
} else {
console.log('visible');
}
}
};
$("#expand-search").on("click", search.resize);
});

jquery control chaining this loses scope

i was wondering if someone new how to keep a control with chaining in scope of the "this" key word. It breaks out of the chain when using .find(this).click does anyone know how to keep the chain from breaking
(function($) {
$.fn.mycontrol = function() {
$(window).resize(function() {
alert('resize')
}).scroll(function() {
alert('scroll')
}).find(document).bind('init', function() {
alert('scroll')
}).ready(function() {
$(this).trigger('init');
}).find(this).click(function() {
alert('click'); // $(this) loses scope here
});
})(jQuery);
$(document).ready(function() {
$('#mycontrol').mycontrol()
});
If I understand correctly what you're looking for, you should be able to just save the value of this before you start your chaining:
(function($) {
$.fn.mycontrol = function() {
var that = this;
$(window).resize(function() {
alert('resize')
}).scroll(function() {
alert('scroll')
}).find(document).bind('init', function() {
alert('scroll')
}).ready(function() {
$(that).trigger('init');
}).find(that).click(function() {
alert('click'); // $(this) loses scope here
});
})(jQuery);
Chaining creates unmaintainable code. Break it up into separate lines:
var $window = $(window);
$window.resize(function()
{
alert('resize')
});
$window.scroll(function()
{
alert('scroll')
});
// etc.
Then you can read it, you can step though it with the debugger, you can delete and remove logic with out breaking anything.
window is an object Window.
This is window.document which contains HTML objects.
So $(window).find(this) return jquery empty object as $(window).find(document) too.
$(document).find(this) works instead which is equivalent of $(window.document).

JS & EXT JS: function inside a function scope misunderstanding

im having some trouble with the following code:
Ext.define('...controller...', {
extend: 'Ext.app.Controller',
init: function() {
...
},
crearLoginWindow:function(){
var loginWindow = Ext.create('Proto1.view.adminbd.LoginWindowBDView', {
itemId: 'loginwindow',
autoShow: true,
modal: true
});
Ext.ComponentQuery.query('#loginwindow > button[text="Cancelar"]')[0].on('click', function(){loginWindow.close()});
//Cant call 'enviarLogin' function if its inside 'crearLoginWindow'
Ext.ComponentQuery.query('#loginwindow > button[text="Conectar"]')[0].on('click', this.enviarLogin, this);
var enviarLogin = function(){
console.log('login')
}
}
});
I want to be able to call 'enviarLogin' inside 'crearLoginWindow' function but it throws a reference error. If the function is placed outside 'crearLoginWindow' it will work.
Being these two lines the source of trouble:
Ext.ComponentQuery.query('#loginwindow > button[text="Conectar"]')[0].on('click', this.enviarLogin, this);
var enviarLogin = function(){
console.log('login')
}
I've tried different scope variants such as;
Ext.ComponentQuery.query('#loginwindow > button[text="Conectar"]')[0].on('click', this.crearLoginWindow.enviarLogin);
this.enviarLogin = function(){
console.log('login')
}
Which makes sense with what i think i understand about scope and the need to specify the place where the function resides to execute it.
Id appreciate a solution because this problem makes my code very messy!
Simply defining a function within another function doesn't attach it to any object or instance, so this.enviarLogin won't work. There are two basic options here:
Just define the inner function as you're doing (moving it up above your handler assignment), and reference it directly by name:
var enviarLogin = function(){
console.log('login')
};
Ext.ComponentQuery.query('#loginwindow > button[text="Conectar"]')[0]
.on('click', enviarLogin);
Define enviarLogin as a method, the same way you are defining crearLoginWindow:
Ext.define('...controller...', {
extend: 'Ext.app.Controller',
init: function() { ... },
crearLoginWindow: function(){
// ...
Ext.ComponentQuery.query('#loginwindow > button[text="Conectar"]')[0]
.on('click', this.enviarLogin, this);
},
enviarLogin: function(){
console.log('login')
}
});
The first version may be better if you don't need to reference enviarLogin outside of the crearLoginWindow method. The second is better if you do need to reference enviarLogin elsewhere, and it makes using this in enviarLogin clearer.

Mootools -- call class function from bound css class results in 'not a function' error

Using Mootools 1.3.2
Code is as follows:
var DNReportAbuse = new Class({
Extends: DNUserDialog,
comment_id: null,
container: null,
initialize: function(classname)
{
var bindclass = $(document.body).getElements(classname);
bindclass.each(function(el) {
el.addEvents({
click: function() {
this.reportComment();
}.bind(this)
});
});
},
reportComment: function() {
this.preventDefault();
alert('hello');
return false;
}
});
The event does bind, and when "this.reportComment();" is replaced with "alert('hello world');" it works entirely ...
... but when "this.reportComment()" is used, I instead receive an error, which Firebug explains as "function this.reportComment() is not a function".
I imagine that my issue has something to do with referring to a class function outside of its proper scope, though I'm a bit confused as to why ... or how to solve the issue. The end goal is to achieve an on-click binding of the reportComment() function to all members of a css class (up to 20 per page). The difficulty is that referencing the reportComment() function with "this.reportComment()" results in an error claiming that the function does not exist, when it clearly does exist.
Looking through similar questions on Stack Overflow did not seem to answer this issue ... so asking in hopes that someone can point me in the right direction.
You have some problems with bind and events:
initialize: function(classname)
{
var bindclass = $(document.body).getElements(classname);
var _self = this; //var to store the 'real' this you will use
bindclass.each(function(el) {
el.addEvents({
click: function(event) { //pass the event
this.reportComment(event);
}.bind(_self) //'this' is referring to the inner each function callback
});
});
},
reportComment: function(event) {
event.preventDefault(); //preventDefault on the event, not on 'this'
alert('hello');
return false;
}

Categories