13 Replies - 3387 Views - Last Post: 16 March 2013 - 03:52 AM

#1 Zel2008  Icon User is offline

  • D.I.C Addict

Reputation: 14
  • View blog
  • Posts: 763
  • Joined: 06-January 09

Wildcards with getElementById

Posted 13 March 2013 - 11:46 AM

Hi all,

I have a group of buttons that I'm trying to use as a number pad, and they each add their values (as strings) to a text field when they are pushed. All the buttons have similar ID's, from button1 to button0. At the moment, what I have down in my Javascript file is:

document.getElementById( "button1" ).onclick = function () {
	var text = document.getElementById( "button1" ).value;
	if( text.length < 4 ) {
		text += "1";
		document.getElementById( "button1" ).value = text;
	}
};

document.getElementById( "button2" ).onclick = function () {
	var text = document.getElementById( "button2" ).value;
	if( text.length < 4 ) {
		text += "2";
		document.getElementById( "button2" ).value = text;
	}
};



And so on for the 10 buttons. This seems to work, but it would be nice to pare down the Javascript a little. I'm pretty sure from Googling that there's a way to use wildcards for this, but I haven't quite found one that seems to be appropriate to my situation.

Is anyone a wildcard guru who could point me in the right direction? I'd appreciate the advice.

Thanks,
Zel2008

Is This A Good Question/Topic? 0
  • +

Replies To: Wildcards with getElementById

#2 Atli  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 3637
  • View blog
  • Posts: 5,765
  • Joined: 08-June 10

Re: Wildcards with getElementById

Posted 13 March 2013 - 12:17 PM

Hey.

There are a number of ways to do that. Using IDs would not be one I'd recommend. The one that would make most sense to me would be to use a class on all the buttons, and then set an event handler to all elements that use that class. A library like jQuery would be a great help with that, but if you're not worried about supporting ancient browsers (IE7 and lower, FF3 or lower) then you have the option of using the querySelectorAll function to do this. Otherwise you'll want to do this differently.

Consider the following:
<input type="button" class="one-of-us" value="One">
<input type="button" class="one-of-us" value="Two">
<input type="button" class="one-of-us" value="Three">


window.addEventListener("load", function() {
    // Get all the input elements with the class on it.
    var elems = document.querySelectorAll("input.one-of-us");
    
    // Go through the list and apply a click handler to each of them.
    for (var i = 0; i < elems.length; ++i) {
        elems[i].addEventListener("click", function() {
            // Use the value of the clicked element.
            alert("You pressed: " + this.getAttribute("value"));
        }, false);
    }
}, false)


Was This Post Helpful? 0
  • +
  • -

#3 andrewsw  Icon User is online

  • Fire giant boob nipple gun!
  • member icon

Reputation: 2890
  • View blog
  • Posts: 9,597
  • Joined: 12-December 12

Re: Wildcards with getElementById

Posted 13 March 2013 - 12:26 PM

Atli 's approach is more modern (and correct - despite the unnecessary use of getAttribute() :) ) but doesn't give easy access to the index numbers 0-9.

You could have a look at the following but I haven't tested it:

for (var i=0; i < 10; i++) {
    document.getElementById("button" + i).onclick = function () {
        var x = i;
        if (this.value.length < 4) {
            this.value += x;
        }
    };
}

Personally, I would use addEventListener() like Atli - although, I am in favour of event delegation for this kind of code.
Was This Post Helpful? 1
  • +
  • -

#4 andrewsw  Icon User is online

  • Fire giant boob nipple gun!
  • member icon

Reputation: 2890
  • View blog
  • Posts: 9,597
  • Joined: 12-December 12

Re: Wildcards with getElementById

Posted 13 March 2013 - 12:32 PM

Actually, my code doesn't quite work yet - I'll get back to you!
Was This Post Helpful? 1
  • +
  • -

#5 Cbeppe  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 31
  • View blog
  • Posts: 215
  • Joined: 16-September 09

Re: Wildcards with getElementById

Posted 13 March 2013 - 12:33 PM

I'd look into using JQuery if I were you.

Alternatively, there's a relatively new Javascript function that allows you to get all elements in a class called document.getElementsByClassName() which is supported by most modern browsers. I haven't used this yet, but it seems interesting enough to look into.

IDs are more practical to identify a single element, a class works better if you have a group of similar elements.
Was This Post Helpful? 1
  • +
  • -

#6 Zel2008  Icon User is offline

  • D.I.C Addict

Reputation: 14
  • View blog
  • Posts: 763
  • Joined: 06-January 09

Re: Wildcards with getElementById

Posted 13 March 2013 - 12:37 PM

Thanks Atli and andrewsw and Cbeppe,
Atli -- I actually have to support IE6 (ugh) and up, and also be cross-compatible with modern browsers as much as possible. It's a bummer that the querySelectorAll method wouldn't work for the old browsers. I already use a little JQuery, so it might be best to do it that way, how would I go about that?

andrewsw -- Can I just put that for loop at the beginning of a Javascript file, like you could with the document.onclick lines, or would I have to put it in a function?

Cbeppe -- Sorry,you posted in the middle of my reply. I'll definitely look into JQuery, but the fact that I'm required to support ancient browsers might stop me from using document.getElementsByClassName().

Thanks,
Zel2008

This post has been edited by Zel2008: 13 March 2013 - 12:40 PM

Was This Post Helpful? 0
  • +
  • -

#7 andrewsw  Icon User is online

  • Fire giant boob nipple gun!
  • member icon

Reputation: 2890
  • View blog
  • Posts: 9,597
  • Joined: 12-December 12

Re: Wildcards with getElementById

Posted 13 March 2013 - 12:43 PM

<!DOCTYPE html>
<html>
<head>
    <title>Page Title</title>
    <style type="text/css">
        /* */
    </style>
    <script type="text/javascript">
        window.addEventListener("load", function () {
            for (var i=0; i < 10; i++) {
                var btn = document.getElementById("button" + i);
                btn.origVal = i;
                btn.addEventListener("click", function () {
                    if (this.value.length < 4) {
                        this.value += this.origVal;
                    }
                }, false);
            }
        }, false);
    </script>
</head>

<body>
<input type="button" id="button0" value="0">
<input type="button" id="button1" value="1">
<input type="button" id="button2" value="2">
<input type="button" id="button3" value="3">
<input type="button" id="button4" value="4">
<input type="button" id="button5" value="5">
<input type="button" id="button6" value="6">
<input type="button" id="button7" value="7">
<input type="button" id="button8" value="8">
<input type="button" id="button9" value="9">
</body>
</html>



Quote

Can I just put that for loop at the beginning of a Javascript file, like you could with the document.onclick lines, or would I have to put it in a function?

No, you have to wait until the page has loaded so that the page-elements are available. Alternatively, and preferable, place the script at the bottom of the page, just before the closing body tag.

If you are already loading the jQuery library for the page then you should make use of this framework.

This post has been edited by andrewsw: 13 March 2013 - 12:41 PM

Was This Post Helpful? 0
  • +
  • -

#8 Atli  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 3637
  • View blog
  • Posts: 5,765
  • Joined: 08-June 10

Re: Wildcards with getElementById

Posted 13 March 2013 - 12:48 PM

View Postandrewsw, on 13 March 2013 - 07:26 PM, said:

Atli 's approach is more modern (and correct - despite the unnecessary use of getAttribute() :) ) but doesn't give easy access to the index numbers 0-9.

Consider that his code is a numpad, which presumably means his code has the number of the button as it's value. The alert in my snippet was meant to be a vague hint at that.
    for (var i = 0; i < elems.length; ++i) {
        elems[i].addEventListener("click", function() {
            displayElement.value += this.value;
        }, false);
    }



As for the getAttribute. It always kind of seemed more appropriate to me to use this. Not sure why. It doesn't really matter, it's more or less just a matter of style. - Of course, these days I write very little code that does use jQuery, so neither method tends to be used.

View Postandrewsw, on 13 March 2013 - 07:32 PM, said:

Actually, my code doesn't quite work yet - I'll get back to you!

That would be the classic callback within a loop conundrum.

The simplest solution to that is:
for (var i=0; i < 10; i++) {
    (function(i) {
        document.getElementById("button" + i).onclick = function () {
            var x = i;
            if (this.value.length < 4) {
                this.value += x;
            }
        };
    }(i));
}


But I was always more inclined to define the function first and just call it inside the loop. Seems less... wasteful, not that it really matters these days.

View PostCbeppe, on 13 March 2013 - 07:33 PM, said:

Alternatively, there's a relatively new Javascript function that allows you to get all elements in a class called document.getElementsByClassName() which is supported by most modern browsers. I haven't used this yet, but it seems interesting enough to look into.

This function is less powerful and less widely supported than the querySelectorAll function I mentioned before. The whole getElementByX range of function is more or less outdated now, and this function especially since it was added after the querySelector functions. It's an old way of thinking, which is thankfully getting replaced by selectors now, in great a part thanks to jQuery.
Was This Post Helpful? 0
  • +
  • -

#9 Zel2008  Icon User is offline

  • D.I.C Addict

Reputation: 14
  • View blog
  • Posts: 763
  • Joined: 06-January 09

Re: Wildcards with getElementById

Posted 13 March 2013 - 12:52 PM

OK -- let me make sure I understand what your code is doing:

1. Connect an event listener to the current window.
2. The event listener fires when the page loads.
3. This event listener creates 10 more event listeners, each of which connects to the appropriate button.
4. And this does all need to go in a function if I'm calling it from a separate JS file.

Is that right?

I'm not sure what the "false"s are in the event listener calls; apparently they're this --

 useCapture (Optional)
    If true, useCapture indicates that the user wishes to initiate capture. After initiating capture, all events of the specified type will be dispatched to the registered listener before being dispatched to any EventTarget beneath it in the DOM tree. Events which are bubbling upward through the tree will not trigger a listener designated to use capture. See DOM Level 3 Events for a detailed explanation. Note that this parameter is not optional in all browser versions. If not specified, useCapture is false.



Do you understand what that means, could you translate it into a little easier English? :)/>/>

EDIT -- And speaking of confusion -- Atli, are you suggesting some kind of numbered function?

Thanks,
Zel2008

This post has been edited by Zel2008: 13 March 2013 - 12:59 PM

Was This Post Helpful? 0
  • +
  • -

#10 andrewsw  Icon User is online

  • Fire giant boob nipple gun!
  • member icon

Reputation: 2890
  • View blog
  • Posts: 9,597
  • Joined: 12-December 12

Re: Wildcards with getElementById

Posted 13 March 2013 - 01:15 PM

Thanks @Atli. Although this:

displayElement.value += this.value;

will surely double-up on the value, assuming displayElement is the button (which is this anyway..). That is, "1" will become "11" then "1111". Apologies: my misunderstanding. displayElement is presumably a text-input, or DIV, for displaying the output.

I like your IIFE solution although mine has the slight advantage that the initial value remains available as a property of the element.

@OP I wouldn't worry too much about the false argument, but you can read about it at quirksmode.

This post has been edited by andrewsw: 13 March 2013 - 01:18 PM

Was This Post Helpful? 0
  • +
  • -

#11 andrewsw  Icon User is online

  • Fire giant boob nipple gun!
  • member icon

Reputation: 2890
  • View blog
  • Posts: 9,597
  • Joined: 12-December 12

Re: Wildcards with getElementById

Posted 13 March 2013 - 01:48 PM

Just out of interest I created a version using event delegation, but it is probably considered more detailed than necessary. Anyway:

<!DOCTYPE html>
<html>
<head>
<title>Calc Buttons Delegation</title>
</head>

<body>
<h1>Event Delegation with Buttons</h1>
<form id="frmCalc" action="">
    <input type="button" id="button0" value="0">
    <input type="button" id="button1" value="1">
    <input type="button" id="button2" value="2">
    <input type="button" id="button3" value="3">
    <input type="button" id="button4" value="4">
    <input type="button" id="button5" value="5">
    <input type="button" id="button6" value="6">
    <input type="button" id="button7" value="7">
    <input type="button" id="button8" value="8">
    <input type="button" id="button9" value="9">
    <input type="text" id="txtResult">
</form>


<script type="text/javascript">
var addEvent = function (elem, eventType, func) {
    if ( elem.addEventListener )
        addEvent = function (elem, eventType, func) {
            elem.addEventListener(eventType, func, false);
        };
    else if ( elem.attachEvent )
        addEvent = function (elem, eventType, func) {
            elem.attachEvent('on' + eventType, func);
        };
    addEvent(elem, eventType, func);
};

var delegateEvent = function (elem, childElems, eventType, func, args) {
    addEvent(elem, eventType, function (e) {
        var evt = e || window.event;
        var elem = evt.target || evt.srcElement;
        if ( elem.nodeName.toLowerCase() == childElems.toLowerCase() ) {
            func(elem, args);
        }
    });
};

function calcValue(obj, output) {
    if (obj.id.indexOf("button") == 0) {
        // the id starts with "button"
        if (!obj.initValue) {
            // store the value on the button once
            obj.initValue = obj.id.substring(obj.id.length - 1);
        }
        output.value += obj.initValue;
    }
}

function init() {
    var frm = document.getElementById("frmCalc");
    delegateEvent(frm, 'input', 'click', calcValue,
                  document.getElementById("txtResult"));
}

addEvent(window, 'load', init);
</script>
</body>
</html>

The OPs original version seems to add the number to the buttons themselves, which seems a little unusual, so I've appended the numbers to a text-input.

This version should also work with IE6 (attachEvent).
Was This Post Helpful? 0
  • +
  • -

#12 Zel2008  Icon User is offline

  • D.I.C Addict

Reputation: 14
  • View blog
  • Posts: 763
  • Joined: 06-January 09

Re: Wildcards with getElementById

Posted 14 March 2013 - 06:06 AM

Thank you all again,
I think I've got more than what I need to get things working. Thanks especially for all your detailed explanations, they really helped.
Thanks,
Zel2008
Was This Post Helpful? 0
  • +
  • -

#13 Dormilich  Icon User is offline

  • 痛覚残留
  • member icon

Reputation: 3402
  • View blog
  • Posts: 9,621
  • Joined: 08-June 10

Re: Wildcards with getElementById

Posted 16 March 2013 - 03:46 AM

some late additions:

post #7: there is no need to use the custom origVal property on the buttons (line #12) since there already exists the defaultValue property (since DOM 1)

post #8 (getAttribute()): the difference between this.getAttribute("value") and this.value is that the latter adheres to the HTML parser. i.e. if you had <div value="somename"> (which is illegal HTML*), getAttribute() would return "somename" while .value would return undefined.

post #9: the picture here explains it (IMHO) quite well.


* - though illegal in HTML it is legal in DOM/SGML, and getAttribute() is a DOM method. there are two APIs you can use in JS (the DOM API and the HTML API)

This post has been edited by Dormilich: 16 March 2013 - 03:55 AM

Was This Post Helpful? 1
  • +
  • -

#14 andrewsw  Icon User is online

  • Fire giant boob nipple gun!
  • member icon

Reputation: 2890
  • View blog
  • Posts: 9,597
  • Joined: 12-December 12

Re: Wildcards with getElementById

Posted 16 March 2013 - 03:52 AM

View PostDormilich, on 16 March 2013 - 03:46 AM, said:

some late additions:
post #7: there is no need to use the custom origVal property on the buttons (line #12) since there already exists the defaultValue property (since DOM 1)

This didn't occur to me :)
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1