0

I have the following js function:

function makeArticleFeed(response) {
        $('#articles-feed').empty();
        if(response.length > 0) {
            for(var x = 0; x<response.length; x++) {
                //format date
                var posted = new Date((response[x].posted * 1000));
                //format extract line brakes
                var extract = response[x].extract.replace(/(\r\n|\n|\r)/gm,"<br>");
                //format categories
                var categories = response[x].cat_name.split(",");
                //make a variable to store the HTML
                var articleHTML = (
                    '<div class="article-box"><h1><a href="#">' + response[x].title+
                    '</a><h1><h3><a href="#">' + response[x].name +
                    '</a>&nbsp;|&nbsp;' + posted.toLocaleDateString() +
                    '</h3><ul class="article-categories">'
                    );
                for(y=0; y<categories.length;y++) {
                    articleHTML += '<li class="article-category">' + categories[y] + " " + '</li>';
                }// end categories append for loop
                articleHTML += '</ul><p>' + extract + '</p></div>';
                //append the HTML
                $('#articles-feed').append(articleHTML);
                //check if article is free, add class accordingly
                if($(".article-category:contains(free)")) {
                    $(this).parent().parent().addClass("free");
                } 

            } //end article feed for loop
            $(".article-box h1 a").click(function(e) {
                e.preventDefault();
                var title = "title="+ $(this).text();
                $.post(
                    "db_queries/articles.php",
                    title,
                    function(data) {
                        var response = JSON.parse(data);
                        // formats article body
                        var articleBody = response[0].body.trim();
                        articleBody = articleBody.replace(/(\r\n|\n|\r)/gm,"<br>");
                        // formats date
                        var posted = new Date((response[0].posted * 1000));
                        $("#articles-feed").empty();
                        $("#articles-feed").append(
                            '<div class="article-box"><h1>' +response[0].title+
                            '</h1><h3>' + posted.toLocaleDateString()+
                            '</h3><p>' + articleBody +
                            '</p><button>Back to articles</button></div>'
                        ); //end append
                        $("#articles-feed button").click(function(e) {
                            e.preventDefault();
                            window.location.assign('articles');
                        })
                    } //end response function
                ); //end POST request
            }) //end article title click function
        } //end if response not empty block
        else {
            $("#articles-feed").append('<h1>Sorry, no article found!</h1>');
        } //end article not found message
    } //end makeArticleFeed

That mostly outputs this HTML:

<div class='article-box'>
   <h1></h1>
   <h3></h3>
   <ul class='article-categories'>
      <li class='article-category'>free</li>
      <li class='article-category'>basic</li>
   </ul>
   <p></p>
</div>
<div class='article-box'>
   <ul class='article-categories'>
      <li class='article-category'>members-only</li>
      <li class='article-category'>basic</li>
   </ul>
</div>

Now I'm using jQuery, to check if the article-category contains free, and want to add a class to the <div class='article-box'> in case it does. So far I came up with this, but this just adds the class to all article boxes:

if($(".article-category:contains(free)")) {
    $('.article-box').addClass("free");
} 

Is there a way to target only the article-box that contains the text I'm looking for?

Miha Šušteršič
  • 9,742
  • 25
  • 92
  • 163

3 Answers3

0

You can use the parents method for this:

$(".article-category:contains(free)").each(function () {
    $(this).parents("div.article-box").addClass("free");
});
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
0

You're using global selector .article-box and doesn't point in any way that it should look for parent element of .article-category containing 'free' text.

You should also remember that you're actually creating a collection, as there might be more than one element containing 'free' text. So you've to iterate through each element, find it's closest .article-box and add 'free' class to it.

$('.article-category:contains(free)').each(function() {
    $(this).closest('.article-box').addClass('free');
});
  • Thanks for the explanation. I guess I'll move this outside of my for-loop. Is there a special reason to use .closest or should I just go with the parents solution (no chance to fail selection there) – Miha Šušteršič Jun 13 '15 at 12:58
  • Here's really good explanation of the difference between those two.[http://stackoverflow.com/a/9193284/4940463](http://stackoverflow.com/a/9193284/4940463) .An yes, you should move outside of the loop, but after the HTML is appended ( in ajax callback ). If you're willing to use it inside the loop, you have to save the each element in some variable `var $articleBox = $('
    ').addClass('article-box'); var $articleCategory = $('
    ').addClass('article-category') if($articleCategory.text().indexOf('free') > -1 ) { $articleBox.addClass('free') } $articleCategory.appendTo($articleBox)`
    – Wojciech Grzebieniowski Jun 13 '15 at 13:02
  • read through it, decided to go with closest as I don't really need the whole DOM tree, just want to `.appendClass`. – Miha Šušteršič Jun 13 '15 at 13:06
0

You can use nested filter. They are ideal in this situation

$filteredDivs=$('.article-box').filter(function(){  
    return $(this).find('.article-category').filter(function(){
      return ($(this).html()=='free');    
    }).length>0;
}).addClass('free');

Fiddle link

Amit.rk3
  • 2,417
  • 2
  • 10
  • 16