views:

97

answers:

4

Is there any way to combine all of this to reduce the amount of js? This is just an example of some of the jquery dialogs I have in my site, there are a few more too. Thanks.

//initiate Search refinement dialog here
$("#chooseMoreCnt, #chooseMoreCat, #chooseMorePr").dialog({
    bgiframe: true,
    autoOpen: false,
    width: 500,
    modal: true,
    open: function(type, data) {
        $(this).parent().appendTo(jQuery("form:first"));
    }
});

//trigger country dialog
$('a.chooseMoreCnt').click(function() {
    $('#chooseMoreCnt').dialog('open');
    return false;
});

//trigger category dialog
$('a.chooseMoreCat').click(function() {
    $('#chooseMoreCat').dialog('open');
    return false;
});

//trigger price dialog
$('a.chooseMorePr').click(function() {
    $('#chooseMorePr').dialog('open');
    return false;
});
+7  A: 

If your links point to the IDs of the dialog elements, and if you add a meta class choose to each of them, you could combine the last three calls to:

$('a.choose').click(function() {
    $(this.hash).dialog('open');
    return false;
});

The HTML for one of those links is the most semantically correct and even works with JS disabled (assuming, the dialogs are there, then):

<a href="#chooseMoreCat" class="choose">Choose more categories</a>

The this.hash part explained:

  • this in the context of a jQuery event handling function is always the element, that the event appeared at. In our case, it's the clicked link. Note, that it's the DOM node, not a jQuery element.

  • this.hash: DOM nodes, that correspond to HTML <a/> elements, have certain special properties, that allow access to the target they're linking to. The hash property is everything after (and including) an # character in the URL. In our case, if the link points to the elements that should become dialogs, it's something like the string "#chooseMoreCnt".

  • $(this.hash) is the jQuery function called for, e.g., "#chooseMoreCnt", which will select the appropriate div.

For the dialog initialization, I would also go for classes:

$(".choose_dialog").dialog({
    bgiframe: true,
    autoOpen: false,
    width: 500,
    modal: true,
    open: function(type, data) {
        $(this).parent().appendTo(jQuery("form:first"));
    }
});

Yes, it means to change the markup, but it also provides you with the freedom to

  1. add any number of dialogs lateron

  2. add any number of openers to any dialog lateron

  3. style all dialogs and links to dialogs consistantly with minimal CSS

without touching the Javascript anymore.

If the dialogs are initiated differently (as mentioned in the comments), then you could go for this part with CuSS's $.each() approach and read the appropriate width inside the function from an object defined elsewhere:

var dialog_widths = {'chooseMoreCat': 400, 'chooseMorePr': 300, /*...*/ };
Boldewyn
+1 for using `this.hash`.
Mathias Bynens
What does the hash do?But that way he had to modify the html structure, do you know if he only have 3 or more?
CuSS
would like to know it to. what is hash for?
meo
Please also address the initialization of the dialogues.
Simeon
I dont mind modifying the html structure if it means condensing the js file. I have more than three dialogs to load, but they are initiated differently. i.e width, height etc.. What do you mean by 'adding a meta class choose'? Do mean add a css class of 'choose' to all the links which trigger the dailogs? thanks for getting back to me by the way!
Mark
@Mark: Exactly, add a class attribute. I updated the answer with a sample markup.
Boldewyn
thx a lot for the hash explanation!
meo
Im trying the above, (thanks for editing it explanation btw) and i cannot seem to get it to work. heres my code. $(".choose_dialog").dialog({ bgiframe: true, autoOpen: false, width: 640, modal: true, open: function(type, data) { $(this).parent().appendTo(jQuery("form:first")); } }); $('a.choose').click(function() { $(this.hash).dialog('open'); return false; });<a href="#chooseMoreCat" class="choose">Choose more categories</a><div class="choose_dialog"> //dialog content here</div>
Mark
i have also tried this.<a href="#chooseMoreCat" class="choose">Choose more categories</a><div id="#chooseMoreCat" class="choose_dialog">dialog content here</div>
Mark
+1 and thanks for the hash explaination. ;)
CuSS
A: 

well, this is a little complicated to minimize. do you have more than 3 dialogs? If yes you can do something like this:

var dialogs=["chooseMorePr","chooseMoreCat","chooseMoreCnt"];
$.each(dialogs,function(i,v){
    $('a.'+v).click(function(){$('#'+v).dialog('open');});
});
CuSS
If there are more than 3 dialogues (which will have to be taken into account when coding a general solution), adding an event handler on every element will be very performance consuming. In addition, using $.each is slower than a for-loop.
Simeon
$.each-loop act like a for-loop if you specify an array, and not Identifyers! Read that at jQuery Docs (http://api.jquery.com/jQuery.each/)!
CuSS
"The $.each() function is not the same as .each(), which is used to iterate, exclusively, over a jQuery object. The $.each() function can be used to iterate over any collection, whether it is a map (JavaScript object) or an array. In the case of an array, the callback is passed an array index and a corresponding array value each time. (The value can also be accessed through the this keyword.)" It is only a way to do the for but with jQuery way.
CuSS
The major performance issue here is the event handlers, that's way much more important than the $.each issue. But yes, as I said, a $.each is slower than a for-loop. I'm fully aware of what they are and do, but I don't understand why you are explaining it to me. Just use a for-loop instead, iterating over the jQuery array (a jQuery set is an array of items).
Simeon
A: 

In order to optimize performance, you should use live when connecting to several elements. Below is my approach to the problem. The solution is dynamic (add as many dialogues as you want to) and very speedy.

Remember to change #anyParentOfTheLinks into the parent div or in worst case remove it and jQuery will use document instead.

var dialogues = ['#chooseMoreCnt', '#chooseMoreCat', '#chooseMorePr'];

$(dialogues.toString()).dialog({
    // ...
});

$('a', '#anyParentOfTheLinks').live('click', function(){
    // Cache for performance
    var $this = $(this), len = dialogues.length;

    for(var i = 0; i < len; i++)
        if($this.is('.' + dialogues[i].substr(1))) {
            $this.dialog('open');
            break;
        }

    return false;
});
Simeon
code too big -1
CuSS
For what? I never said it was the shortest, I said it was the best.
Simeon
i didn't mark as -1, and read the question: "Is there any way to combine all of this to REDUCE the AMOUNT of JS?"
CuSS
@CuSS: If you didn't mark as -1, why did you say that in your comment?
Boldewyn
because i can't mark, and he as marked, just because i didn't like his code
CuSS
@CuSS: Yes I have read the question. My code amount is reduced in relation to the original, is it not? In addition the other user's valid but slow answers, I wanted to provide a performance optimized version. The questioner may or may not need it, but here it is. Shorter and faster. I don't understand why that should earn -1.
Simeon
A: 

This is what I would suggest. Specify a general DialogContent (say) class to all the divs and initialize them using:

$(".dialogContent").dialog({
    bgiframe: true,
    autoOpen: false,
    width: 500,
    modal: true,
    open: function(type, data) {
        $(this).parent().appendTo(jQuery("form:first"));
    }
});

And ofcourse use Boldewyn's solution for click event (it is better to use live() IMHO if things are getting dynamically generated). This way you take care of all initializations and click events with way less code.

HTH

Raja