92

I have a button:

<button id="a" onclick="Foo()">Button A</button>

When I click this button the first time, I want it to execute Foo (which it does correctly):

function Foo() {
  document.getElementById("a").onclick = Bar();
}

What I want to happen when I click the button the first time is to change the onclick function from Foo() to Bar(). Thus far, I've only been able to achieve an infinite loop or no change at all. Bar() would look something like this:

function Bar() {
  document.getElementById("a").onclick = Foo();
}

Thus, clicking this button is just alternating which function gets called. How can I get this to work? Alternatively, what's a better way to show/hide the full text of a post? It originally starts shorted, and I provide a button to "see the full text." But when I click that button I want users to be able to click the button again to have the long version of the text go away.

Here's the full code, if it helps:

function ShowError(id) {
    document.getElementById(id).className = document.getElementById(id).className.replace(/\bheight_limited\b/, '');
    document.getElementById(id+"Text").className = document.getElementById(id+"Text").className.replace(/\bheight_limited\b/, '');
    document.getElementById(id+"Button").innerHTML = "HIDE FULL ERROR";
    document.getElementById(id+"Button").onclick = HideError(id);
}

function HideError(id) {
    document.getElementById(id).className += " height_limited";
    document.getElementById(id+"Text").className += " height_limited";
    document.getElementById(id+"Button").innerHTML = "SHOW FULL ERROR";
    document.getElementById(id+"Button").onclick = "ShowError(id)";
}
user66001
  • 774
  • 1
  • 13
  • 36
Tony Stark
  • 24,588
  • 41
  • 96
  • 113
  • 2
    I'm not making this an answer since you are specifically asking about vanilla JavaScript, but you may want to look into jQuery. It's a JavaScript library that can help you do what you are looking to do in your question. – JasCav Mar 14 '11 at 20:12
  • Know about JQuery, can only use Javascript in this case. Thanks. – Tony Stark Mar 14 '11 at 20:13
  • 1
    The `onclick` property should be in all lowercase. https://developer.mozilla.org/en/DOM/element.onclick – Matt Ball Mar 14 '11 at 20:15
  • Aren't event handlers added by using += ? And perhaps you might even need to do this: `myobject.onclick += function() { Foo(); }` – Mikael Östberg Mar 14 '11 at 20:16
  • 1
    Turns out I didn't need the +=. I think += wouldn't remove the existing onclick function, right? – Tony Stark Mar 14 '11 at 20:22

8 Answers8

131

Your code is calling the function and assigning the return value to onClick, also it should be 'onclick'. This is how it should look.

document.getElementById("a").onclick = Bar;

Looking at your other code you probably want to do something like this:

document.getElementById(id+"Button").onclick = function() { HideError(id); }
Ryan
  • 1,646
  • 1
  • 12
  • 8
  • 15
    Just wanted to add that Ryan does not include the parentheses after Bar because it is not a function call. – GoldfishGrenade Nov 07 '14 at 04:01
  • ... you probably want to do something like this: .onclick = HideError; // if this won't work, why not. What's the diff from above answer? – pashute Jun 01 '16 at 04:04
  • @pashute The difference is that `.onclick = HideError` is going to invoke `HideError(event: MouseEvent)` whereas the above answer invokes `HideError(id)`. If you don't care about parameters, then you can do the shorter version and ignore the event that gets passes in. – Patrick Oct 18 '19 at 16:04
85
var Foo = function(){
    document.getElementById( "a" ).setAttribute( "onClick", "javascript: Boo();" );
}

var Boo = function(){
    alert("test");
}
Otuyh
  • 2,384
  • 5
  • 22
  • 40
  • 2
    This seems to be the best way to do it. Though others work, adding a function directly to onclick may not work in some scenarios. I faced an issue in a case where creating multiple buttons in a loop and assigning a function for onclick for each button in the loop was not working. It would assign the function for the last button to all the buttons. Using this method works like a charm. Thanks Hor! – Deepak G M Jan 22 '13 at 08:59
  • 2
    Should be `onclick`, not `onClick`. – user66001 Mar 30 '14 at 15:22
  • @user66001 it doesn't matter, HTML is not case sensitive – Kyle Sep 11 '15 at 13:59
  • @Calne - camel case'ng it might make people think it needs to be. – user66001 Sep 11 '15 at 15:22
  • 2
    Is this still true? 'onClick' did not work for me, but 'onclick' did.Using Chrome 47 on Windows 7 64-bit. – Sujay Phadke Dec 26 '15 at 08:07
25

Do not invoke the method when assigning the new onclick handler.

Simply remove the parenthesis:

document.getElementById("a").onclick = Foo;

UPDATE (due to new information):

document.getElementById("a").onclick = function () { Foo(param); };
Community
  • 1
  • 1
John Giotta
  • 16,432
  • 7
  • 52
  • 82
15

Thanks to João Paulo Oliveira, this was my solution which includes a variable (which was my goal).

document.getElementById( "myID" ).setAttribute( "onClick", "myFunction("+VALUE+");" );
TheSatinKnight
  • 696
  • 7
  • 16
11

I recommend this approach:

Instead of having two click handlers, have only one function with a if-else statement. Let the state of the BUTTON element determine which branch of the if-else statement gets executed:

HTML:

<button id="a" onclick="toggleError(this)">Button A</button>

JavaScript:

function toggleError(button) { 
    if ( button.className === 'visible' ) {
        // HIDE ERROR
        button.className = '';
    } else {
        // SHOW ERROR
        button.className = 'visible';
    }
}

Live demo: http://jsfiddle.net/simevidas/hPQP9/

Šime Vidas
  • 182,163
  • 62
  • 281
  • 385
  • I personally like this solution because it keeps the code for the button together (and being a toggle, if you update one side, usually you want to update the other side), but I was also working with Vue and using v-on:click, so the top answer didn't seem to be working for me. Thanks Sime! – OhFiddleDiddle Sep 10 '19 at 06:08
6

You could try changing the button attribute like this:

element.setAttribute( "onClick", "javascript: Boo();" );
Kyle
  • 1,568
  • 2
  • 20
  • 46
4

What might be easier, is to have two buttons and show/hide them in your functions. (ie. display:none|block;) Each button could then have it's own onclick with whatever code you need.

So, at first button1 would be display:block and button2 would be display:none. Then when you click button1 it would switch button2 to be display:block and button1 to be display:none.

1

For anyone, like me, trying to set a query string on the action and wondering why it's not working-

You cannot set a query string for a GET form submission, but I have found you can for a POST.

For a GET submission you must set the values in hidden inputs e.g.

an action of: "/handleformsubmission?foo=bar" would have be added as the hidden field like: <input type="hidden" name="foo" value="bar" />

This can be done add dynamically in JavaScript as (where clickedButton is the submitted button that was clicked:

var form = clickedButton.form;
var hidden = document.createElement("input");
hidden.setAttribute("type", "hidden");
hidden.setAttribute("name", "foo");
hidden.setAttribute("value", "bar");
form.appendChild(hidden);

See this question for more info submitting a GET form with query string params and hidden params disappear

anotheruser1488182
  • 315
  • 1
  • 3
  • 9