-4

I've added a block-level element to the DOM, such a p tag. Its dimensions should be automatically computed (e.g. auto). I cannot, however, retrieve its height with jQuery, at least initially. After some time has passed (presumably some layout processing has occurred), I can retrieve the height.

What has to occur in order for an element to actually be measurable, other than adding it to the DOM, in order for its computed height to be retrievable?

To be specific, I have a select element with some option elements that have image URL data attached to each of them them. I call an image-picker plugin that reads the option tag data, hides the select element, and turns the options into a container with div elements that look like this:

<div class='container' style='width:800px'>
    <div class='convertedOptionElement' style='width:33.33%'>
        <div class='thumb' style='width:100%'>
            <img src="https://lh3.ggpht.com/hhG6g0m8Q6QqZnloQJHV9uXFdsDjpzD0vJdkbra5e_PiwOjVXuBdVR0D2L0RPmwb1zw=h900">
            <p>Image Title</p>
        </div>
    </div>
</div>

So there I have a fixed-width container that will be filled with div elements at 33.33% width (producing 3 columns). Each of those div's represent one of the converted option elements. Within each of those, there's a div element at 100% width, which contains an img and p tag.

Furthermore, I'm using the imagesLoaded plugin and the masonry plugin to lay out the images. On the imagesLoaded progress event, which runs after each image is loaded, I can clearly see that the img element has a non-zero height and a width. Its containers, however, do not, nor does the p tag.

The only thing special that may be occurring is that immediatly after creating the elements with the image-picker plugin, I'm detaching them with $('.convertedOptionElement').detach(), and then in the progress event for imagesLoaded, which fires as each image is loaded, I append them to the container and call masonry.appended method so it performs the layout. That's where the problem arises, because in spite of everything being in the DOM, the computed heights are zero.

Please note that even if I provide exact widths (e.g. 250px instead of 33.33% and 100%), and then in that very same loaded event handler I explicitly set a width and height in jQuery by computing a scaled height from the existing image dimensions (i.e. all parent elements are given explicit sizes)... the paragraph tag still has a zero height.

Here is my code, but this is working. It's not working in the exact context I'm using though, and I can't figure out why. http://jsfiddle.net/p7cgahro/7/

Triynko
  • 18,766
  • 21
  • 107
  • 173
  • 5
    Judging by your rep you've been here long enough, and seen enough questions to know this isn't how it's done. We need to see your code to begin to be able to diagnose any issues. – Rory McCrossan Nov 30 '15 at 16:37
  • No, this is a fundamental question about how heights are computed and when they are retrievable. If an element has in fact been added to the DOM, under what conditions would it's height be zero or irretrievable by jQuery. – Triynko Nov 30 '15 at 16:40
  • 1
    Generally speaking, it has no dimensions when there is no content or styling: http://jsfiddle.net/p7cgahro/ – Rory McCrossan Nov 30 '15 at 16:42
  • It does have dimensions, just not at first. I updated the question. If it's visible, and it shows dimensions in the element inspector, it should be retrievable in JavaScript, but it's not. – Triynko Nov 30 '15 at 16:43
  • 1
    Right, again, as I said, there's no reason for this not to work with the basic information you've given. If you can be bothered to actually give us an example of what you're trying to do I'm sure someone will spend some time to help you. – Rory McCrossan Nov 30 '15 at 16:44
  • Once the item has been added to the DOM the height function retrieves a value. If it hasn't been added to the DOM it will always reflect 0. Can you share some code to help duplicate the issue? http://jsfiddle.net/nboko6ke/ – Sean Wessell Nov 30 '15 at 16:45
  • $(document).append('

    Hello

    '). console.log( $(document).find('p').height()); //zero, why? Basic. Should work. Does not. Chrome and Firefox.
    – Triynko Nov 30 '15 at 16:45
  • 1
    You can't append to the `document` - use the `body`. http://jsfiddle.net/p7cgahro/1/ – Rory McCrossan Nov 30 '15 at 16:47
  • 1
    Why would you append an element to the document instead of the body? – j08691 Nov 30 '15 at 16:47
  • 1
    @AlanBuchanan No it wasn't. Now we've finally managed to drag an exmaple out of the OP it's a basic syntax issue. If he'd provided that in the first place it would been answered in seconds. – Rory McCrossan Nov 30 '15 at 16:48
  • Just an example, not literally adding it to the document. It's in the DOM. That's the point. The height is zero. Change it to body if you'd like. – Triynko Nov 30 '15 at 16:49
  • 2
    He did. Did you try his fiddle? – j08691 Nov 30 '15 at 16:50
  • Yes, and that works. So I need to add more information to the question now that the basic premise has been confirmed. – Triynko Nov 30 '15 at 16:57
  • Let me know if more information is necessary, I've added a more detailed explanation. – Triynko Nov 30 '15 at 17:16
  • Here's the exact code, working. http://jsfiddle.net/p7cgahro/4/ I need to figure out why it's not working in my particular context. The only difference is that mine is running in an ajax request complete handler and inside a modal dialog that's animating into the display. – Triynko Nov 30 '15 at 18:43
  • This gets even stranger. The very first time after the image is loaded, the code runs and the p tag has the correct height. If I add another image, the existing ones have the wrong height (because they were already displayed earlier) while the newest one has a correct height (25px). On subsequent runs, the p tag always has a height of -10, which is incorrect (based on the margins). This makes no sense, because these elements are generated anew each time, and yet the seem to be maintaining some kind of state. – Triynko Nov 30 '15 at 18:56
  • Turns out, this could have been answered in its original form, without a single line of code. Besides being in the DOM, in order for an element to be measurable, none of its parent element can have display:none, and possibly particularly if its opacity was zero. Those conditions seem to prevent any kind of initial layout from occurring. Very very basic info. Furthermore, the 'display:none' style on the parent was unexpected, since I called bootstraps modal('show') method. It must be on a timer, since display:none is not removed until some time has elapsed. – Triynko Nov 30 '15 at 21:45
  • Not only that, but the "zero" height is documented behavior, but I guess people who lack knowledge can only offer snarky comments like 'you've been here long enough to know'. http://stackoverflow.com/questions/3632120/jquery-height-width-and-displaynone – Triynko Nov 30 '15 at 21:49
  • And again: http://stackoverflow.com/questions/1472303/jquery-get-width-of-element-when-not-visible-display-none – Triynko Nov 30 '15 at 21:50

2 Answers2

2

The problem was a parent element that had 'display:none;', which I was not expecting it to have.

It turns out that after calling bootstrap's modal('show') on a dialog, it doesn't actually change anything right away.

For example, immediately after the call to modal('show'), the dialog still has CSS class fade (without class in) and it's display style is still none. After some time, the in class is added which basically override's the fade class's zero opacity and set its to 1 (with a CSS animation). The display:none style is also removed.

Essentially, the problem boiled down to the fact that a parent element either had display:none and opacity:0, at the moment we were trying to make measurements. In particular, it was the display:none value that threw off the measurements.

Interestingly, this issue could have been answered straightforwardly in the original version of my question, without a single line of code, since I simply asked "What has to occur in order for an element to actually be measurable, other than adding it to the DOM, in order for its computed height to be retrievable?"

The answer is... none of the parent elements can have 'display:none'.

Triynko
  • 18,766
  • 21
  • 107
  • 173
1

Given your code:

$(document).append('<p>Hello</p>');
console.log($(document).find('p').height()); //zero, why?

You are attempting to append HTML to the document which is invalid. Use the body element instead:

$('body').append('<p>Hello</p>');
console.log($('body').find('p').height());

Working example

Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339
  • That was an example, not to be taken literally as adding to the document. – Triynko Nov 30 '15 at 16:56
  • 2
    @Triynko **You** need to post a code example that demonstrates what you're talking about since the example Rory provided refutes your claim. – j08691 Nov 30 '15 at 16:57