2

I am trying to convert as much jQuery into native JavaScript on a project, partially for learning more JS.

Below is some code I have that Expands a text area when Focus and on Blur makes it small again.

It works just fine except one textarea fields that are inserted into the DOM after the DOM is loaded, how can I make it work for those items as well without using jQuery?

(function() {

    var descriptions = document.querySelectorAll('.edit_description');

    for (var i = 0; i < descriptions.length; i++){
        descriptions[i].addEventListener('blur', handler, false);
        descriptions[i].addEventListener('focus', handler, false);
    }

    //descriptions.addEventListener('blur', handler, false);
    //descriptions.addEventListener('focus', handler, false);

    function handler(event) {
        if (event.type === "blur") {
            // It's a blur event
            this.setAttribute("style","height:18px;");
            this.style.height = "18px";
        }
        else {
            // It must be a focus event
            this.setAttribute("style","height:10em;");
            this.style.height = "10em";
        }
    }
})();

This jQuery version works perfectly, even for text fields added after the DOM has already loaded and that is what I need to reproduce but in native JavaScript that does not rely on other libraries like jQuery....

$(document).on("focus", "textarea.edit_description", function() {
    $(this).addClass("expanding")
    $(this).animate({
        height: "10em"
    }, 500);
});
$(document).on("blur", "textarea.edit_description", function() {
     $(this).animate({
         height: "18px"
     }, 500);
     $(this).removeClass("expanding")
});
JasonDavis
  • 48,204
  • 100
  • 318
  • 537
  • provide us the fiddle. – Fahad Khan Sep 26 '14 at 01:42
  • 1
    If you're running this code at page load/document ready, that other new element doesn't exist then, so why would it have a handler? You need to add the handler when you add the element. – Jared Farrish Sep 26 '14 at 01:56
  • This could help you http://stackoverflow.com/questions/20330945/how-to-addeventlistener-to-future-dom-elements – icaru12 Sep 26 '14 at 02:00
  • 2
    [Or...](http://jsfiddle.net/qghvz7tm/) – Jared Farrish Sep 26 '14 at 02:15
  • 1
    event delegation should be the pattern you are looking for. – sabithpocker Sep 26 '14 at 02:15
  • @JaredFarrish You Fiddle link indeed does exactly as I need! I don't really understand how the `setTimeout` function is adding a new `textarea` which in turn makes my other newly added textares work? It works but I don't really understand why! Would love a detailed answer if you have the time – JasonDavis Sep 27 '14 at 00:25

2 Answers2

2

Attach the handlers to the document and check event.target to see if it has the appropriate class.

function handler(e) {
  // check that the event target has the desired class
  if (e.target.classList.contains("edit-description")) {
    console.log("%s %o", e.type, e.target);
  }
}

// add handlers using the useCapture argument
document.addEventListener("blur", handler, true);
document.addEventListener("focus", handler, true);

// add another input to the DOM
var input = document.createElement("input");
input.id = "b";
input.className = "edit-description";
document.body.insertBefore(input, document.body.children[1]);
<input id="a" class="edit-description">

Note that we specified true for the addEventListener() useCapture argument. This is necessary for event delegation (in this case) because blur and focus are not bubbling events.

See also: Element.classList

canon
  • 40,609
  • 10
  • 73
  • 97
2

Why do you want to use javascript for this? Are you opposed to a CSS solution? You can target focused elements using the :focus selector:

.edit-description {
  height: 1em;
  display: block;
}
.edit-description:focus {
  height: 10em;
}
<textarea class="edit-description"></textarea>
<textarea class="edit-description"></textarea>
<textarea class="edit-description"></textarea>
canon
  • 40,609
  • 10
  • 73
  • 97
  • 1
    I'm not, it actually slipped my mind as i'm so used to seeing it done with JS lately. One thing I have to be careful of is this will be part of a Module that will be installed in SugarCRM so some people/businesses have dinosaur computers/browsers so I just need to make sure it works going far back in time...I imagine it would though, thanks for sharing! – JasonDavis Sep 27 '14 at 17:18
  • 1
    @jasondavis - Since you're wanting to support legacy browsers, note that IE8 and below do not support [`EventTarget.addEventListener()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.addEventListener#Browser_compatibility). You need to [include a detection for `EventTarget.attachEvent()`](http://stackoverflow.com/a/10896968/451969) and use it instead for IE8 and below (note it uses a different event name than `.addEventListener()` and also that it's been removed from IE11 altogether). – Jared Farrish Sep 27 '14 at 20:41
  • @jasondavis I believe there's support for `:focus` back to IE8. – canon Sep 28 '14 at 00:51