Accessing a jQuery element reference as an object property - javascript

I'm trying to set an element as a property of an object using jQuery. When I make a direct reference to the jquery object, it works, however when I make the reference through the calculator object, it doesn't.
How do I fix this?
var calculator = {
settings: {
displayNumber: $('.dispNumber'),
modNumber: $('.modNumber')
}
}
window.onload = function(){
console.log( $('.dispNumber').html() ); //this one works
console.log( calculator.settings.displayNumber.html() ); //this one doesn't
}

If calculator.settings.displayNumber isn't created in a dom ready scope, it won't have the elements.

Since you are using jQuery, you should put everything handling the DOM inside either :
$(function() {
//code here will always run after the DOM is ready.
var calculator = {
settings: {
displayNumber: $('.dispNumber'),
modNumber: $('.modNumber')
}
};
console.log( $('.dispNumber').html() ); //this one works
console.log( calculator.settings.displayNumber.html() ); //this one doesn't
});
OR
simply add <script>........code.......</script> before your </body>.
The first one is the proper way to handle DOM-related operations.
Edit: reusable object :
var Calculator = function($) {
this.settings = {
displayNumber: $('.dispNumber'),
modNumber: $('.modNumber')
};
};
Calculator.prototype = {
log: function() {
console.log(this.settings.displayNumber.html());
console.log(this.settings.modNumber.html());
}
}
$(function(){
var calculator = new Calculator($);
calculator.log();
console.log(calculator.settings.displayNumber.html());
});

Your code works fine. The only reasons why it shouldn't work is that calculator is not instanciated before window.onload.
Remove that issue and everything works. See: http://jsfiddle.net/352Cm/
var calculator = {
settings: {
displayNumber: $('.dispNumber'),
modNumber: $('.modNumber')
}
}
console.log( $('.dispNumber').html() ); //this one works
console.log( calculator.settings.displayNumber.html() ); //this one doesn't
Try to console.log(calculator) in window.load and you'll probably see 'undefined' or crashing code.

Related

jQuery plugin instance variables

I'm beginning with jQuery plugins, apologies for the newbie question. My objective is to have a single plugin instantiated twice, where each instance has its own variables values. However, they seem to share the namespace.
For example, given the following plugin:
(function ( $ ) {
var x = false;
$.fn.test = function() {
alert(x);
if ( !x )
x = true;
return this;
};
}( jQuery ));
that is invoked from the following divs:
$( "div1" ).test();
$( "div2" ).test();
The alert displays first false, then true, when the objective is to have to sets of variables where the alert would display false twice.
is this possible?
There is some confusion in your question. Your plugin is a simple function. You don't "instantiate" a function by calling it. So you don't "instantiate" your plugin either.
You can instantiate things in your function, and persist them somewhere.
Since the outer scope runs only once, in your original solution you only get one instance of variable x.
If you create it inside the function, a new instance gets created every time you call it.
I assume you want to create an instance for every element you call this plugin on. A good solution would be to attach your data to the DOM element you initiate your plugin on, like:
(function ( $ ) {
$.fn.test = function() {
var vars = this.data('testPlugin');
if (!vars) {
vars = {
x: false,
something: 'else'
};
this.data('testPlugin', vars);
}
alert(vars.x);
vars.x = !vars.x;
return this;
};
}( jQuery ));
Try this fiddle.
You should put
var x = false;
inside $.fn.test function, otherwise the x variable is the same for all test() functions, and set to true after first call.
You can read more here about javascript variable scoping.
Actually, this is much easier than the previous answers. The context of this in your plugin is the jQuery object for the DOM element you're receiving based on the selector you provided. To gain uniqueness, simply iterate over each element, like so:
(function($) {
$.fn.test = function() {
return this.each(function() {
var x = false;
alert(x);
if (!x) {
x = true;
}
});
}
}(jQuery));
$("div1").test(); //false
$("div2").test(); // false
Here's a JSFiddle to confirm: http://jsfiddle.net/Z6j7f/

Dynamic access to the object name

I am trying to select certain property of dynamic object
var minus = {
doAction: function(){
console.log("this is minus");
}
}
var plus = {
doAction: function(){
console.log("this is plus");
}
}
var panelEvents = {
button: function(){
$(document).on("click", ".plus, .minus", function(){
var buttonClass = $(this).attr('class');
window[buttonClass][doAction](); //get an error
});
}
}
panelEvents.button();
Questions
1. How can I dynamically call various objects with the same methods?
2. Is it bad practice in point of OOP view to access methods in such way?
UPDATE
I understood, that it is not flexible approach. So now I have only theoretical interest of accessing dynamic object. Neither
window[buttonClass]['doAction']();
nor
window[buttonClass].doAction();
working.
Firebug:
TypeError: window[buttonClass] is undefined
window[buttonClass]'doAction';
Should I obviously attach minus and plus objects to window?
SOLUTION
The problem was that my code was inside jQuery object
$(document).ready(function(){
//my code
)};
With the line that fails, you are trying to call a function that is named the same as the content of the variable doAction. The problem here is that doAction is not defined.
You would have to write:
window[buttonClass]['doAction']();
or
window[buttonClass].doAction();

Using an anonymous function as part of a javascript object

I'm going to show you two snippets.
This works fine:
this.searchBox = new Foo.UI.SearchBox(this.input, {
autoCompleteSearchComplete: processSearchResults
});
This doesn't work at all:
this.searchBox = new Foo.UI.SearchBox(this.input, {
autoCompleteSearchComplete: function() {
processSearchResults
}
});
I need to place that processSearchResults call inside an if statement, to check if my search text input ($('.search')) has any text written inside it.
My first idea was to use this function type notation, but it's not working. It's as if the call to processSearchResults is never made at all.
Any suggestions?
That's because you do not actually call that function. This would be correct:
this.searchBox = new Foo.UI.SearchBox(this.input, {
autoCompleteSearchComplete: function() {
if (...) {
processSearchResults();
}
}
});

JavaScript function to bind events specified in object

I'm creating a function that gets in input a JavaScript object with this format:
var input = {
'selector1' : {
'event1' : function(element,value){
// ...
},
'event2' : function(element,value){
// ...
},
...
'eventN' : function(element,value){
// ...
}
},
'selector2' : {
'event1' : function(element,value){
// ...
},
'event2' : function(element,value){
// ...
},
...
'eventN' : function(element,value){
// ...
}
}
}
My function bind the events this way:
function event_binder(events_fns){
for(sel in events_fns){
for(ev in events_fns[sel]){
$(sel).on(ev,function(){
console.log(sel+'+'+ev);
var th = $(this);
var func_to_call = events_fns[sel][ev];
func_to_call(th,th.html());
});
}
}
}
but when I run it, it shows that every event's been bound to the last event.
I created a jsFiddle for better explain my problem:
http://jsfiddle.net/Polmonite/6rRgr/
As the console.log suggest, it seems that the event binding always use the last
function in the object.
If I'm interpreting right, it would seems that the evaluation of the .on
function only happens at the end, so it use the last values of sel and ev
variables (a scoping problem), but I don't quite understand how to fix it.
EDIT: I need to specify one thing: I want to create a working version of the event_binder function, not a working version of the jsfiddle, which is just an example.
The issue is scope - there is only one sel and ev variable in the whole function, which is overwritten each time. To create a new scope (with its own variables), you have to wrap them in their own function. Luckily, jQuery provides an iterating function that you can pass a function to, so that you don't have this issue: $.each. See: http://jsfiddle.net/6rRgr/3/.
$.each(events_fns, function(sel, funcs) {
$.each(funcs, function(ev, func) {
$(sel).on(ev,function(){
console.log(sel+'+'+ev);
var th = $(this);
func(th,th.html());
});
});
});

Javascript: How to access object member from event callback function

I have some problems trying to figure out what is wrong with my object design.
var comment = function(){
var textarea = null;
$(document).ready( init );
function init()
{
$('.reply').click( comment.reply_to );
this.textarea = $('.commentbox textarea');
console.log( this.textarea ); // properly shows the textarea element
console.log( textarea ); // outputs null
}
function set_text( the_text )
{
console.log( textarea ); // outputs null
console.log( this.textarea ); // outputs undefined
textarea.val( the_text );
}
return {
reply_to: function()
{
console.log( this ); // outputs the element who fired the event
set_text( 'a test text' ); // properly gets called.
}
};
}();
When document is fully loaded, init() is automatically called and initializes the object. I must note that the textarea member properly points to the desired element.
A click event is attached to a "reply" button, so reply_to() function is called whenever user clicks on it.
So, this is what I don't understand:
* When using "this" is safe? Using it from reply_to() it is not, as it seems like the context is set to the caller element.
* Why I can call "set_text()" from reply_to, but I cannot access the "textarea" member?
* How I should do to access "textarea" member from reply_to() (which is an event callback)?
Since inside those handlers the context will change, it's easiest to keep a reference to the context you want, I personally prefer self. Here's one alternative format:
var comment = function(){
this.textarea = null;
var self = this;
$(document).ready( init );
function init()
{
$('.reply').click( reply_to );
self.textarea = $('.commentbox textarea');
}
function set_text( the_text )
{
self.textarea.val( the_text );
}
function reply_to() {
set_text( 'a test text' );
}
}();
You can test it here. Admittedly though I'm not really sure what you're trying to accomplish though. You are trying to return the reply_to function, but bind it yourself inside the init() ready handler...so you can either bind it immediately (like above), or change it up and return what you want to bind elsewhere.

Categories