Passing two different arguments to function - javascript

I have written some jQuery functions, and recently realized I needed to reuse the code for another situation. I refactored the code to accept a selector as an arguement, so I can now use for case 1, and case 2. However, when I execute my functions in document.ready I get weird results.
$( document ).ready(function() {
imageCalc('.com-background > img');
setImageDims('.com-background > img', '#main-content');
imageCalc('.blog-entry-content iframe');
setImageDims('.blog-entry-content iframe', '#content');
});
It should be noted, these selectors do no show up on the same page. Also, when I only run one instance of imageCalc() and setImageDims() These functions work just fine. Here are the functions in question..
function imageCalc(selector) {
var obj=$(selector);
$imgWidth = obj.width();
$imgHeight = obj.height();
$imgAspectRatio = $imgHeight / $imgWidth;
// $(selector).css('margin-left', function( calcMargin ) { return parseInt($('.main-content').css('padding')) * -1 + "px"; }); fix for ie
obj.css('margin-left', '-10px' );
}
function setImageDims(selector, content_area) {
var container = $(content_area);
$(selector).css('height', function() { return $imgAspectRatio * container.width(); });
$(selector).css('width', function() { return container.width() + 20; });
}
In summary, all the code works just fine, when I only have each function called only ONCE in document.ready but I need to use this code for 2 scenarios, how can I do this?

Add a var in front of your $imgWidth, $imgHeight, and $imgAspectRatio variables. Without the var, they're being declared at global scope, and therefore accidentally getting shared across both calls to that function.
UPDATE: I just noticed that the $imgAspectRatio is being used by both functions. Perhaps you can make that the return value from the first function, so it can be passed into the second function.
To elaborate... something like this should theoretically work, although I'm not able to test it since I don't have the corresponding HTML:
function imageCalc(selector) {
var obj=$(selector);
var $imgWidth = obj.width();
var $imgHeight = obj.height();
var $imgAspectRatio = $imgHeight / $imgWidth;
// $(selector).css('margin-left', function( calcMargin ) { return parseInt($('.main-content').css('padding')) * -1 + "px"; }); fix for ie
obj.css('margin-left', '-10px' );
return $imgAspectRatio;
}
function setImageDims(selector, content_area, $imgAspectRatio) {
var container = $(content_area);
$(selector).css('height', function() { return $imgAspectRatio * container.width(); });
$(selector).css('width', function() { return container.width() + 20; });
}
$( document ).ready(function() {
var ratio1 = imageCalc('.com-background > img');
setImageDims('.com-background > img', '#main-content', ratio1);
var ratio2 = imageCalc('.blog-entry-content iframe');
setImageDims('.blog-entry-content iframe', '#content', ratio2);
});

This will require you to re-work your functionsas setImageDims depends on $imgAspectRatio to be available globally.
function imageCalc(selector) {
var obj=$(selector),
$imgWidth = obj.width(),
$imgHeight = obj.height(),
$imgAspectRatio = $imgHeight / $imgWidth;
// $(selector).css('margin-left', function( calcMargin ) { return parseInt($('.main-content').css('padding')) * -1 + "px"; }); fix for ie
obj.css('margin-left', '-10px' );
return $imgAspectRatio;
}
function setImageDims(selector, content_area) {
var container = $(content_area);
$(selector).css('height', function() { return imageCalc(selector) * container.width(); });
$(selector).css('width', function() { return container.width() + 20; });
}

Related

(this).attr() stops working after jquery.noConflict()

I had this code initially that worked on one project but when i decided to port it to another project, it has issues with the $.
So i decided to use the jQuery.noConflict() method to resolve it. It resolved alright but the .attr() method now returns undefined.
Initial Code
$(".sharebtn").click(function(event)
{
event.preventDefault();
content = $(this).attr("data-share-content"); content_id = $(this).attr("data-share-contentid"); medium=$(this).attr("data-share-medium");
cur_count = parseInt($("#share_count_holder_"+content_id).val());
if(cur_count<=999){$("#post-share-count").html((cur_count+1));}
if(cur_count>999 && cur_count<=1000000){ disp=parseFloat(Math.round((cur_count/1000)+'e1')+'e-1'); $("#post-share-count").html(disp+"K"); }
if(cur_count>1000000){ disp=parseFloat(Math.round((cur_count/1000000)+'e1')+'e-1'); $("#post-share-count").html(disp+"M"); }
$("#share_count_holder").val((cur_count+1));
window.open($(this).attr("data-share-link"),"popupWindow","width=600,height=400,scrollbar=yes");
var url = bh_url+'/admin-2/modules/blog/candor_blogger_ajax.php?action=run_share';
$.post(url,{ content_type:content, content_id:content_id, medium:medium} ,function(data) { },"json");
});
After noConflict()
var bh = jQuery.noConflict();
bh(".sharebtn").click(function(event)
{
event.preventDefault();
content = bh(this).attr("data-share-content"); content_id = bh(this).attr("data-share-contentid"); medium=bh(this).attr("data-share-medium");
cur_count = parseInt(bh("#share_count_holder_"+content_id).val());
if(cur_count<=999){bh("#post-share-count").html((cur_count+1));}
if(cur_count>999 && cur_count<=1000000){ disp=parseFloat(Math.round((cur_count/1000)+'e1')+'e-1'); bh("#post-share-count").html(disp+"K"); }
if(cur_count>1000000){ disp=parseFloat(Math.round((cur_count/1000000)+'e1')+'e-1'); bh("#post-share-count").html(disp+"M"); }
bh("#share_count_holder").val((cur_count+1));
window.open(bh(this).attr("data-share-link"),"popupWindow","width=600,height=400,scrollbar=yes");
var url = bh_url+'/admin-2/modules/blog/candor_blogger_ajax.php?action=run_share';
bh.post(url,{ content_type:content, content_id:content_id, medium:medium} ,function(data) { },"json");
});
The click event fires but when i log the content to console i get undefined. - When I restore the $, it works fine in the old project.
What could be my problem.
Try using an IFFE and passing in jQuery like this:
jQuery.noConflict(); // releases $ back to any other library that might be using it
(function($) { // IIFE passing in jQuery as $, inside the scope of this function $ is an now alias for jQuery
$(".sharebtn").click(function(event) {
event.preventDefault();
content = $(this).attr("data-share-content");
content_id = $(this).attr("data-share-contentid");
medium = $(this).attr("data-share-medium");
cur_count = parseInt($("#share_count_holder_" + content_id).val());
if (cur_count <= 999) {
$("#post-share-count").html((cur_count + 1));
}
if (cur_count > 999 && cur_count <= 1000000) {
disp = parseFloat(Math.round((cur_count / 1000) + 'e1') + 'e-1');
$("#post-share-count").html(disp + "K");
}
if (cur_count > 1000000) {
disp = parseFloat(Math.round((cur_count / 1000000) + 'e1') + 'e-1');
$("#post-share-count").html(disp + "M");
}
$("#share_count_holder").val((cur_count + 1));
window.open(bh(this).attr("data-share-link"), "popupWindow", "width=600,height=400,scrollbar=yes");
var url = bh_url + '/admin-2/modules/blog/candor_blogger_ajax.php?action=run_share';
$.post(url, {
content_type: content,
content_id: content_id,
medium: medium
}, function(data) {}, "json");
});
}(jQuery)); // pass in jQuery

jQuery .data() is being overwritten

I currently have the following code for a jQuery tooltip plugin I am writing. I am storing the config for each tooltip with jQuery's .data() method. However, when I go to retrieve the data it has been overwritten by the most recently stored data from a completely different selector. I can't figure out the issue as it was working prior and then suddenly stopped. The main areas to look in are the addTooltip(), removeTooltip(), and displayTooltip().
Example:
$('#tooltip1').addTooltip('tooltip', { 'direction': 'bottom' });
$('#tooltip2').addTooltip('tooltip', { 'direction': 'left' });
In the above example I am selecting two completely different elements however when I display the #tooltip1 tooltip it will be using #tooltip2's config which in this case is 'direction': 'left'.
Any help is appreciated.
(function($) {
// Used as a template for addTooltip()
var tooltipDefaults = {
'class': null,
'showOn': 'mouseenter',
'hideOn': 'mouseleave',
'direction': 'top',
'offset': 0
}
// Store generated IDs to avoid conflicting IDs
var tooltipIds = new Array();
// Keep track of displayed popups
var displayedTooltips = new Array();
function generateUniqueId()
{
var id;
do {
id = Math.floor(Math.random()*90000) + 10000;
} while ($.inArray(id, tooltipIds) !== -1);
tooltipIds.push(id);
return id;
}
function getUniqueId(id)
{
return parseInt(id.substr(0, 5));
}
function isUniqueId(id)
{
return !NaN(getUniqueId(id));
}
function removeUniqueId(id)
{
var id = getUniqueId(id);
var idIndex = $.inArray(id, tooltipIds);
if (idIndex !== -1) {
tooltipIds.splice(idIndex);
}
}
$.fn.displayTooltip = function()
{
var element = $(this);
var tooltip = $('#' + element.attr('data-tooltip-id'));
var config = element.data('config');
var offset = element.offset();
var left;
var top;
switch (config.direction) {
case 'left':
top = offset.top + "px";
left = offset.left - tooltip.outerWidth() - config.offset + "px";
break;
case 'top':
top = offset.top - element.outerHeight() - config.offset + "px";
left = offset.left + ((element.outerWidth() / 2) - (tooltip.outerWidth() / 2)) + "px";
break;
case 'right':
top = offset.top + "px";
left = offset.left + element.outerWidth() + config.offset + "px";
break;
case 'bottom':
top = offset.top + element.outerHeight() + config.offset + "px";
left = offset.left + ((element.outerWidth() / 2) - (tooltip.outerWidth() / 2)) + "px";
break;
}
tooltip.css({
'position': 'absolute',
'left': left,
'top': top,
'z-index': 5000
});
if (element.isTooltipDisplayed()) {
return;
}
tooltip.show();
displayedTooltips.push(element.attr('id'));
}
$.fn.hideTooltip = function()
{
var element = $(this);
var idIndex = $.inArray(element.attr('id'), displayedTooltips);
if (idIndex !== -1) {
displayedTooltips.splice(idIndex);
}
$('#' + element.attr('data-tooltip-id')).hide();
}
$.fn.addTooltip = function(content, params)
{
var config = $.extend(tooltipDefaults, params);
return this.each(function() {
var element = $(this);
// If the element already has a tooltip change the content inside of it
if (element.hasTooltip()) {
$('#' + element.attr('data-tooltip-id')).html(content);
return;
}
var tooltipId = (element.is('[id]') ? element.attr('id') : generateUniqueId()) + '-tooltip';
element.attr('data-tooltip-id', tooltipId);
var tooltip = $('<div>', {
id: tooltipId,
role: 'tooltip',
class: config.class
}).html(content);
$('body').append(tooltip);
/**
* If showOn and hideOn are the same events bind a toggle
* listener else bind the individual listeners
*/
if (config.showOn === config.hideOn) {
element.on(config.showOn, function() {
if (!element.isTooltipDisplayed()) {
element.displayTooltip();
} else {
element.hideTooltip();
}
});
} else {
element.on(config.showOn, function() {
element.displayTooltip();
}).on(config.hideOn, function() {
element.hideTooltip();
});
}
// Store config for other functions use
element.data('config', config);
// Saftey check incase the element recieved focus from the code running above
element.hideTooltip();
});
}
$.fn.hasTooltip = function()
{
return $(this).is('[data-tooltip-id]');
}
$.fn.isTooltipDisplayed = function()
{
var element = $(this);
if (!element.hasTooltip()) {
return false;
}
return ($.inArray(element.attr('id'), displayedTooltips) === -1) ? false : true;
}
$.fn.removeTooltip= function()
{
return this.each(function() {
var element = $(this);
var tooltipId = element.attr('data-tooltip-id');
var config = element.data('config');
$('#' + tooltipId).remove();
if (isUniqueId(tooltpId)) {
removeUniqueId(tooltipId);
}
element.removeAttr('data-tooltip-id');
if (config.showOn === config.hideOn) {
element.off(config.showOn);
} else {
element.off(config.showOn);
element.off(config.hideOn);
}
element.removeData('config');
});
}
// Reposition tooltip on window resize
$(window).on('resize', function() {
if (displayedTooltips.length < 1) {
return;
}
for (var i = 0; i < displayedTooltips.length; i++) {
$('#' + displayedTooltips[i]).displayTooltip();
console.log(displayedTooltips);
}
});
}(jQuery));
When you do this:
element.data('config', config);
config will be prone to unwanted modification whenever we call:
var config = $.extend(tooltipDefaults, params);
An example of this: http://jsfiddle.net/j8v4s/1/
You can solve this by creating a new object that inherits from tooltipDefaults but when modified, only itself will be changed. You can make your tooltipDefaults object a constructor like so:
function TooltipDefaults() {
this.class = null;
this.showOn = 'mouseenter';
this.hideOn = 'mouseleave';
this.direction = 'top';
this.offset = 0;
}
Now we can just do this:
var config = new TooltipDefaults();
$.extend(config, params);
Example: http://jsfiddle.net/sXSFy/4/
And here's a working example of your plugin: http://jsfiddle.net/DWtL5/2/
put the declaration of config inside the each loop
return this.each(function() {
var element = $(this);
var config = $.extend(tooltipDefaults, params);
...
otherwise the config in each of the elements data is going to reference that single config object, and when you change it the changes will be seen by each of the references.
You can also use the extend method again to make a clone of the config
var defConfig = $.extend(tooltipDefaults, params);
return this.each(function() {
var element = $(this);
var config = $.extend({}, defConfig);

jQuery interval won't restart after hover out

After calling a PHP function, which generates the HTML,
I call the function below for the specific slider id.
That works fine, hover pauses the slideshow, also ok.
But when I am hovering out of the section, firebug gives the following error:
TypeError: o.handler.apply is not a function
And the slideshow won't continue.
Thanks in advance.
function CallSlider(sliderid){
var $slider = $('#'+sliderid);
var $slide = 'li';
var $transition_time = 1000; // 1 second
var $time_between_slides = 2000; // 4 seconds
function slides(){
return $slider.find($slide);
}
slides().fadeOut();
// set active classes
slides().first().addClass('active');
slides().first().fadeIn($transition_time);
$('#'+sliderid).hover(function() {
clearInterval(sliderid);
}, sliderid = setInterval(
function(){
var $i = $slider.find($slide + '.active').index();
//alert('test');
slides().eq($i).removeClass('active');
slides().eq($i).fadeOut($transition_time);
if (slides().length == $i + 1) $i = -1; // loop to start
slides().eq($i + 1).fadeIn($transition_time);
slides().eq($i + 1).addClass('active');
}
, $transition_time + $time_between_slides
)
);
}
I believe that error is related to the fact that hover() expects parameters to be functions.
Type: Function() - A function to execute when the mouse pointer enters/leaves the element.
http://api.jquery.com/hover/
I suggest putting your "hover off" code in its own function, like so:
$('#'+sliderid).hover(
function() {
// hover over
clearInterval(sliderid);
},
function () {
// hover off
sliderid = setInterval(...);
}
);
EDIT:
Here's an example, based on the code you provided, of how to keep things flexible (i.e. for dynamic lists).
var slide = 'li';
var transition_time = 1000; // 1 second
var time_between_slides = 2000; // 4 seconds
function startCycle($slider, $slides) {
return setInterval(
function () {
var $thisslide=jQuery(slide+'.active',$slider);
var $nextslide=($thisslide.next(slide).length?$thisslide.next(slide):$slides.eq(0));
$thisslide.removeClass('active').fadeOut(transition_time);
$nextslide.fadeIn(transition_time).addClass('active');
}, transition_time + time_between_slides
);
}
jQuery('ul.slider').each(function () {
var sliderid;
var $slider = jQuery(this);
var $slides = $slider.find(slide);
$slides.fadeOut();
// set active classes
$slides.first().addClass('active').fadeIn(transition_time);
$slider.hover(
function () {
// hover over
clearInterval(this.sliderid);
},
function () {
// hover off
this.sliderid = startCycle($slider, $slides);
}
);
this.sliderid = startCycle($slider, $slides);
});
http://jsfiddle.net/gk74V/1/

how to get property from other function

I want to access var w value from other function. Is it possible.
<script type="text/javascript">
var first = {
myFirst: function(){
var w= 90;
var q=12;
}}
var second= {
mySecond: function(){
first.myFirst.w
}}
</script>
In that way you cannot access w because it's defined in the local scope of myFirst. You can do something like:
var first = {
myFirst: function(){
first.myFirst.w = 90;
var q=12;
}
};
var second= {
mySecond: function(){
alert(first.myFirst.w);
}
};
first.myFirst();
second.mySecond(); //alerts 90
In that way w will be added as property of the function myFirst, if you want to add it as property of first, use:
var first = {
myFirst: function(){
this.w = 90;
var q=12;
}
};
var second= {
mySecond: function(){
alert(first.w);
}
};
first.myFirst();
second.mySecond(); //alerts 90
No, that's not possible, because the scope of w is within the function. Once the function has been called w no longer exists.
Also, technically you would need to call first.myFirst().w;
To get that to work you could do this instead:
var first = {
myFirst: function(){
var w= 90;
var q=12;
return { w : w };
}
}
first.myFirst().w // now works.

Extend Zepto.js with a jQuery method? scrollTop()

I'm using Zepto.js on a current project. Zepto doesn't support the scrollTop() method that jQuery has in it.
Is it possible to kind of extend Zepto to work with scrollTop() too?
Update: All I want is to create my own small and simple "animated scroll" function like I have used before with jQuery. See the working example here. However I have no idea how to make the same function work without the scrollTop() function available in Zepto.js.
scrollTop isn't animatable using Zepto's .animate method, as it uses CSS transitions.
Try something like this: http://jsfiddle.net/DVDLM/5/
function scroll(scrollTo, time) {
var scrollFrom = parseInt(document.body.scrollTop),
i = 0,
runEvery = 5; // run every 5ms
scrollTo = parseInt(scrollTo);
time /= runEvery;
var interval = setInterval(function () {
i++;
document.body.scrollTop = (scrollTo - scrollFrom) / time * i + scrollFrom;
if (i >= time) {
clearInterval(interval);
}
}, runEvery);
}
$('#trigger').click(function () {
scroll('600px', 500);
});
EDIT: I added a runEvery variable, which specifies how often the interval should be ran. The lower this is, the smoother the animation is, but it could affect performance.
EDIT2: I think I misread the question. Here is the answer to the new question:
$.zepto.scrollTop = function (pixels) {
this[0].scrollTop = pixels;
};
dont want to steel nobody work so here is the short answer
Porting from jQuery to Zepto
Use the DOM native scrollTop property:
$('#el')[0].scrollTop = 0;
(function ($) {
['width', 'height'].forEach(function(dimension) {
var offset, Dimension = dimension.replace(/./, function(m) { return m[0].toUpperCase() });
$.fn['outer' + Dimension] = function(margin) {
var elem = this;
if (elem) {
var size = elem[dimension]();
var sides = {'width': ['left', 'right'], 'height': ['top', 'bottom']};
sides[dimension].forEach(function(side) {
if (margin) size += parseInt(elem.css('margin-' + side), 10);
});
return size;
}
else {
return null;
}
};
});
["Left", "Top"].forEach(function(name, i) {
var method = "scroll" + name;
function isWindow( obj ) {
return obj && typeof obj === "object" && "setInterval" in obj;
}
function getWindow( elem ) {
return isWindow( elem ) ? elem : elem.nodeType === 9 ? elem.defaultView || elem.parentWindow : false;
}
$.fn[method] = function( val ) {
var elem, win;
if (val === undefined) {
elem = this[0];
if (!elem) {
return null;
}
win = getWindow(elem);
// Return the scroll offset
return win ? ("pageXOffset" in win) ? win[i ? "pageYOffset" : "pageXOffset"] :
win.document.documentElement[method] ||
win.document.body[method] :
elem[method];
}
// Set the scroll offset
this.each(function() {
win = getWindow(this);
if (win) {
var xCoord = !i ? val : $(win).scrollLeft();
var yCoord = i ? val : $(win).scrollTop();
win.scrollTo(xCoord, yCoord);
}
else {
this[method] = val;
}
});
}
});
})(Zepto);
The answer is simple, Zepto dose not use timeout style animation, it uses css3, so here is a basic implementation for a scroll function:
HTML:
Animated Scroll
Hello You
​
CSS:
#page { height:5000px; position:relative; }
#element { position:absolute; top:600px }
JS:
function scroll(selector, animate, viewOffset) {
$('body').scrollToBottom (600, '800');
}
$('#trigger').click(function(e) {
e.preventDefault();
scroll( $('#element'), true, 30 );
});
$.fn.scrollToBottom = function(scrollHeight ,duration) {
var $el = this;
var el = $el[0];
var startPosition = el.scrollTop;
var delta = scrollHeight - startPosition;
var startTime = Date.now();
function scroll() {
var fraction = Math.min(1, (Date.now() - startTime) / duration);
el.scrollTop = delta * fraction + startPosition;
if(fraction < 1) {
setTimeout(scroll, 10);
}
}
scroll();
};
​
Note that version 1.0 of Zeptos now supports scrollTop(). See Documentation:
http://zeptojs.com/#scrollTop

Categories