1

this is my first post ever on stackoverflow! I am a front-end web developer enthusiast and novice...If I am breaching the stackoverflow etiquette or rules of the road please let me know or give me the smack down..

I am trying to evaluate class names in an array of elements. If the class name contains a certain value then I want to manipulate an attribute for that element.

First, I create an array of elements using jquery stored as a variable:

note that buttons class naming convention is "share_button_[social media service name]"

Next, I create a for loop to iterate through the buttons variable

Within the for loop I have switch statement - the purpose is to evaluate each element in the Buttons array and add an href attribute to the element if it meets a certain criteria

Putting it all together:

var buttons = $('a[class^="share_button"]');

for (i=0; i < buttons.length; i++) {
    switch (true) {
        case ($(buttons[i]).attr('[class*="twitter"]')):
        console.log('twitter!');
        break;

        case ($(buttons[i]).attr('[class*="linkedin"]')):
        console.log('linkedin!');
        break;

        case ($(buttons[i]).attr('[class*="facebook"]')):
        console.log('facebook_like!');
        break;

        case ($(buttons[i]).attr('[class*="google_plusone"]')):
        console.log('google_plusone!');
        break;

        case ($(buttons[i]).attr('[class*="reddit"]')):
        console.log('reddit!');
        break;   
    }
}

This does not seem to be working at all. Here is the codepen, http://cdpn.io/fKoak

Is it a good practice to loop through a jquery array of elements like this?

Should I be using the switch statement in this case and am I using it correctly? (there are more possible cases then I have case statements for and I have no default - I want the cases without a match to "do noting")

In this particular case, what i wrong with the formation of my code that the desired outcome is not happening?

JustinShea
  • 23
  • 2

3 Answers3

1

I think it would be better to do something more like this.

var $buttons = $('a[class^="share_button"]');

var $twitterButtons = $('[class*="twitter"]', $buttons);
$twitterButtons.each(function(i, button) {
    //Do stuff to the twitter button
});

var $linkedinButtons = $('[class*="linkedin"]', $buttons);
$linkedinButtons.each(function(i, button) {
    //Do stuff to the linkedin button
});

var $facebookButtons = $('[class*="facebook"]', $buttons);
$facebookButtons.each(function(i, button) {
    //Do stuff to the facebook button
});

var $google_plusoneButtons = $('[class*="google_plusone"]', $buttons);
$google_plusoneButtons.each(function(i, button) {
    //Do stuff to the google_plusone button
});

var $redditButtons = $('[class*="reddit"]', $buttons);
$redditButtons.each(function(i, button) {
    //Do stuff to the reddit button
});

Adding the second parameter to your selectors gives them a context. So $('[class*="twitter"]', $buttons) looks through $buttons and selects those with a class containing twitter

tleef
  • 3,516
  • 1
  • 24
  • 34
  • thanks for feedback. it doesn't answer my question(s) fully but it is certainly a workable solution. A huge plus one (metaphorical - I don't have reputation enough to actually do it) for introducing me to the concept of using a second parameter in jquery selectors - I can see how that may be very useful. I am going to add the solution I settled on as a separate answer. – JustinShea Sep 27 '13 at 03:13
  • Hi Tom - I am trying the context parameter (I have also tried .find) against the $buttons variable above. But, it keeps on returning an empty array instead of the elements I am attempting to target. Here is a simplified sample of my code - http://cdpn.io/sFqCx – JustinShea Sep 27 '13 at 14:09
  • Sorry about that, I just didn't know how your HTML was structured. Using a selector with context applies the selector to the descendants of the context, same with find. Like so http://jsfiddle.net/FL9CJ/ If you want to apply the selector to the list of elements directly use filter. Here is an example http://jsfiddle.net/fV3m5/ – tleef Sep 28 '13 at 16:03
  • thanks for all the feedback Tom - .filter was the method I needed. I got so hung up in wanting to use the new (to me) context parameter that I failed to see the obvious solution. At any rate, this has been a very valuable learning exercise for me so thanks for helping a beginner out... – JustinShea Sep 29 '13 at 01:54
  • Hi Tom, I "accepted" the solution I ultimately used. Once I have the rep I will certainly come back and plus one your answer because it was certainly "useful"... – JustinShea Sep 30 '13 at 17:55
0

You can use jQuery's each() method to iterate over the elements, then check the className

$('a[class^="share_button"]').each(function(i, elem) {
    if ( elem.className.indexOf('twitter') != -1 ) {
        console.log('twitter');
    }else if ( elem.className.indexOf('linkedin') != -1 ) {
        console.log('linkedin');
    }else if (..... etc
});

A better approach would be to keep the switch, but google_plusone kinda screws that up with the underscore, so you'd have to replace that with something else:

$('a[class^="share_button"]').each(function(i, elem) {
    switch( elem.className.split('_').pop() ) {
        case 'twitter' :
           console.log('twitter');
           break;
        case 'linkedin' :
           console.log('linkedin');
           break;
        case 'googleplusone' :

           // you'll have to remove the underscore or just check for "plusone"
    }
});
adeneo
  • 312,895
  • 29
  • 395
  • 388
  • The problems with this (and the OPs) code is that if a button has both a twitter and a linkedin class it will only get the twitter changes. If you know that a button will never have multiple of these social network classes then it is fine. – tleef Sep 26 '13 at 15:22
  • @Tom - why on earth would a button for a social service have classes belonging to two different social services ? – adeneo Sep 26 '13 at 15:29
  • Wasn't really my point. Just saying if it did, your code would have unexpected behavior. It would give preference to the social network higher in your switch statement / if else if chain. Plus I said if they never would multiple social network classes on one button, there wouldn't be any problem. – tleef Sep 26 '13 at 15:32
  • @adeno thanks for the feedback. I had messed with the .each method and couldn't get it to work - seems passing in the index and element parameters to callback function are a pretty big deal - thanks for clarifying that for me (+1 if I had the rep). gotta assume .each and for loop are interchangeable here? at any rate, i settled on .each method with a switch statement. although, instead of using the split method and popping out the last string from array I kept in in the jquery fam by using the .is method against attribute selectors I used in my original question...I'll post my solution below.. – JustinShea Sep 27 '13 at 03:23
0

I ultimately decided to drop the for loop and use jquery .each method -http://api.jquery.com/each/ - that was recommended by @adeno above. The two solutions offered by @adeno using .each both work good but I finally chose to go with the jquery .is method https://stackoverflow.com/a/2240085 - http://api.jquery.com/is/ - since we decided to use .each method it is already a "jquery solution" so using .is method to evaluate if the class name of each element contained a certain value was a lot less code - and allowed for more flexibility then the proposed .indexOf and .split/.pop methods by @adeno in imo..
@Tom also gave a workable solution. However, although I didn't mention it specifically in my question, I wanted a solution that would use an iterator to go through the array of selected button elements.

var $buttons = $('a[class^="share_button"]');

$buttons.each(function(i,e){  
    switch (true) {
        case ($(e).is('[class*="twitter"]')):
        alert('yea! it\'s a twitter button - now do something');
        break;

        case ($(e).is('[class*="linkedin"]')):
        alert('yea! it\'s a linkedin button - now do something');
        break;

        case ($(e).is('[class*="facebook"]')):
        alert('yea! it\'s a faceboook button - now do something');
        break;

        case ($(e).is('[class*="google_plusone"]')):
        alert('yeah! it\'s a google plus one button - now do something');
        break;

        case ($(e).is('[class*="reddit"]')):
        alert('yea! it\'s a reddit one button - now do something');
        break;
    }  
});
Community
  • 1
  • 1
JustinShea
  • 23
  • 2
  • Out of curiosity, why did you want to use an iterator? – tleef Oct 01 '13 at 02:14
  • @Tom - I wasn't sure what services I might add buttons for in the future - so I wanted to be the script to be as low maintenance as possible should I add more... – JustinShea Oct 02 '13 at 14:32