I need to improve my jquery code where I repeat my function 6 times!!!
is there away to do a loop to shorten the code ?
(function( jQuery ){
jQuery.fn.vesta = function(imgN){
var imgPath = "http://localhost:8080/mhost/media/magentohost/vesta/vesta"
var currImg = imgPath + imgN + ".png";
var targetImg = jQuery('.img-browser img');
jQuery('.img-browser img').attr('src', currImg);
}
})( jQuery );
jQuery('.vesta1').on('click', function (e) {
jQuery('.vesta1').vesta(1);
});
jQuery('.vesta2').on('click', function (e) {
jQuery('.vesta2').vesta(2);
});
jQuery('.vesta3').on('click', function (e) {
jQuery('.vesta3').vesta(3);
});
jQuery('.vesta4').on('click', function (e) {
jQuery('.vesta4').vesta(4);
});
jQuery('.vesta5').on('click', function (e) {
jQuery('.vesta5').vesta(5);
});
jQuery('.vesta6').on('click', function (e) {
jQuery('.vesta6').vesta(6);
});
You can DRY this up by using a common class, and a data attribute to specify the parameter to send to your vesta function:
<div class="vesta" data-vesta="1">1</div>
<div class="vesta" data-vesta="2">2</div>
<div class="vesta" data-vesta="3">2</div>
Then there is no need to loop at all:
$('.vesta').on('click', function (e) {
$(this).vesta($(this).data('vesta'));
});
Use a common class and a data attribute
jQuery('.vesta').on('click', function (e) {
var elem = $(this);
elem.vesta(elem.data("ind"));
});
and the HTML
<div class="vesta vesta1" data-ind="1">
Just put it into a for loop, and take advantage of the dynamic nature of JavaScript:
for (var i = 1; i <= 6; i++) {
$('.vesta' + i).on('click', (function (index) {
return function (e) {
$('.vesta' + index).vesta(index);
};
})(i));
}
I suppose you need the this reference along with some hack kind of thing
$('[class*=vespa]').on('click', function(e){
$(this).vesta(+(this.className.match(/vespa(\d+)/)[1]))
});
Here, we capture elements which have a class that matches at least vespa and then we use some bit of regex to match the digits after vespa and + unary operator changes the String version of numbers into actual numbers.
It would be quite easy if you can alter the structure of the HTML.
You would give all elements the same class, say vesta. But you also give them an attribute, say data-number. For example, like this:
<div class="vesta" data-number="4"></div>
Then, your jQuery code would be as simple as:
$(document).on({
click: function() {
var $this = $(this),
number = +$this.data('number');
$this.vesta(number);
}
}, '.vesta');
Edit:
I was a bit lazy with explaining the code snippet that I have provided an hour ago, but I am modifying my post now in response to the comments.
This code snippet will allow you to apply listeners from '.vesta1' elements to '.vestaN'
[#Variable]
NumberOfClasses - is the positive integer after 'vesta'. Eg: vesta1 ,vesta2, vesta100 ... etc
var NumberOfClasses=6;
for(var i=1;i<=NumberOfClasses;i++){
var className = '.vesta'+(i+1);
jQuery(className ).on('click', function (e) {
$(this).vesta(i);
});
}
Related
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 7 years ago.
I'm using a plugin that uses jQuery(document).on() to activate a modal. I have a bunch of modals on the page.
If I manually create an .on for each modal opening/closing everything works as
jQuery(document).on('opened', '[data-remodal-id=modal-1]',
function() {
player1.api('play')
});
jQuery(document).on('closed', '[data-remodal-id=modal-1]',
function(e) {
player1.api('unload')
});
jQuery(document).on('opened', '[data-remodal-id=modal-2]',
function() {
player2.api('play');
});
jQuery(document).on('closed', '[data-remodal-id=modal-2]',
function(e) {
player2.api('unload');
});
However this is a managed page, that could need 2,3 or 10 modals with their own content. I'm trying to do what I did above, only dynamically. Here's my attempt, and I can see why it doesn't work, but I have no idea how to approach this properly.
var countPlusOne;
for (i=0;i<players.length;i++){
countPlusOne=i+1;
var dataSelector = '[data-remodal-id=modal-'+countPlusOne+']';
jQuery(document).on('opened', dataSelector, function () {
players[i].api('play');
});
jQuery(document).on('closed', dataSelector, function (e) {
players[i].api('unload');
});
}
Hopefully it gives you some idea of what i'm trying to do? Is it even possible?
Per my understanding, you have dynamic elements and have to bind events to them.
You can try something like this:
var count = 1;
function addInput(){
var content = document.getElementById("content");
var input = "<input id='txt_"+count+"' class='input'>";
count++;
content.innerHTML+=input;
}
function registerEvents(){
$(document).on("blur", ".input", function(){
console.log($(this).attr("id"));
})
}
registerEvents();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id="content"></div>
<button onclick="addInput()">Add input</button>
If playerX are global vars, you could refactorize your code to this:
jQuery(document).on('opened closed', '[data-remodal-id]', function (e) {
window["player" + $(this).data("remodalId").replace('modal-' ,'')].api(e.type === "opened" ? 'play' : 'unload');
});
But i guess you don't need all this different playerX variables anyway.
Ultimately, your api() should handle player id and it would be called like that e.g:
player.api(1, 'play');
EDIT: Ok i'm miss this part in OP
I'm using a plugin
So you shouldn't override api() method.
EDIT2: to answer your question, using closure, you could use:
var countPlusOne;
for (i = 0; i < players.length; i++) {
(function(i) {
countPlusOne = i + 1;
var dataSelector = '[data-remodal-id=modal-' + countPlusOne + ']';
jQuery(document).on('opened', dataSelector, function() {
players[i].api('play');
});
jQuery(document).on('closed', dataSelector, function(e) {
players[i].api('unload');
});
})(i);
}
Is there a way to use jQuery selectors in modular way:
var logo = $('.logo', function() {
function show () {
console.log('logo has appeared');
$(this).addClass('logo-animated');
};
function hide() {
console.log('logo has been removed');
};
});
I want to be able to assign selector to variable and have some functions within it that I could be able access from outer it's scope.
NOTICE, that is pseudo code, I just drew you a picture of how I see it.
var selector = $('.someclass',
# here goes functions that I could access from outside;
);
UPDATE
var parallax = function() {
var images = ["http://localhost:8000/static/assets/images/hero-image-welcome.jpeg"];
var selector = $('.parallax-module');
var reload = function() {
console.log('reload')
};
$(selector).each(function(index) {
var image = {};
image.element = $(this);
image.height = image.element.height();
images.push(image);
$(this).css('background-image', 'url(' + images[index] + ')');
});
return {
images: images,
reload: reload()
}
}();
parallax.reload;
console.log(parallax.images[0])
// This goes without error, but isn't right;
var sParallax = $('.parallax-module');
sParallax.addClass('someClass');
// This would cause error;
parallax.addClass('someClass');
In this case I can use parallax public properties and methods, but I can't use selector (as I did in the beginning) without creating a new link to it. I know I can use public properties to access selector, but it's not the way I looking for.
You can just set the variable with your desired selector and then just add functions to that variable
var logo = $('.logo');
logo.show = function () {
console.log('logo has appeared');
$(this).addClass('logo-animated');
}
logo.hide = function () {
console.log('logo has been removed');
}
logo.show();
logo.hide();
JSFIDDLE
You can access through this:
logo.prevObject[0].show()//or hide()
I think I found the way, but it does not look right to me, it is working thought:
var parallax = function() {
var images = ["http://localhost:8000/static/assets/images/hero-image-welcome.jpeg"];
var selector = $('.parallax-module');
var reload = function() {
console.log('reload')
};
$(selector).each(function(index) {
var image = {};
image.element = $(this);
image.height = image.element.height();
images.push(image);
$(this).css('background-image', 'url(' + images[index] + ')');
});
return {
images: images,
reload: reload()
}
}().selector;
With selector reference in the end it is now valid to use parallax variable as simple link to DOM element, as well as to access functions that within it.
Preamble: I'm Italian, sorry for my bad English.
This is my problem:
I want to assign a function to a set of buttons.
I need to send a parameter to the function.
this is the code that I've tried:
function test(atxt) {
var buttons = $('.tblButton');
for (var i = 0; i < buttons.length; i++) {
buttons[i].onClick(sayHello(atxt));
}
}
function sayHello(txt){alert('hello' + txt)};
...getting the following error:
Uncaught TypeError: Object #<HTMLButtonElement> has no method 'onClick'
can you tell me where I went wrong and how can I fix it?
EDIT: I need iteration because I need the 'id of the button as a parameter of the function so i need to do buttons[i].onClick(sayHello(buttons[i].id))
buttons[i].onClick(sayHello(atxt));
Supposed to be
$(buttons[i]).on('click', function() { sayHello(atxt) });
If you want to get the current button id then I think you are looking for this..
for (var i = 0; i < buttons.length; i++) {
$(buttons[i]).on('click', function() { sayHello(this.id) });
}
If you want to iterate through all of the buttons then you have to do that with .each() handler of the jquery:
$(function(){
$(".tblButton").each(function () {
$(this).click(function(){
alert($(this).attr('id'));
});
});
});
checkout the jsbin: http://jsbin.com/usideg/1/edit
Would this not work for your example: Do you have another reason for the iteration?
function test(atxt) {
$('.tblButton').on('click',function(){sayHello(atxt);});
}
function sayHello(txt){alert('hello' + txt)};
OR optionally if the elements are static and present:
function test(atxt) {
$('.tblButton').click(function(){sayHello(atxt);});
}
function sayHello(txt){alert('hello' + txt)};
Alternate approach: just change
to this style:
var txt = "fred";
var atext = "hello" + txt;
function sayHello(atext) {
alert(atext);
}
$('.tblButton').on('click', function() {
sayHello(atext);
});
//below here just to demonstrate
$('.tblButton').eq(0).click();//fires with the fred
txt = "Johnny";// new text
atext = 'hello' + txt;
$('.tblButton').eq(1).click();//fires the Johnny
see it working here:
http://jsfiddle.net/dFBMm/
SO based on your note:
this markup and code:
<button class="tblButton" id="Ruth">Hi</button>
<button class="tblButton" id="Betty">Hi again</button>
$('.tblButton').on('click', function() {
alert("Hello "+$(this).attr("id"));
});
$('.tblButton').eq(0).click();//fires with the Ruth
$('.tblButton').eq(1).click();//fires the Betty
http://jsfiddle.net/dFBMm/1/
I have in Javascript:
for ( i=0; i < parseInt(ids); i++){
var vst = '#'+String(img_arr[i]);
var dst = '#'+String(div_arr[i]);
}
How can I continue in jQuery like:
$(function() {
$(vst).'click': function() {
....
}
}
NO, like this instead
$(function() {
$(vst).click(function() {
....
});
});
There are other ways depending on your version of jquery library
regarding to this, your vst must need to be an object which allow you to click on it, and you assign a class or id to the object in order to trigger the function and runs the for...loop
correct me if I am wrong, cause this is what I get from your question.
$(function() {
$(vst).click(function() {
....
}
})
You can use any string as element selector param for jQuery.
Read the docs for more information.
http://api.jquery.com/click/
http://api.jquery.com/
You can pass a String in a variable to the $() just the way you want to do it.
For example you can do:
var id = 'banner';
var sel = '#'+id;
$(sel).doSomething(); //will select '#banner'
What's wrong is the syntax you are using when binding the click handler. This would usually work like:
$(sel).click(function(){
//here goes what you want to do in the handler
});
See the docs for .click()
Your syntax is wrong, but other than that you will have no problem with that. To specify a click:
$(function() {
for ( i=0; i < parseInt(ids); i++){
var vst = '#'+String(img_arr[i]);
var dst = '#'+String(div_arr[i]);
$(vst).click(function (evt) {
...
});
}
})
Note that since vst is changing in the loop, your event code should also be placed in the loop.
EDIT: Assuming you want the same thing to happen for each image and each div, you could also do something like this:
$(function () {
function imgEventSpec($evt) {
// image clicked.
}
function divEventSpec($evt) {
// div clicked.
}
for (var idx = 0; idx < img_arr.length && idx < div_arr.length; idx ++) {
$("#" + img_arr[idx]).click(imgEventSpec);
$("#" + div_arr[idx]).click(divEventSpec);
}
});
This is the html. If a link is clicked I want to replace the span-element in front of it with some text.
<p><span id="sp1">that1</span> Update1</p>
<p><span id="sp2">that2</span> Update2</p>
<p><span id="sp3">that3</span> Update3</p>
<p><span id="sp4">that4</span> Update4</p>
<p><span id="sp5">that5</span> Update5</p>
As you can see, my idea was to give the spans en the anchors identical id's and a number.
In my jquery-code I loop through all the anchor-elements, give them a click-event that causes the span-element in front of it to be replaced.
<script type="text/javascript" >
$(document).ready(function() {
var numSpans = $("span").length;
for (n=0;n<=numSpans;n++) {
$("a#update" + n).click(function(e){
$('span#sp' + n).replaceWith('this');
e.preventDefault();
});
}
});
</script>
For some reason this does not work.
What am I doing wrong?
The problem with your original code is that you're creating a closure on the variable n. When the event handler is called, it is called with the value of n at the point of invocation, not the point of declaration. You can see this by adding an alert call:
$(document).ready(function() {
var numSpans = $("span").length;
for (n = 1; n <= numSpans; n++) {
$("a#update" + n).click(function(e) {
alert(n); //Alerts '6'
$('span#sp' + n).replaceWith('this');
e.preventDefault();
});
}
})
One way to fix this is to create a closure on the value of n in each iteration, like so:
$(document).ready(function() {
var numSpans = $("span").length;
for (n = 1; n <= numSpans; n++) {
$("a#update" + n).click(
(function(k) {
return function(e) {
alert(k);
$('span#sp' + k).replaceWith('this');
e.preventDefault();
}
})(n)
);
}
})
However, this is messy, and you'd do better to use a more jQuery-y method.
One way to do this would be to remove the ids from your code. Unless you need them for something else, they're not required:
<p><span>that1</span> Update1</p>
<p><span>that2</span> Update2</p>
<p><span>that3</span> Update3</p>
<p><span>that4</span> Update4</p>
<p><span>that5</span> Update5</p>
jQuery:
$(function() {
$('a.update').live('click', function() {
$(this).siblings('span').replaceWith("Updated that!");
});
});
jsFiddle
Don't create functions in a loop. With jQuery, there's no need for an explicit loop at all.
$(function()
{
$('span[id^=sp]').each(function(n)
{
$('#update' + n).click(function(e)
{
$('#sp' + n).replaceWith(this);
return false;
});
});
});
Demo: http://jsfiddle.net/mattball/4TVMa/
You can do way better than that, though:
$(function()
{
$('p > a[id^=update]').live('click', function(e)
{
$(this).prev().replaceWith(this);
return false;
});
});
Demo: http://jsfiddle.net/mattball/xySGW/
Try this:
$(function(){
$("a[id^='update']").click(function(){
var index = this.id.replace(/[^0-9]/g, "");
$("span#sp" + index).replaceWith(this);
e.preventDefault();
});
});