EL expression inside p:commandButton onclick does not update/re-render on ajax request?

12,820

Indeed. PrimeFaces (and standard JSF) does not re-evaluate the EL in on* attributes on a per-request basis. It only happens on a per-view basis. RichFaces however does that in <a4j:xxx> components.

You need to solve the problem differently. I suggest to use the visible attribute of the <p:dialog> instead.

<h:form>
    ...
    <p:commandButton value="Delete all friends?" update=":deleteDialogs" />
</h:form>
...
<h:panelGroup id="deleteDialogs">
    <p:dialog id="deleteFriendsConfirmDialog" visible="#{facesContext.postback and not empty userBean.user.friendList}">
        ...
    </p:dialog>
    <p:dialog id="friendsAlreadyDeletedErrorDialog" visible="#{facesContext.postback and empty userBean.user.friendList}">
        ...
    </p:dialog>
</h:panelGroup>

An alternative is to use PrimeFaces' RequestContext in the bean's action method which allows you to execute JavaScript code programmatically in bean's action method (although this tight-couples the controller a bit too much with the view, IMO).

<p:commandButton value="Delete all friends?" action="#{userBean.deleteAllFriends}" />

with

RequestContext context = RequestContext.getCurrentInstance();

if (!user.getFriendList().isEmpty()) {
    context.execute("deleteFriendsConfirmDialog.show()");
} else {
    context.execute("friendsAlreadyDeletedErrorDialog.show()");
}

Unrelated to the concrete problem, your original onclick, while it does not work out in your particular case, shows some poor practices. The javascript: pseudoprotocol is superfluous. It's the default already. Remove it. Also the test against == 'true' is superfluous. Remove it. Just let the EL print true or false directly. The following is the proper syntax (again, this does not solve your problem, just for your information)

<p:commandButton
    onclick="if (#{not empty userBean.user.friendList}) deleteFriendsConfirmDialog.show(); else friendsAlreadyDeletedErrorDialog.show();"
    value="Delete all friends?" />

It would have worked if you were using RichFaces' <a4j:commandButton>.

<a4j:commandButton
    oncomplete="if (#{not empty userBean.user.friendList}) deleteFriendsConfirmDialog.show(); else friendsAlreadyDeletedErrorDialog.show();"
    value="Delete all friends?" />
Share:
12,820
Murat Derya Özen
Author by

Murat Derya Özen

Software Engineer

Updated on June 05, 2022

Comments

  • Murat Derya Özen
    Murat Derya Özen almost 2 years

    The onclick attribute of my commandButton has some EL dependent Javascript inside. To be more specific, here is that piece of code:

    <p:commandButton
        onclick="javascript: if('#{userBean.user.friendList.size() gt 0}' == 'true') deleteFriendsConfirmDialog.show(); else friendsAlreadyDeletedErrorDialog.show();"
        value="Delete all friends?" />
    

    deleteFriendsConfirmDialog clears the list of friends and updates the @form. The list of friends, commandButton and the dialogs are all in that form.

    So I click the button, confirmation dialog comes up (because the length of friends' list is gt 0), I confirm and the list is emptied, the view is updated. However, when I click the Delete all friends? button once more, the confirmation dialog comes up again. Since the length of the list is now 0, I instead expect the error dialog to show.

    That, I guess, is because the Javascript written inside onclick is not updated (although the button is in the form).

    Edit: Changing #{userBean.user.friendList.size() gt 0} to #{not empty userBean.user.friendList} doesn't work neither.

    How come? What's wrong here?

    Any help appreciated. :)

  • Murat Derya Özen
    Murat Derya Özen over 12 years
    I decided to stick with your first approach and added the visibility attribute to the dialogs as you mentioned. But what about the onclick attribute of the button now? How does it know which dialog to show? Because on page load, the list may already be empty, or not.
  • Murat Derya Özen
    Murat Derya Özen over 12 years
    Furthermore, the javascript: and == true weren't there initially. I was just trying every possible combination to make it work :) But thank you very much for the tip.
  • BalusC
    BalusC over 12 years
    Just remove the onclick. The update of the command button will update the dialogs and they will then be shown/hidden depending on the result of the visible attribute. If true, then it will show immediately, else if false, then it will still be hidden. The #{facesContext.postback} will return false if it's on page load (at least, if you adhere the normal practice of navigating between pages by GET).
  • Murat Derya Özen
    Murat Derya Özen over 12 years
    I just figured out why it wasn't working for me. The button doesn't call anything. So the facesContext.postback is initially false. Therefore, clicking the button doesn't do anything even though there are friends in the list. Furthermore; if I remove all the friends one by one (using the remove buttons I placed on each row), then when the last friend is removed, friendsAlreadyDeletedErrorDialog will show out of nowhere. Any idea what to do, other than taking the second approach?
  • BalusC
    BalusC over 12 years
    As to the button not calling anything, try action="#{null}". As to the button which deletes single friends, it should perform an ajax request and not update the "delete all friends" dialogs.
  • Murat Derya Özen
    Murat Derya Özen over 12 years
    Unfortunately action="#{null}" doesn't work. I can't open the page: Error 404--Not Found. Any suggestions?
  • Murat Derya Özen
    Murat Derya Özen over 12 years
    And about the single buttons, on this question of mine, stackoverflow.com/questions/8803032/…, you suggested to update @form. This covers the dialogs too. The confirm dialog is in the form because it executes an ajax call (empties the list)
  • BalusC
    BalusC over 12 years
    Do you have more into the button? ajax=false or something? Dialogs should not go inside a form, they should be outside a form, exactly as shown in my example. The dialogs in turn can however contain another form. A form should cover only exactly the data it needs to process during a full submit.
  • Murat Derya Özen
    Murat Derya Özen over 12 years
    Alright, I'll move the dialogs out of the form. The button only has icon, value, action and update
  • BalusC
    BalusC over 12 years
    I tried to reproduce your problem of the <p:commandButton> not invoke anything when the action attribute is absent. I can't reproduce it with PF 3.0 Final. It works as expected. Your particular <p:commandButton> problem must be caused elsewhere.
  • Murat Derya Özen
    Murat Derya Özen over 12 years
    BalusC, actually, moving the dialogs out of the form solved the problem. I don't know why :) Didn't need the action="#{null}". Thank you very much for your efforts in trying to solve my problem, once again. I appreciate your knowledge and willingness to help others. Thanks.
  • BalusC
    BalusC over 12 years
    You're welcome. Maybe some required="true" validation error occurred in one of the dialogs because its data would also be submitted because it's inside the same form. That's exactly why you should not nest different "forms" inside one same <h:form>.
  • Alexandre Lavoie
    Alexandre Lavoie over 9 years
    It seems that EL reevaluation doesn't work anymore with a4j:commandButton, I was using it before with RichFaces 4.3.X and even 4.5.0.Alpha (don't remember which exactly). Now doesn't work in RichFaces 4.5.0.Alpha3.