Search code examples
javascriptjquerydom-traversal

Iterate over dom elements using document.getElementsByTagName, pass element as jquery object


What I need is to iterate over the dom at some start element and then go through all elements below the start element.

Here is what I was doing so far.

function iterDomFromStartElem = function(startElem, callBackFunc) {
    if (startElem !== null) {
        var items = startElem.getElementsByTagName("*");
        for (var i = 0; i < items.length; i++) {
            callBackFunc(items[i]);
        }
    }
}

The reason why I need to iterate over the dom from some start element is because our team recently got a request to implement font resizing; however, we developed are site statically with font-size in many different places using pixels. I realize that the easier approach would be to refactor the existing code, set a static font size at the root of the page, and use em's/percentages else where, so that if the business owner wanted to have a resize control on the pages, all we would have to do is increase the font-size in one spot. This refactor would require many hours, and i have been tasked with this using the least amount of man hours.

So, then, I have a call back defined like so,

function resizeFont(startElem, scale) {
    iterDomFromStartElem(startElem, function(node) {
        // get current size of node, apply scale, increase font size
    }
}

Using this raw javascript would work but i'm having trouble getting font-size if its declared inside a css class.

I know that jquery has a css property and if I had a jquery object I could do $(this).css(....), so,

when I call callBackFunc(items[i]), how can I convert the items[i] into a jquery object so that in my call back function, I can do node.css(......)?

I guess I could do $(items[i].id), perhaps that would be the simplest.

Is there an easier way with javascript to determine the font size even if that font size is declared in a css class and that css class is attached to the element?


Solution

  • Preface: I think you're better off fixing the problem properly. You might save an hour or two now by taking a shortcut, but it's likely to cost you in the long term.

    But re your actual question:

    how can I convert the items[i] into a jquery object so that in my call back function, I can do node.css(......)?

    If you pass a raw DOM object into $(), jQuery will return a wrapper around it. You don't have to go via the ID.

    You can also get a jQuery instance for all descendant elements of a given starting point, like this:

    var x = $("#starting_point *");
    

    ...although you'd still end up creating a lot of temporary objects if you then looped through it, like this:

    $("#starting_point *").each(function() {
        // Here, `this` is the raw DOM element
    });
    

    Here's an example of looping all elements under a given starting point with jQuery, in this case showing their tag and id (if any) and turning them blue (live copy):

    $("#start *").each(function() {
      display(this.tagName + "#" + (this.id || "?"));
      $(this).css("color", "blue");
    });
    

    Note I said under. If you also want to include #start, the selector changes to #start, #start *.

    Here's a complete example of increasing the font size of elements starting with (and including) a given start point, where the font size is variously set by inline and stylesheet styles (live copy):

    CSS:

    .x13 {
      font-size: 13px;
    }
    .x17 {
      font-size: 17px;
    }
    .x20 {
      font-size: 20px;
    }
    

    HTML:

    <input type="button" id="btnBigger" value="Bigger">
    <div id="start" class="x13">
      This is in 13px
      <p style="font-size: 15px">This is in 15px
        <span class="x17">and this is 17px</span></p>
      <ul>
        <li id="the_list_item" style="10px">10px
          <strong style="font-size: 8px">8px
            <em class="x20">five</em>
          </strong>
        </li>
      </ul>
    </div>
    

    JavaScript:

    jQuery(function($) {
    
      $("#btnBigger").click(function() {
        $("#start, #start *").each(function() {
          var $this = $(this),
              fontSize = parseInt($this.css("font-size"), 10);
          display("fontSize = " + fontSize);
          $this.css("font-size", (fontSize + 2) + "px");
        });
      });
    
      function display(msg) {
        $("<p>").html(msg).appendTo(document.body);
      }
    
    });