I'm trying to use the objects within my jQuery code.
I've nearly this:
var opts = {
ul: $(this).find('.carousel'),
li: ul.find('li')
}
li property gives an error Cannot call method 'find' of undefined
How can it be fixed?
It doesn't matter what your selector is, you can't access a property of an object that you are declaring, while you are declaring it.
Why would ul be declared? You're making a property ul on your opts object.
Ugly:
What you might want is:
var opts = {
ul: $(this).find('.carousel')
}
opts.li = opts.ul.find('li');
But if you don't actually need references to both groups then:
Cleaner:
var opts = {
li: $(this).find('.carousel li')
}
is just as good.
Cleanest:
You could also do:
var $carousel = $(this).find('.carousel');
var options = {
carousel: $carousel,
carouselItems: $carousel.find('li')
}
Godawful, but you asked for it:
var CarouselOptions = (function () {
var options = function (carousel) {
this.carousel = $(carousel);
this.carouselItems = this.carousel.find('li');
};
options.prototype.myOptionsFunction = function () {
// Don't know what you want your object to do, but you wanted a prototype...
};
return options;
})();
var opts = new CarouselOptions($(this).find('.carousel'));
Also
(Be careful with what your this is, presumably you have more than one .carousel element on the page, and here you want the one that is within the target of an event.)
Your error message is essentially saying that $(this) is undefined (or in other words, jQuery couldn't find this element). Because you don't have any code other than the single object you are trying to set, I don't know what the actual value of this is.
What I would do is ensure that this is set to an element of some sort. A simple console.log(this) should handle that. If this isn't an HTML element, then that's your problem. Either ensure you are inside of a jQuery event function like this:
$('#id').click(function() {
this === document.getElementById('id'); // true
});`
Or you can just drop the $(this):
var opts = {};
opts.ul = $('.carousel'),
opts.li = opts.ul.find('li')
var that = $(this);
var opts = {
ul: that.find('.carousel'),
li: ul.find('li')
}
Related
What am I doing wrong, and how can one pass variables to a different function within the same wrapping variable/function.
Example:
function customFunctionWrap(){
this.myVar1 = 0;
this.getCurrentPosition = function(){
if (navigation.geolocation) {
navigator.geolocation.getCurrentPosition(function(position){});
}
},
this.doSomething = function(){ // Works
//Do something, return
this.callWithParams(); //Works
},
//If I remove passing in 'value1',calling it elsewhere works
this.doSomethingWithParams = function(value1){
//Use value1
//Return
},
this.callWithParams = function(){
var value1 = 'xyz'; //Is a variable that changes based on some DOM element values and is a dynamic DOM element
this.doSomethingWithParams(value1); //THROWS TYPEDEF ERROR: this.doSomethingWithParams is not a function
this.getCurrentPosition();
}
};
var local = new customFunctionWrap();
local.doSomething(); //WORKS
I know there is another way to do it and then directly use customFunctionWrap.callWithParams(), but am trying to understand why the former approach is erroring out.
var customFunctionWrap = {
myVar1 : 0,
callWithParams : function(){
}
}
What JS sees:
var customFunctionWrap = (some function)()
returned function is fired, because the last (), so it has to yield/return something, otherwise, like in your code it is "returning" undefined.
So your given code does not work.
The very first fix is to delete last 2 characters from
var customFunctionWrap = (some function)()
to make it return constructor.
I'm trying to reuse an object I created to dynamically create more than one slider on a page.
My idea was to create an array and push my slider object there as often as needed, so I could access it by id. Unfortunatelly it doesn't work. Hope someone can point me in the right direction ...
So what I have is this;
var slider = {
"init":function(slide_it){
this.parent = $(slide_it);
/Count Elements and create a navigation depending on the count etc./
},
"otherstuff":{...}
}
In my (document).ready function I create an array and fill it up with different slider objects, add Ids to an accordion and call the init function:
var slide_array = [];
var accordion_sections = $('#accordion > div').length;
for(var i = 0; i < accordion_sections; i++){
slide_array.push(slider);
$('#accordion').children('div').eq(i).attr('id', 'slide_it_'+ i);
slide_array[i].init($('#slide_it_' + i).find('.slider'));
}
Then I have a button with class="next" and I call a function within the slider
$('.next').click(function(){
slide_array[0].otherstuff();
});
My plan is to get the parent of .next and its id so that I can use slide_array[parentID].otherstuff();
But ... it's not working propperly when I call the init function inside the for loop more then once.
More weird, some functions calls seem to work, other have no effect.
What am I doing wrong?
You can use Object.create.
var s1 = Object.create(slider),
s2 = Object.create(slider);
s1.init(...);
s2.init(...);
If you return this from init your will be able to chain like:
var s1 = Object.create(slider).init(...);
However at this point I would just ditch the object literal and use constructors, since this is what you need.
function Slider(slide_it) {
this.parent = $(slide_it);
}
Slider.prototype = {
constructor: Slider,
otherStuff: function () {}
};
var s1 = new Slider(...),
s2 = new Slider(...);
Write a function to return the object:
function slider() {
return {
"init":function(slide_it){
this.parent = $(slide_it);
/Count Elements and create a navigation depending on the count etc./
},
"otherstuff":{...}
};
}
Then:
slide_array.push( slider() );
That'll give you a separate object every time. In you're version, you're filling the array with references to the same single object.
Why not just turn that into a jQuery plugin ?
jQuery.fn.slider = function(options) {
return this.each(function() {
var sliderElem = $(this),
settings = $.extend({
speed : 3000,
something : 'other thing'
}, options);
otherStuff(sliderElem);
});
function otherStuff(elem) {
}
}
$('#accordion > div').slider();
No iteration or jumping through hoops, just call it on the collection and it creates a new slider for each element ?
I'm writing simple slider for my website. This slider contains list items. I want to use OOP approach.
My actual code:
var miniSlider = function(objId)
{
this.obj = $("#" + objId);
this.obj.settings = [];
this.obj.settings['items'] = $('ul li', this.obj).length;
this.pagerNext = this.obj.find("i.next");
this.pagerPrev = this.obj.find("i.prev");
this.pagerNext.on("click", function() {
alert(this.obj.settings['items']);
});
};
I can invoke a few other sliders (yes, that's why I introduced a class):
miniSlider("mini-slider");
The problem is that when I'm in jQuery this.pagerNext.on("click", function() { }); this is no longer my object but - it's become a clicked element. How can I access this.obj.settings after click in a well done way (and with multi sliders support)?
EDIT:
Here is a full code created with a cooperation with SOF community :)
var MiniSlider = function(objId)
{
this.obj = $("#" + objId);
this.obj.settings = {
items: $("ul li", this.obj).length,
autoChangeTime: 8000
};
this.obj.activeElement = null;
this.pagerNext = this.obj.find("i.next");
this.pagerPrev = this.obj.find("i.prev");
var self = this;
this.pagerNext.on("click", function() {
self.obj.activeElement = $('li.active', self.obj);
if(self.obj.settings.items > 0)
{
if(self.obj.activeElement.is(':last-child'))
{
$('li.active', self.obj).removeClass('active');
$('li', self.obj).first().addClass('active');
}
else
{
self.obj.activeElement.next().addClass('active').prev().removeClass('active');
}
}
});
this.pagerPrev.on("click", function()
{
self.obj.activeElement = $('li.active', self.obj);
if(self.obj.settings.items > 0)
{
if(self.obj.activeElement.is(':first-child'))
{
self.obj.activeElement.removeClass('active');
$('li', self.obj).last().addClass('active');
}
else
{
self.obj.activeElement.prev().addClass('active').next().removeClass('active');
}
}
});
this.obj.parent().on('mouseenter mouseleave', function(e) {
if (e.type == 'mouseenter')
{
$(this).addClass('stop');
}
else
{
$(this).removeClass('stop');
}
});
setInterval(function() {
if(self.obj.settings.items > 0 && !self.obj.parent().hasClass("stop"))
{
self.pagerNext.click();
}
}, this.obj.settings.autoChangeTime);
};
and invoke:
new MiniSlider("mini-slider");
Alex gave you the solution to the this problem in your callback, but there is another problem in your code.
You are calling the miniSlider() function without a new operator:
miniSlider("mini-slider");
That means that inside the function, this is not a unique object, but is actually the window object!
You need to use the new operator to create an individual object for each call:
new miniSlider("mini-slider");
But you should also change the name of this function to follow the JavaScript convention that constructors begin with a capital letter. Call it MiniSlider and use it like so:
new MiniSlider("mini-slider");
If you follow this convention (which most experienced JavaScript programmers do), it will help you remember when to use new. If the function begins with a capital letter, it's a constructor and you need to use new with it. Otherwise, you don't.
If you'd like to be able to use your constructor without new, that is also possible with a bit more code, e.g.:
function MiniSlider( objId ) {
if( this == window ) return new MiniSlider( objId );
// the rest of your constructor code goes here
}
But generally people don't bother with that and just use the initial capital letter on the constructor as a reminder to use new.
Also, as a suggestion, I like to use a meaningful name when I save this in a variable, and then I use that name consistently instead of using this at all. Doing it this way it might look like:
var miniSlider = function(objId) {
var slider = this;
slider.obj = $("#" + objId);
slider.obj.settings = [];
slider.obj.settings['items'] = $('ul li', slider.obj).length;
slider.pagerNext = slider.obj.find("i.next");
slider.pagerPrev = slider.obj.find("i.prev");
slider.pagerNext.on("click", function() {
alert(slider.obj.settings['items']);
});
};
Why do I prefer that approach over using this in most places and another variable like self where you need it? This way I don't have to remember which to use: I can always use slider in the code instead of this. (Of course you could use self or any other name; I just like to have a more meaningful name if I'm going to the trouble of making up a name at all.)
Another minor problem in the code is in these two statements:
slider.obj.settings = [];
slider.obj.settings['items'] = $('ul li', slider.obj).length;
You shouldn't use an Array when you are going to be giving it named properties like this. Use an Object instead. Arrays should only be used when you have numeric indexes like 0, 1, 2, etc. And with an object literal you can set the property at the same time:
slider.obj.settings = {
items: $('ul li', slider.obj).length
};
Also, when you use that property:
alert(slider.obj.settings['items']);
you can write it more simply as:
alert(slider.obj.settings.items);
Either way it does the same thing.
Save a reference to this in a local variable, and use that variable instead of this in the nested function.
var self = this;
this.pagerNext.on("click", function() {
alert(self.obj.settings['items']);
});
I have a problem, I want to create a JavaScript class:
function Calculatore(txt,elements) {
this.p= new Processor();
this.output=txt;
$(elements).click(this.clickHandler);
}
Calculatore.prototype.clickHandler = function() {
var element=$(this);
// Code Here
// "this" contains the element.
// But what if I want to get the "output" var?
// I tried with Calculatore.prototype.output but no luck.
}
So how can I solve this?
You can use jQuery's $.proxy:
function Calculatore(txt,elements) {
this.p= new Processor();
this.output=txt;
$(elements).click($.proxy(this.clickHandler, this));
}
Calculatore.prototype.clickHandler = function(event) {
var clickedElement = event.target;
alert(this.output);
}
Edited. Jason brought up a good point in the comments. It's probably better to use event.target which references only the element clicked, rather than elements which may reference an array of objects matching the selection.
You have a collision between this values. You currently don't have access to the instance because this has been set to the element inside a click handler.
You could make a proxy function to pass both the this value (the element) and the instance:
function Calculatore(txt,elements) {
this.p= new Processor();
this.output=txt;
var inst = this; // copy instance, available as 'this' here
$(elements).click(function(e) {
return inst.clickHandler.call(this, e, inst); // call clickHandler with
// 'this' value and 'e'
// passed, and send 'inst'
// (the instance) as well.
// Also return the return
// value
});
}
Calculatore.prototype.clickHandler = function(e, inst) {
var element = $(this);
var output = inst.output;
};
Let's say I have this jQuery extension method:
$.fn.foobar = function() {
var clone = this.parent().clone();
};
After I've gotten clone, how can I find the cloned child element that is the same as this?
Will this work?
$.fn.foobar = function() {
var clone = this.parent().clone();
var cloneOfThis = clone.find(this);
};
Or this?
$.fn.foobar = function() {
var clone = this.parent().clone();
var self = this;
var cloneOfThis;
clone.children().each(function() {
var $this = $(this);
if ($this === self) {
cloneOfThis = $this;
}
});
};
You could try giving it some unique class that could be used to refer back to the proper element.
$.fn.foobar = function() {
// Add a class to "this", then clone its parent
var clonedParent = this.addClass("someUniqueClass").parent().clone();
// Reference the new clone of "this" inside the cloned parent,
// then remove the class
var cloneOfThis = clonedParent.find(".someUniqueClass").removeClass("someUniqueClass");
// Remove the class from the original
this.removeClass("someUniqueClass");
};
You can't get a reference comparison to work here because this isn't in the clone, it's the original element, it wasn't moved. An element like the one you cloned is in the cloned parent, so you have to decide what "the same" means, is it the same ID, the same HTML content, the same value?
You just need to pick a value you can compare, because the reference won't work here...you can't find something that isn't there :)
Taking patrick dw's answer a little further, and incorporating Felix King's comment, I would suggest the following:
$.fn.foobar = function() {
return $(this).each(function() {
// Add a class to "this", then clone its parent
var clonedParent = $(this).addClass("someUniqueClass").parent().clone();
// Reference the new clone of "this" inside the cloned parent
var cloneOfThis = clonedParent.find(".someUniqueClass");
//remove the unique class to preserve the original state (other than the clone which is now present)
$('.someUniqueClass').add(cloneOfThis).removeClass('someUniqueClass');
});
};