4

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. :)

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Murat Derya Özen
  • 2,154
  • 8
  • 31
  • 44

1 Answers1

7

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?" />
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • 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 Jan 11 '12 at 16:57
  • 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. – Murat Derya Özen Jan 11 '12 at 16:59
  • 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). – BalusC Jan 11 '12 at 17:01
  • 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? – Murat Derya Özen Jan 11 '12 at 17:13
  • 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. – BalusC Jan 11 '12 at 17:17
  • Unfortunately `action="#{null}"` doesn't work. I can't open the page: `Error 404--Not Found`. Any suggestions? – Murat Derya Özen Jan 11 '12 at 17:25
  • And about the single buttons, on this question of mine, http://stackoverflow.com/questions/8803032/datatable-does-not-update-after-successful-ajax-call, 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) – Murat Derya Özen Jan 11 '12 at 17:31
  • 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. – BalusC Jan 11 '12 at 17:32
  • Alright, I'll move the dialogs out of the form. The button only has icon, value, action and update – Murat Derya Özen Jan 11 '12 at 17:41
  • I tried to reproduce your problem of the `` 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 `` problem must be caused elsewhere. – BalusC Jan 11 '12 at 18:17
  • 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. – Murat Derya Özen Jan 11 '12 at 20:37
  • 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 ``. – BalusC Jan 11 '12 at 20:39
  • 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. – Alexandre Lavoie Aug 26 '14 at 16:01