1

I require Cross compatability IE7 upwards For an event listener. Due to the system I am using I can only use an external js file to create the listeners. I wish to create a rule for all textarea boxes, making they increase in height when they wrap the text meaning that you never have to scroll (They need to be printed with all the text showing). This works fine using addEventListener, but because I can't uses THIS I can not get this to work generically using attachEvent.

<html>
<style>
input[type="text"], textarea{ width:10%;}
</style>
<script>
function gettext(){
var x=document.getElementsByTagName("textarea");
var ent; 
for(i = 0; i < x.length; i++){
if (x.item(i).addEventListener) {
    x.item(i).addEventListener("keyup", function () {ChangeDepth(this)}, false)
    x.item(i).addEventListener("mouseup", function () {ChangeDepth(this)}, false)
    x.item(i).addEventListener("change", function () {ChangeDepth(this)}, false)
 }            
 else {
   ent = document.getElementById(x.item(i).id)
   x.item(i).attachEvent ("onkeyup", function () {ChangeDepth(ent)});
   x.item(i).attachEvent ("onmouseup", function () {ChangeDepth(ent)});
   x.item(i).attachEvent ("onchange", function () {ChangeDepth(ent)});

  }
}
}

function ChangeDepth(e){
var t = e.scrollHeight +'px';
if ((e.clientHeight < e.scrollHeight)||(e.clientHeight > e.scrollHeight)){e.style.height = t ;}
}
</script>
<body onload="gettext()">
<p>(Type in the textarea box when the text wraps it will increase the height of the box)<br />
<textarea name="c" cols="" rows="1" id="c"  ></textarea>
<br />
<textarea name="f" cols="" rows="1" id="f"  ></textarea></p>
</body>
</html>

This only works for the last textarea field in IE 8. I am assuming this because It only has the value of the last object. No idea what to do next

David
  • 2,053
  • 2
  • 16
  • 26
user1554759
  • 69
  • 2
  • 7
  • 1
    You don't need to add a reference to the element when you're attaching the event. You could simply wire it like this: `x.item(i).addEventListener("keyup", ChangeDepth, false)` Then you'll only need to change the `ChangeDepth` function. – Shmiddty Sep 24 '12 at 20:42
  • Brilliant. Works and I have learnt something completely new. Thanks – user1554759 Sep 24 '12 at 21:37

5 Answers5

3

http://jsfiddle.net/KAy9a/

function wireUp() {
    console.log('wiring');
    var x = document.getElementsByTagName("textarea");
    var ent;
    for (i = 0; i < x.length; i++) {
        if (x.item(i).addEventListener) {
            x.item(i).addEventListener("keyup", ChangeDepth, false)
            x.item(i).addEventListener("mouseup", ChangeDepth, false)
            x.item(i).addEventListener("change", ChangeDepth, false)
        }
        else {
            x.item(i).attachEvent("onkeyup", ChangeDepth);
            x.item(i).attachEvent("onmouseup", ChangeDepth);
            x.item(i).attachEvent("onchange", ChangeDepth);

        }
    }
}

function ChangeDepth(e) {
    // instead of passing in the element, we get the Event object
    // we can then get the event target (or srcElement) to know where the event came from    
    e = e || event;
    e = e.target || e.srcElement;

    // the code below is the same you had before:
    var t = e.scrollHeight + 'px';
    if ((e.clientHeight < e.scrollHeight) || (e.clientHeight > e.scrollHeight)) {
        e.style.height = t;
    }
}
Shmiddty
  • 13,847
  • 1
  • 35
  • 52
  • 1
    It should be noted that for bubbling events, the element that fired the event (`event.target` or `event.srcElement`) isn't the one calling the listener (i.e. `this` within listeners set using `addEventListener`). – RobG Sep 24 '12 at 23:51
2

You can use a cross–browser addEvent function that sets this to the element within the listener for browsers that use the old IE event model (which includes IE 8 in quirks mode). e.g.

function addEvent(el, evt, fn) {

  if (el.addEventListener) {
    el.addEventListener(evt, fn, false);

  } else if (el.attachEvent) {
    el.attachEvent('on' + evt, function() {fn.call(el);});
  }
}

Now in your code you can do:

function gettext() {
  var x = document.getElementsByTagName("textarea");
  var ent; 

Declare an extra variable to store a reference to the current element.

  var el;

  for (var i = 0; i < x.length; i++) {

Note that i should be declared, otherwise it will become a global variable when the above is executed and possibly mess with other code.

    el = x[i];

Since getElementsByTagName returns a NodeList, you can access members by index, which is less to type. Storing a reference is (imperceptibly) faster and less to type later.

    addEvent(el, 'keyup', ChangeDepth);
    addEvent(el, 'mouseup', ChangeDepth);
    addEvent(el, 'change', ChangeDepth);
 } 

You no longer need to pass a reference to the element since in the listener it will be this. Note that where addEventListener was used to attach the listener, the first argument passed will be the event object. But where attachEvent was used, it won't be passed so get it using window.event.

function ChangeDepth(e) {

  // Get a reference to the related event object
  var e = e || window.event;

  // Get a reference to the element that called the listener
  var elementThatCalledListener  = this;

  ...

}
RobG
  • 142,382
  • 31
  • 172
  • 209
  • do you know how far back attachEvent is supported in IE? –  Feb 26 '13 at 18:28
  • It was certainly in IE 5 and probably in IE 4, perhaps earlier. – RobG Feb 26 '13 at 23:55
  • well, I have to document my code, so I'm going to put IE 5+ to make sure. I don't think getElementByID was available till 5.5. –  Feb 27 '13 at 15:52
  • According to [*JavaScript, The Definitive Guide* ed 4](http://docstore.mik.ua/orelly/webprog/jscript/ch19_03.htm), attachEvent was introduced in IE 5. And yes, I think getElementById was introduced in IE about the same time, along with support for DOM 2 Core. – RobG Feb 27 '13 at 23:31
1

This seems to work - JavaScript:

function load() {
    'use strict';

    function changeHeight(){
        var elem = document.activeElement;

        var heightStr = elem.scrollHeight +'px';
        if ((elem.clientHeight < elem.scrollHeight) || (elem.clientHeight > elem.scrollHeight))
        {elem.style.height = heightStr ;}
    }

    var x = document.getElementsByTagName("textarea");
    var i;

    for (i = 0; i < x.length; i++) {
        if (x[i].addEventListener) {
            x[i].addEventListener("keyup", changeHeight)
            x[i].addEventListener("mouseup", changeHeight)
            x[i].addEventListener("change", changeHeight)
        }
        else {
            x[i].attachEvent("onkeyup", changeHeight);
            x[i].attachEvent("onmouseup", changeHeight);
            x[i].attachEvent("onchange", changeHeight);
        }
    }
}

if (window.addEventListener) {
    window.addEventListener('load', load);
} else if (window.attachEvent) {
    window.attachEvent('onload', load);
}

HTML:

<!DOCTYPE html>
<style>
    input[type="text"], textarea {
        width: 10%;
    }
</style>
<p>(Type in the textarea box when the text wraps it will increase the height of the box)<br/>
    <textarea rows='1'></textarea>
    <br/>
    <textarea rows='1'></textarea>
</p>
<script type="text/javascript" src="legacyEventIE.js"></script>
</body>
</html>

Here is a link to the working code:

http://www.quirkscode.com/flat/forumPosts/legacyEventIE/legacyEventIE.html

Xitalogy
  • 1,592
  • 1
  • 14
  • 17
  • do you know how far back attachEvent is supported in IE? –  Feb 26 '13 at 18:29
  • @pure_code See here (if it is correct) - says since IE 5: http://www.quirksmode.org/js/events_advanced.html#link6 – Xitalogy Feb 28 '13 at 00:23
0

You should avoid creating functions inside loops. This causes problems because the variables used are closure-scoped to the encapsulating function and therefore are common to all the "new" functions.

In other words:

var i, fns = [];
for(i = 0; i < 10; i++) {
    fns.push(function () { return i; });
}

Will create 10 functions that all return 10 (or whatever i ends up being):

fn[0](); //is 10
fn[5](); //is 10
i = 5;
fn[5](); //is 5

There are a few ways to fix this. The first is to use a function wrapper and pass in the dynamic variable as an argument. Like so:

ent = document.getElementById(x.item(i).id)
(function (my_ent, my_i) {
    x.item(my_i).attachEvent ("onkeyup", function () {ChangeDepth(my_ent)});
    x.item(my_i).attachEvent ("onmouseup", function () {ChangeDepth(my_ent)});
    x.item(my_i).attachEvent ("onchange", function () {ChangeDepth(my_ent)});
}(ent, i));

Another, arguably better, solution (at least one that won't cause JSLint to yell at you) is to create a generator function:

var attachEvents = function (item, ent) {
    item.attachEvent ("onkeyup", function () {ChangeDepth(ent)});
    item.attachEvent ("onmouseup", function () {ChangeDepth(ent)});
    item.attachEvent ("onchange", function () {ChangeDepth(ent)});
};

//... Inside the for loop:
    else {
        ent = document.getElementById(x.item(i).id)
        attachEvents(x.item(i), ent);
    }

This is better because its not as "heavy" and it is easier to determine what data are relevant to the creation of the event handlers (e.g. it's easier to maintain).

But it does require more of a change. So it's up to you.

Pete
  • 2,538
  • 13
  • 15
  • Good that you explained about closures. The best solution for this case don't need extra functions or generators. See the answer by Shmiddty, where they are eliminated. – some Sep 24 '12 at 21:08
0
var add_event_column_rubrics = function(){
    var id_current_event;
    var secect_class_column_rubrics = document.querySelector('.rubric_click');

    if(secect_class_column_rubrics.addEventListener)//other
        secect_class_column_rubrics.addEventListener('click',function(e){f_secect_class_column_rubrics(e)},false);
    else{if(secect_class_column_rubrics.attachEvent)//IE
        secect_class_column_rubrics.addEventListener('onclick',f_secect_class_column_rubrics);
}

    var f_secect_class_column_rubrics = function(e){
        e=e||window.event;
        e=e.target||e.srcElement;`enter code here`
        // console.log(e);//debug
        id_current_event = e.id;
        alert(id_current_event);
    };
};
amiron
  • 721
  • 9
  • 11