Reputation: 611
So I got a for each loop that loops through every '.related__item' and checks if it contains an image (using '.related__item-image') or not. If true, use the correct function that calculates the text heights for each '.related__item' and trigger a dotdodot function.
What my problem is, is that it loops through each '.related__item' correctly and console.logs a correct true or false depending on the image. But for some reason, it gives the same height for ALL the related items. So I believe that somewhere within the if statement, something is going wrong, but I just can't figure out exactly what.
How can I make it so that for every iteration, the loop gives a true or false, sets the correct heights for all elements and then goes on the to next and do the same thing. Am I looking at making an each in and each?
Jfiddle: https://jsfiddle.net/bwbeLbnv/
OR
JS:
var self = this;
var textBlock = $('.text', self);
var titleHeight = $('.related__item-title', self).outerHeight(true);
var containerHeight = $('.related__item', self).outerHeight();
var imageHeight = $('.related__item-image', self).outerHeight();
var relatedItems = $(".related-magazines .related__item");
var calculate_with_image = function() {
var totalHeight = titleHeight + imageHeight;
textBlock.css({height: containerHeight - totalHeight});
textBlock.trigger("update.dot");
};
var calculate_without_image = function() {
textBlock.css({height: containerHeight - titleHeight});
textBlock.trigger("update.dot");
};
var related_resize = function() {
for ( var i = 0; i < relatedItems.length; i++ ) {
var element = relatedItems.eq(i);
var hasImage = element.find('.related__item-image', self).length === 1;
console.log($(element).text());
console.log(hasImage);
if (hasImage === true) {
calculate_with_image();
console.log('IMAGE');
} else if (hasImage === false) {
calculate_without_image();
console.log('TEXT');
}
}
};
related_resize();
HTML: (Stripped)
<div class="related-magazines"> <!-- container -->
<div class="content"> <!-- inner container -->
<div>
<h3>Related pages</h3>
</div>
<!-- first column group -->
<div class="field-name-sections first">
<!-- related item w/ image -->
<div class="related__item hni-grid first">
<div class="related__item-section">
<a href="link/url">
<div class="related__item-image">
<img class="item" src="img/url">
</div>
<div class="body">
<div class="related__item-title">
<h4>
This is a title
</h4>
<h5 class="related-magazine-title">
This is a subtitle
</h5>
</div>
<div class="text">
This is a long description. etc etc etc.
</div>
</div>
</a>
</div>
</div>
<!-- related item w/o image -->
<div class="related__item last">
<div class="related__item-section">
<a href="link/url">
<div class="body">
<div class="related__item-title">
<h4>
This is a title
</h4>
<h5 class="related-magazine-title">
This is a subtitle
</h5>
</div>
<div class="text" data-padding-bottom="1">
This is a long description. etc etc etc.
</div>
</div>
</a>
</div>
</div>
</div>
<!-- second column group -->
<div class="field-name-sections last">
<!-- related item w/ image -->
<div class="related__item">
<div class="related__item-section">
<a href="link/url">
<div class="related__item-image">
<img class="item" src="image/url">
</div>
<div class="body">
<div class="related__item-title">
<h4>
This is a title
</h4>
<h5 class="related-magazine-title">
This is a subtitle
</h5>
</div>
<div class="text">
This is a long description. etc etc etc.
</div>
</div>
</a>
</div>
</div>
<!-- related item w/ image -->
<div class="related__item">
<div class="related__item-section">
<a href="link/url">
<div class="related__item-image">
<img class="item" src="image/url">
</div>
<div class="body">
<div class="related__item-title">
<h4>
This is a title
</h4>
<h5 class="related-magazine-title">
This is a subtitle
</h5>
</div>
<div class="text">
This is a long description. etc etc etc.
</div>
</div>
</a>
</div>
</div>
</div>
</div> <!-- end content --> </div> <!-- end related magazines -->
Upvotes: 0
Views: 149
Reputation: 12637
Alright, I've stripped the whole HTML structure to give you an idea to how it looks like.
Thanx, this really helps. The Problem in your code is that calculate_with_image()
and calculate_without_image()
don't consider the current .related__item
at all. All values that are used in these functions are computed before the loop. That's why they return the same value for each iteration.
comment: Most jQuery-methods that compute/return a value and don't apply something to the nodes in the jQuery selection, compute this value from the first DOM-Node in the selection. So that $('.related__item-image').outerHeight()
first fetches all .related__item-image
nodes from the document, but returns only the outerHeight()
of the first one.
That's one thing that went wrong in your code.
I'm not sure wether this was your intention, but I think you tried to fetch all related nodes first, and then iterate over these lists (I mean this part: var textBlock = $('.text')
and the following lines). If there is a 1:1 relationship between these lists, fine (not good, but ok). If not, you'll end in a mess; so generally avoid this approach if possible. It's to easy that something may go wrong. Or may change and then go wrong.
If I got your intentions wrong here, never mind.
I can't test wether the following code produces the expected result, since it depends on your CSS, but I think it should do the job: (otherwise, you'll tell me what's wrong)
$(".related-magazines .related__item").each(function(){
//comment: jQuery iterators provide the current Element as `this`
var $this = $(this); //the current item wrapped in a jQuery-object.
var containerHeight = $this.outerHeight(); //the height of this particular item
//fetch the related image, and get it's outerHeight
//returns `null` if no image is found, wich then will be replaced with a 0
var imageHeight = $this.find('.related__item-image').outerHeight() || 0;
//same for the related title:
var titleHeight = $this.find('.related__item-title').outerHeight(true) || 0;
//btw, this would also work:
//var imageHeight = $('.related__item-image', this).outerHeight() || 0;
//and I mean `this` and not your cached `self`, but not your combination of find and self.
console.log($this.text());
console.log(imageHeight > 0);
//inlined `calculate_with_image()` and `calculate_without_image()` because they are short,
//and almost identical, and need access to the same Nodes that are used
//comment: jQuery allows method-chaining
$this.find('.text') //get the textBlock
.height( containerHeight - (titleHeight + imageHeight) ) //set it's height
.trigger("update.dot"); //and trigger
console.log(imageHeight > 0? "IMAGE": "TEXT");
});
One could argue that imageHeight > 0
is inaccurate, when testing wether there is an image or not. Because there might be an image, but with an height of 0. Well yes, but for this computation that wouldn't make any difference.
There might be a problem with an Image, leading to this height of 0. Maybe it's not loaded yet, or maybe one of it's parents is display:none
, but handling that problem would be the topic of a different SO-Question.
Upvotes: 1
Reputation: 123
If I'm understanding correctly, this is because the imageHeight variable inside calculate_with_image() should be the height of the particular image found in the loop correct?
Edit: The imageHeight variable you have, and are using, will only be for one image found. it doesn't update based on what you've found within the loop. Passing the height, or the image, found in the loop into calculate_with_image() (as described below) solves the problem.
If that's the case, you'll want to either pass in the element found in the loop itself to calculate_with_image(), or the height, like so:
// calculate_with_image function
var calculate_with_image = function(element) {
var elementImageHeight = element.find('.related__item-image', self).outerHeight();
var totalHeight = titleHeight + elementImageHeight;
textBlock.css({height: containerHeight - totalHeight});
textBlock.trigger("update.dot");
};
// if statement found within your loop.
if(hasImage === true){
calculate_with_image(element); // option one, pass the element
console.log('IMAGE');
} // carry on with else if
OR
// calculate_with_image function
var calculate_with_image = function(elementImageHeight) {
var totalHeight = titleHeight + elementImageHeight;
textBlock.css({height: containerHeight - totalHeight});
textBlock.trigger("update.dot");
};
// if statement found within your loop.
if(hasImage === true){
var elementImageHeight = element.find('.related__item-image', self).outerHeight();
calculate_with_image(elementImageHeight);
console.log('IMAGE');
} // carry on with else if
This way, your calculate_with_image will know the height of the specific image you wanted to deal with. Either approach works. it's just a matter of whether you'd like the element (specific image found) to be available in the function, or just the height you needed.
Upvotes: 1