Hiding overflowing element based on its height

365 views Asked by At

I'm writing (using pure JavaScript = no JQuery) a custom control which is a container that collapses it's contents when they span multiple lines and show only the first one. When you click a button in the control (down arrow), the container expands all of it's content. If content spans only 1 line, I don't show the button at all and it behaves as a regular container.

The 2 pictures below show the control collapsed (upper one) and expanded (bottom one).

Control collapsed

Control expanded

The problem I face is how do I know when to show the button and when not = how to detect if content is multiline or spans only a single line. My approach would be getting the height of the element, then collapsing it and seeing if the height changed (if it did, then it must be multiline).

The problem with that approach is inside my function createCollapsingPanel() the element I'm creating hasn't been yet appended to the DOM - the function returns the element, which will only then be appended to DOM (illustrated by Architecture 1 below). If that would concern only that 1 function, I could of course move appending inside the function (Architecture 2 below). Unfortunately that is the way I wrote all of my functions (they return elements, which are only then appended into parent elements in the outer functions that called them) and so that would mean re-writing other parent functions that in the end call this one, in general my whole architecture of functions.


Architecture 1

function createOuterElement() {
  var outerElement = document.createElement(...);

  outerElement.appendChild(createInnerElement());
  /* Do other things with outerElement */

  return outerElement;
}

function createInnerElement() {
  var innerElement = document.createElement(...);

  /* Do things with innerElement */

  return innerElement;
}

Architecture 2

function createOuterElement(parentElement) {
  var outerElement = document.createElement(...);

  parentElement.appendChild(outerElement);
  createInnerElement(outerElement);
  /* Do other things with outerElement */
}

function createInnerElement(parentElement) {
  var innerElement = document.createElement(...);

  parentElement.appendChild(innerElement);
  /* Do other things with innerElement */
}

Main Question

Any ideas on how to deal with that in my current architecture (Architecture 1)? Maybe there's an event I could attatch to the control element and it would get invoked after the element is inserted into DOM and browser styles are calculated for it?

Additional Question

Is writing functions in Architecture 1 considered a bad practice? I'm pretty new to non-basic JavaScript, so am unsure what good practices are.

2

There are 2 answers

9
dreamlab On BEST ANSWER

you could always have the inner container be multiline and just clip it with the outer container.

on the outer container use:

  • overflow: hidden
  • height:somevalue

on the inner container use:

  • position: absolute
  • height: auto

put the span's inside the inner container.

you can now measure the inner containers height independently from the outer ones.

6
dreamlab On

you can use a hidden container in the dom to measure element sizes. the hidden container can be a simple div in the dom like:

   ...
   <body>
      <div id="measurementContainer" style="display:none;"></div>

a measuring function could than:

  1. append the element to the measurement container (div)
  2. measure the element
  3. and remove it from the measurement container again

for example:

    function measureElementWidth(element) {
       var measurementContainer = document.getElementById(measurementContainer);
       measurementContainer.appendChild(element);

       var width = element.clientWidth;

       measurementContainer.removeChild(element);

       return width;
}

alternatively you can use MutationObservers and get notified if an element is added to the dom. check if all needed browsers support this.


or even simpler: just call your sizing function after you append your elements to the dom.