4

I need to enable / disable a button on a JSF 2.0 page depending on user has entered text in a text area or not.

However, while enabling/disabling the button works, the action is not getting invoked.

Here is the code:

<script>
                                function countChar() {
                                    var val = findElement('inputNoteTextArea');
                                    var len = val.value.length;
                                    var maxLen = 400;
                                    var charLeft;
                                    $('#charNum').text(
                                            'Note:' + maxLen + ' characters left  out of ' + maxLen);
                                    if (len >= maxLen) {
                                        val.value = val.value.substring(0, maxLen);
                                        $('#charNum').text(' you have reached the limit');
                                        document.getElementById('noteSubmitButton').disabled = false;
                                    } else if (len > 0 ){
                                        charLeft = maxLen - len;
                                        $('#charNum').text(
                                                'Note :' + charLeft
                                                        + ' characters left  out of ' + maxLen);
                                        document.getElementById('noteSubmitButton').disabled = false;
                                    } else {
                                        charLeft = maxLen - len;
                                        $('#charNum').text(
                                                'Note :' + charLeft
                                                        + ' characters left  out of ' + maxLen);
                                        document.getElementById('noteSubmitButton').disabled = true;
                                    }
                                }                               
                            </script>
                            <h:inputTextarea
                                value="#{requestScopeBean.notes}" rows="6"
                                cols="90" onkeyup="countChar();" 
                                id="inputNoteTextArea" binding="#{requestScopeBean.inputNoteText}">                                         </h:inputTextarea>
                            <div id="charNum" class="fontNormal11">
                                <span class="fontB11">Note:</span> 400 characters
                                left out of 400
                            </div>
                            <a4j:commandButton styleClass="cmdButton marR5 floatL"
                                value="Save Note" id="noteSubmitButton"
                                render="NotesForm"
                                action="#{requestScopeBean.saveNotes}"
                                title="Submit" disabled="#{requestScopeBean.enableDisableButton}"
                                oncomplete="countChar();"/>
                            <script>
                            document.getElementById('noteSubmitButton').disabled = true;
                            </script>
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Walker
  • 1,277
  • 10
  • 22
  • 30

1 Answers1

5

Re-enabling a server-side disabled button via JavaScript indeed will never work. When processing the form submit, JSF will check the disabled attribute once again before creating and queueing the action event. This is done as part of safeguard against tampered/hacked requests (imagine a command button which is disabled when the user isn't the site admin, such a button absolutely shouldn't be enableable by just JavaScript code which the enduser has full control over).

In your case, the disabled="#{bean.disabled}" still evaluated true at that moment, making the button effectively still disabled during processing the form submit and thus the action event won't be queued and the action method won't be invoked. This is also mentioned as point #5 of commandButton/commandLink/ajax action/listener method not invoked or input value not updated.

What should you do? Just enable the button by JSF instead of JavaScript. Let the disabled attribute instead check if the input value is empty or not.

<h:inputTextarea value="#{bean.input}" ...>
    <f:ajax event="keyup" delay="200" render="buttonId" />
</h:inputTextarea>
<h:commandButton id="buttonId" ... disabled="#{empty bean.input}" />

The delay="200" is just to avoid the server being hit by a flood of ajax requests, one for every single typed character.

Or, initially disable the button by JavaScript instead of JSF. You already have the right script for that in place, however it's missing the form ID, causing it possibly to not work (using <h:form prependId="false"> is by the way bad practice, you shouldn't do that).

<h:form id="formId">
    ...
    <h:commandButton id="buttonId" ... /> <!-- Note: no JSF disabled attribute! -->
</h:form>

<script>
    document.getElementById("formId:buttonId").disabled = true;
</script>

Don't forget to remove the JSF disabled attribute from the button, for reasons explained above.

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • by removing disabled attribute, it worked. action is getting invoked now. in page's view source earlier i could see only onClick = "return false;" for command button. now its value is like : onclick="jsf.util.chain(this,event,"return true;","RichFaces.ajax(\"noteSubmitButton\",event,{\"incId\":\"1\"} )");return false;" – Walker Jan 22 '14 at 10:00
  • i could do ajax using as well, but i was seeing that processing circle on each keyup, which may disturb user while adding notes. using resulted in button enable / disable only after user clicked out of input text area component, so, it did not look as dynamic. Hence going with javascript way. – Walker Jan 22 '14 at 10:02