Berklie
Berklie

Reputation: 590

jQuery: Create reusable function with variable on click

What is the correct way to make the following code reusable (so that I don't have to have so many versions of the same function each time that I want to hide/show a set of DIVs):

// instructions
$('#hideInstructionsOverview').click(function() {
    $('#instructionsOverview').fadeOut(400, function () {
        $('#instructionsDetail').fadeIn(400);
    });
});

$('#hideInstructionsDetail').click(function() {
    $('#instructionsDetail').fadeOut(400, function () {
        $('#instructionsOverview').fadeIn(400);
    });
});

// group
$('#hideGroupOverview').click(function() {
    $('#groupOverview').fadeOut(400, function () {
        $('#groupDetail').fadeIn(400);
    });
});

$('#hideGroupDetail').click(function() {
    $('#groupDetail').fadeOut(400, function () {
        $('#groupOverview').fadeIn(400);
    });
});

The above code is used in the same way to hide "instructions" and "group" divs (and about 7 other divs in the same manner). The similar way that each is called is with this code:

<a id="hideInstructionsOverview" href="javascript:void(0);"><img src="img/misc/plus.png" alt="" width="40" height="40" border="0"></a>
<a id="hideInstructionsDetail" href="javascript:void(0);"><img src="img/misc/minus.png" alt="" width="40" height="40" border="0"></a>

<a id="hideGroupOverview" href="javascript:void(0);"><img src="img/misc/plus.png" alt="" width="40" height="40" border="0"></a>
<a id="hideGroupDetail" href="javascript:void(0);"><img src="img/misc/minus.png" alt="" width="40" height="40" border="0"></a>

I'm thinking that there's a way that I can create a function that accepts variables, and that I pass three variables on click: (1) what image id was clicked (I think that $this is probably used), (2) what div to fadeOut and (3) what div to fadeIn. I can't seem to get the variable creation and passing correct, but I imagine that the final, reusable function would look something like this:

// divToggler
$('$this').click(function() {
    $('#divToFadeOut').fadeOut(400, function () {
        $('#divToFadeIn').fadeIn(400);
    });
});

Thanks so much in advance!

Berklie

Upvotes: 1

Views: 1544

Answers (4)

Huangism
Huangism

Reputation: 16438

There are many ways of doing this

You can try putting the div id you want to fade in as an attribute of the element that you are clicking on, for example using your current setup

html

<a id="groupOverview" class="clickClass" rel="#groupOverview">link here</a>

JS

$('.clickClass').click(function() {
    var showThis = $(this).attr('rel');
    $( '#' + $(this).attr('id').replace('hide', '') ).fadeOut(400, function() {
        $( showThis ).fadeIn(400);
    });
});

You can apply this kind of setup easily with different naming convention as well. If you had different div ID that did not match up that nicely you can always define another attribute to take on values you need. To make it more readable, here I have defined the js line by line instead of the all in one thing

$('.clickClass').click(function() {
    // gets the id attribute of clicked element and replaces the hide string with nothing (removes it). This works only because you have setup your html this way
    var hideThis = '#' + $(this).attr('id').replace('hide', '');

    // gets the rel which I have set to the id of the showing element
    var showThis = $(this).attr('rel');

    $( hideThis ).fadeOut(400, function() {
        $( showThis ).fadeIn(400);
    });
});

I don't have time to make a sample because I am at work but if something doesn't work let me know and it should be an easy fix but I think this structure is the easiest to understand and implement

Upvotes: 0

Daniel Aranda
Daniel Aranda

Reputation: 6552

There you have:

function _setupClick(starterName, finalName){
    var initializer = $('#hide' + starterName.charAt(0).toUpperCase() + starterName.slice(1));
    var overview = $('#' + starterName);
    var detail = $('#' + finalName);
    initializer.click(function(){
        overview.fadeOut(400, function () {
            detail.fadeIn(400);
        });
    });
}
function setupClick(name){
    _setupClick(name + 'Overview', name.toLowerCase() + 'Detail');
    _setupClick(name + 'Detail', name.toLowerCase() + 'Overview');
}

setupClick('instructions');
setupClick('group');

Upvotes: 0

fedosov
fedosov

Reputation: 2049

Try this (working example):

function capitaliseFirstLetter(string)
{
    return string.charAt(0).toUpperCase() + string.slice(1);
}

// Implementing:
function elementsToggler(elements)
{
    for (var i = 0; i < 2; i++)
    {
        $("#hide"+capitaliseFirstLetter(elements[i])).bind("click", { i: i }, function(e)
        {
            $("#"+elements[e.data.i]).fadeOut(400, function()
            {
                $("#"+elements[e.data.i === 0 ? 1 : 0]).fadeIn(400);
            });
        });
    }
}

// Binding:
elementsToggler(["instructionsOverview", "instructionsDetail"]);
elementsToggler(["groupOverview", "groupDetail"]);

Upvotes: 0

Mitya
Mitya

Reputation: 34556

Ideally you would tackle this hierarchically rather than relying on lots of IDs. This is not always possible, and since you didn't post your HTML structure, I'll just answer the question at hand. Note, this utilises ECMA 5's Object.keys() method. It would need modifying for use in IE <= 8.

var map = {
    hideInstructionsOverview: {out: 'instructionsOverview', in: 'instructionsDetail'},
    hideInstructionsDetail: {out: 'instructionsDetail', in: 'instructionsOverview'}
    /* etc... */
}

$('#'+Object.keys(map).join(', #')).on('click', function() {
    var thisMapEntry = map[$(this).attr('id')];
    $('#'+thisMapEntry.out).fadeOut(400, function () {
        $('#'+thisMapEntry.in).fadeIn(400);
    });
});

It could be made shorter still with some assumptions about naming conventions (which appear sound, from what you posted) but I won't risk that one.

Upvotes: 1

Related Questions