Dev P
Dev P

Reputation: 1187

Iteriting <p> elements getting their height and using it to set height of parent LI element

I have a situation where I need to be able to set the height of an "li" and "div" element based on the height of its "p" element.

For example in the following HTML:

<ul>
  <li class ="activity-item">
   <div class ="activity-detail">
    <div class ="activity-comments">
     <p class="activity-comments"></p>
    </div>
   </div>
  </li>
  <li class ="activity-item">
   <div class ="activity-detail">
    <div class ="activity-comments">
     <p class="activity-comments">sample content - dummy text</p>
    </div>
   </div>
  </li>
</ul>

I will need to set the height of the "div class=activity-detail" element and the "li class=activity-item" element to the height of the "p class=activity-comment". The "p" element can be empty i.e. not have any contents or it can have a lot of text.

The challenge is to be able to first get the heights of all the "p" elements within all the "li" elements if the "p" elements are not empty and secondly use the height values to set the height of each of the "li" elements.

I have the following jquery so far which gets me the heights of the "p" elements (based on their contents), but not quite sure how to go about using the retrieved height values to then set the heights of the "li" elements:

$(document).ready(function(){  
    $('.activity-item p').each(function(index, element){
         var commentsHeight = $(this).height();
         alert(commentsHeight);


             //the below does not quite work correctly yet
         $('li.activity-item').css("height",commentsHeight);
         $('div.activity-detail').css("height",commentsHeight);
     });
    });

Any help/assistance is much appreciated. Thanks

Upvotes: 2

Views: 255

Answers (4)

David Thomas
David Thomas

Reputation: 253318

At its simplest, assuming each <li> should have the height of its descendant, I'd suggest:

// iterating over each <li> element using the height() method;
// using that method's anonymous function to return a specific
// potentially unique value for each element in turn:
$('li').height(function(){

  // looking inside of the current <li> element for a <p>
  // element that is not ':empty' and caching the result
  // of that selector in the 'p' variable:
  let p = $(this).find('p:not(:empty)');

  // if we have a collection greater than 0 (and so a truthy
  // length) we return the height of the first found <p> element
  // matching the selector; otherwise with a falsey length (of
  // zero) we return 0 (on the assumption you wish to hide those
  // elements):
  return p.length ? p.height() : 0;
});

$('li').height(function() {
  let p = $(this).find('p:not(:empty)');
  return p.length ? p.height() : 0;
});
li {
  box-sizing: border-box;
  position: relative;
  background-color: #f90;
  list-style: none;
}
li::before {
  content: attr(style);
  position: absolute;
  top: 0;
  right: 0;
  height: auto;
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
  <li class="activity-item">
    <div class="activity-detail">
      <div class="activity-comments">
        <p class="activity-comments"></p>
      </div>
    </div>
  </li>
  <li class="activity-item">
    <div class="activity-detail">
      <div class="activity-comments">
        <p class="activity-comments">sample content - dummy text</p>
      </div>
    </div>
  </li>
</ul>

JS Fiddle demo.

If, however, each <li> should instead have a common height, based on the height of the tallest contained <p> element:

// selecting all <li> elements, and updating the height of
// all <li> elements:
$('li').height(

  // here we select all non-empty <p> elements contained
  // within an <li> element using jQuery and then convert
  // that collection to an Array, using get(); we then
  // use Array.prototype.reduce() to reduce the Array to one
  // single value, in this case the height of the tallest
  // <p> element:
  $('li p:not(:empty)').get().reduce(function(a, b) {

    // the initial value is 0 (set as the second argument
    // to the reduce() method); in this function we
    // subtract the clientHeight of each <p> element from
    // the initial value, and then from the previous value,
    // keeping the largest value (whether a or b):
    return b.clientHeight - a;
  }, 0)
);

$('li').height(
  $('li p:not(:empty)').get().reduce(function(a, b) {
    return b.clientHeight - a;
  }, 0)
);
li {
  box-sizing: border-box;
  position: relative;
  background-color: #f90;
  list-style: none;
}
li::before {
  content: attr(style);
  position: absolute;
  top: 0;
  right: 0;
  height: auto;
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
  <li class="activity-item">
    <div class="activity-detail">
      <div class="activity-comments">
        <p class="activity-comments"></p>
      </div>
    </div>
  </li>
  <li class="activity-item">
    <div class="activity-detail">
      <div class="activity-comments">
        <p class="activity-comments">sample content - dummy text</p>
      </div>
    </div>
  </li>
</ul>

JS Fiddle demo.

References:

Upvotes: 0

Alex Char
Alex Char

Reputation: 33218

Not sure if I understand correct but I get the height of each p(if contain some text) and assign that height to closest li element and closest div with class .activity-detail:

$(document).ready(function() {
  $('.activity-item p').each(function(index, element) {
    var txt = $.trim($(this).text());
    var commentsHeight = 0;
    if (txt !== "") {
      commentsHeight = $(this).height();
    }

    if (commentsHeight > 0) {
      $(this).parents('li').css('height', commentsHeight);
      $(this).closest('div.activity-detail').css("height", commentsHeight);
    }
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
  <li class="activity-item">
    <div class="activity-detail">
      <div class="activity-comments">
        <p class="activity-comments"></p>
      </div>
    </div>
  </li>
  <li class="activity-item">
    <div class="activity-detail">
      <div class="activity-comments">
        <p class="activity-comments">sample content - dummy text</p>
      </div>
    </div>
  </li>
</ul>

Upvotes: 3

LatentDenis
LatentDenis

Reputation: 2991

In case you wanted a handy tool to do the same thing via alternate resource: http://smohadjer.github.io/sameHeight/demo/demo.html

If you wanted to look at the code in github: https://github.com/smohadjer/sameHeight

Just through this jQuery call:

$('.parent-element').sameHeight({

    //this option by default is false so elements on the same row can have
    //different height. If set to true all elements will have the same height
    //regardless of whether they are on the same row or not.
    oneHeightForAll: true,

    //this option by default is false. If set to true css height will be
    //used instead of min-height to change height of elements.
    useCSSHeight: true,

    //this function will be called every time height is adjusted
    callback: function() {
        //do something here...
    }
});

Or without all the options: $('.parent-element').sameHeight();

Upvotes: 0

DaniP
DaniP

Reputation: 38252

With Jquery you can use parents() to search the li wrapper for each p:

$(document).ready(function(){  
  $('.activity-item p').each(function(index, element){
     var commentsHeight = $(this).height();
     alert(commentsHeight);

     //Refer to "this" element and search for the parents
     $(this).parents('li, div.activity-detail').css("height",commentsHeight);
  });
});

Upvotes: 2

Related Questions