Optimizing JQuery - javascript

I have Jquery code that looks like this. Is there a way to optimize this code? What happens if the image doesn't have a title attribute? Should I insert a case for using the value of the alt attribute as a backup and If I'm chaining the .attr() function multiple times, then it'd be cleaner code I you just ran the .attr() function a single time passing a value pair object of all my properties to the function. How can I do this ?
$(function() {
$('.component-individual-detail-profile').each(function() {
var $self = $(this), $images = $self.find('.photos');
$images.find('li').click(function(e) {
e.preventDefault();
var thumb = $(this);
$images.find('.selected')
.attr('src', thumb.find('img').attr('src'))
.attr('alt', thumb.find('img').attr('alt'))
.attr('title', thumb.find('img').attr('title'));
});
});
});

You can store the attributes in a array, and cache the $thumb.find('img') selector:
$('.component-individual-detail-profile').each(function() {
var $self = $(this);
var $images = $self.find('.photos');
$images.find('li').click(function(e) {
e.preventDefault();
var $thumb = $(this).find('img');
var $selected = $images.find('.selected');
$.each(['src', 'alt', 'title'], function(index, attrName){
$selected.attr(attrName, $thumb.attr(attrName));
});
});
});

Have you considered var thumb = $(this).find("img") for starters? Anywhere your code repeats function calls, you're probably doing something wrong.
Regarding "what if there is no attribute", you can do thumb.attr('title') || thumb.attr('alt'), using the logical or (||) to provide a value if the first one doesn't exist.
According to the documentation, you can do...
$images.find('.selected').attr({
src: thumb.attr('src'),
alt: thumb.attr('alt'),
title: thumb.attr('title') || thumb.attr('alt')
});

Related

Efficiently removing items from the DOM

This is kind of a nitpicky question, but I'm curious which would be a more efficient implementation.
I'm adding an overlay and a spinner over an element, then later I'm removing it.
I can define two methods:
addSpinner: function() {
$('<div></div>').addClass('overlay').appendTo('#myDiv');
$('<img>').attr('src', 'images/spinner.gif').addClass('spinner').appendTo('#myDiv');
},
removeSpinner: function() {
$('.overlay, .spinner', this.el).remove();
},
The remove spinner is going to have to look for those elements each time I call it. So my other option is to have addSpinner re-define removeSpinner with a more direct reference to the elements.
addSpinner: function() {
var overlay = $('<div></div>').addClass('overlay').appendTo('#myDiv');
var spinner = $('<img>').attr('src', 'images/spinner.gif').addClass('spinner').appendTo('#myDiv');
this.removeSpinner = function() {
overlay.remove();
spinner.remove();
};
},
This means no searching the DOM for those two elements, but the function is redefined each time. Pros and Cons?
I don't think it's relevant but these are Backbone/Marionette views.
The most efficient would probably be to keep a reference to the elements that you can use when you remove them, something like
var obj = {
addSpinner: function() {
this.overlay = $('<div />', {'class' : 'overlay'});
this.spinner = $('<img />', {'class' : 'spinner', src : 'images/spinner.gif'});
$('#myDiv').append(this.overlay, this.spinner);
},
removeSpinner: function() {
this.overlay.add(this.spinner).remove();
}
}
That way you don't have to call jQuery or query the DOM uneccessary

$(this) and scope - passing a specific element

I have a variety of .img-drop-zones and upon drop a file is read, I wish to display it on top of the specific drop zone it was placed on, but how do I get it? $(this) does not work because of scope, how can I pass it through?
$('.img-drop-zone').on('drop', function(e){
var files = e.originalEvent.dataTransfer.files;
$.each(files, function(index, file){
p.file.read(file, function(content) {
//how can I get the img-drop zone here?
});
})
});
Just declare an additional variable in the outer scope that you can refer to within the $.each closure:
var $this = $(this);
$.each(..., function() {
// use $this here to refer to the img-drop-zone
});
When referring to an object to something that isn't a jQuery object it's more common to use self or that.
$(this) is what you need
$('.img-drop-zone').on('drop', function(e){
var files = e.originalEvent.dataTransfer.files;
var dropJone = $(this);
$.each(files, function(index, file){
p.file.read(file, function(content) {
//how can I get the img-drop zone here?
//use dropJone here
});
})
});

Call Javascript Function with argument and use argument as a variable name

I've the following snip of a code:
var about = "about.html";
function loadPage(target){
$("#dashboard").load(target);
}
$(".nav li").click(function(){
loadPage($(this).attr("class"));
});
So when I click on a button like <li class="about">, target is = about.
But in that way, $("#dashboard").load(target); doesn't load the variable about which is the html-file which I want to load.
So how is it possible to call the variable in this way?
You seem to miss the .html part. Try with
$("#dashboard").load(target+'.html');
But, supposing you have only one class on your li element, you'd better use this.className rather than $(this).attr("class").
EDIT :
if you want to use your about variable, you may do this :
$("#dashboard").load(window[target]);
But it would thus be cleaner to have a map :
var pages = {
'about': 'about.html',
'home': 'welcome.jsp'
}
function loadPage(target){
$("#dashboard").load(pages[target]);
}
$(".nav li").click(function(){
loadPage(this.className);
});
A stupid answer : create a <a> tag, and set its href attribute to the correct value.
Otherwise :
A standard way to store key: values pairs in javascript is to use a plain object :
var urls = {};
urls['about'] = 'mysuperduperurlforabout.html';
function loadPage(target) {
var url = urls[target];
//maybe check if url is defined ?
$('#dashboard').load(url);
}
$(".nav li").click(function(){
loadPage($(this).attr("class") + ".html");
});
or
$("#dashboard").load(target+".html");
You can call the variables like this (if that's what you asked):
var test = 'we are here';
var x = 'test';
console.log(window[x]);
It's similar to the $$ in PHP. The output will be:
we are here in the console window.
You could put the "about" as an object or array reference similar to:
var pageReferences = [];
pageReferences["about"] = "about.html";
var otherReference = {
"about": "about.html"
};
function loadPage(target) {
alert(pageReferences[target]);
alert(otherReference[target]);
$("#dashboard").load(target);
}
$(".nav li").click(function () {
loadPage($(this).attr("class"));
});
Both of these alerts will alert "about.html" referencing the appropriate objects.
EDIT: IF you wished to populate the object based on markup you could do:
var otherReference = {};
$(document).ready(function () {
$('.nav').find('li').each(function () {
var me = $(this).attr('class');
otherReference[me] = me + ".html";
});
});
You could even store the extension in an additional attribute:
var otherReference = {};
$(document).ready(function () {
$('.nav').find('li').each(function () {
var me = $(this).attr('class');
otherReference[me] = me + "." + $(this).attr("extension");
});
});
Better would be to simply put the page reference in a data element:
<li class="myli" data-pagetoload="about.html">Howdy</li>
$(".nav li").click(function () {
loadPage($(this).data("pagetoload"));
});

How to get outer element value in JavaScript

I have the following jQuery code:
$('.active #search').on('mouseout', function () {
$('#search_box #search').not('.active').each(function(){
this.value = $('.active #search')[0].value;
})
});
It works, but I have to call $('.active #search') twice. How can I refer to the $('.active #search') array from within my inner function?
P/S: I know I'll be complained about giving multiple elements same ID, but this seem to be generated by Rails automatically (text_field_tag).
I think this is what you're looking for:
$('.active #search').on('mouseout', function () {
var val = $(this)[0].value; //cache value of $('.active #search').
$('#search_box #search').not('.active').each(function () {
this.value = val;
})
});
You can do something like below. I added self = $(this)
$('.active #search').on('mouseout', function () {
var self = $(this);
$('#search_box #search').not('.active').each(function(){
this.value = self[0].value;
});
});
Here is a link to very good explanation of 'this' keyword, explained by Jeffrey Way
tutsplus.com/lesson/the-this-keyword
Therese several ways of achieving this:
var activeSearch = $('.active #search');
activeSearch.on('mouseout', function () {
$('#search_box #search').not('.active').each(function(){
this.value = activeSearch.val();
})
});
notice that since this is an id you are querying for you should have only one element so you can replace activeSearch[0].value with activeSearch.val();
second way:
$('.active #search').on('mouseout', function () {
var activeSearch = $(this);
$('#search_box #search').not('.active').each(function(){
this.value = activeSearch.val();
})
});
when in an event handler $(this) will give you a jquery object of the event sender. you can further simplify it by ignoring jquery and just using plain elements by doing the following:
$('.active #search').on('mouseout', function () {
var activeSearch = this;
$('#search_box #search').not('.active').each(function(){
this.value = activeSearch.value;
})
});
this is the same as above but you arent dealing with jquery objects.
What you end up using depends on you but the final code snippet would be my preferred way.
You can use $(this) instead of using the $('.active #search')

How to get image id using jQuery?

I have written code like this. <img id='test_img' src='../../..' />
I want to get the id of this image on image load like,
$(img).load(function() {
// Here I want to get image id i.e. test_img
});
Can you please help me?
Thanks.
$(img).load(function() {
var id = $(this).attr("id");
//etc
});
good luck!!
edit:
//suggested by the others (most efficient)
var id = this.id;
//or if you want to keep using the object
var $img = $(this);
var id = $img.attr("id")
Don't use $(this).attr('id'), it's taking the long, inefficient route. Just this.id is necessary and it avoids re-wrapping the element with jQuery and the execution of the attr() function (which maps to the property anyway!).
$(img).load(function() {
alert(this.id);
});
$(function() {
$('img#test_img').bind('load', function() {
console.log(this.id); //console.log($(this).attr('id'));
});
});
$(img).load(function() {
alert($(this).attr('id'));
});

Categories