2

I'm quite new to PrimeFaces and JSF in general and I couldn't find a topic with similar situation. I checked I have no nested forms. Seems like I'm running into some weird behaviour - at least I have no idea why it does what it does ;)

Let's say I have a List. Class 'Module' has a List. My intention is to show data in a table, nicely grouped by module and elements in rows under it. Seemed like subtable was my wish come true, but I found out it's only for reporting issues, so it's not selectable. Unfortunately I need to know the selection to run actions like 'Delete' or 'Edit' on an module. I tried to place a button in subtable facet with an actionlistener setting the current object in backing bean and then opening a dialog to offer further actions (on selected module). I first thought it works, but then noticed that pressing the same button, a randomly module object was transfered into backing bean.

<p:dataTable id="displayModules" var="displayModuleBean"
     value="#{displayModuleController.displayModuleBeans}"
     emptyMessage="Es existieren keine Module für diese Kampagne.">
     <p:row>
        <p:column headerText="Vermarkter" />
        <p:column headerText="Platzierung" />
        <p:column headerText="Umfeld" />
        <p:column headerText="Format(e)" />
        <p:column headerText="Startdatum" />
        <p:column headerText="Enddatum" />
        <p:column headerText="Abrechnungsart" />
     </p:row>

     <p:subTable id="displayModuleElements" var="displayModuleElement"
        value="#{displayModuleBean.moduleElements}"
        sortBy="#{displayModuleBean.module.name}" sortOrder="descending">
        <f:facet name="header" style="vertical-align: middle">
             #{displayModuleBean.module.name}

           <p:commandButton alt="Modul bearbeiten" icon="ui-icon-pencil"
              style="float:right"
              actionListener="#{displayModuleController.setSelectedDisplayModuleBean(displayModuleBean)}"
              oncomplete="displayModuleEditDialog.show();"
              update=":tabview:displayModulesDialogForm:editDisplayModules">
           </p:commandButton>
        </f:facet>

        <p:column headerText="Vermarkter">
           <h:outputText value="#{displayModuleElement.advertiserName}" />
        </p:column>
     </p:subTable>
  </p:dataTable>

Backing Bean (DisplayModuleController, SessionScoped):

public void setSelectedDisplayModuleBean(ModuleBean selectedDisplayModuleBean)
{
    this.selectedDisplayModuleBean = selectedDisplayModuleBean;
    this.setSelectedDisplayModuleName(this.selectedDisplayModuleBean != null ? this.selectedDisplayModuleBean.getModule().getName()
        : null);
    this.addFacesMessage(FacesMessage.SEVERITY_INFO, "Set selected ModuleBean: ",
        this.selectedDisplayModuleBean != null ? this.selectedDisplayModuleBean.getModule().getName() : "keins");
}

I even tried a workaround with an Accordion Panel and Datatables on each tab, but I'm ending at the same weird behaviour. I also tried adding a button in each row to transfer the selected element itself (not the parent module), but that works exactly the same randomly way.

What the hell am I missing? Would be great if someone could help me to get on the right way ;)

I'm using: PrimeFaces 4.0, MyFaces 2.1.13, Apache Tomcat 7.0.42

LG, Ani

LadyAni
  • 43
  • 1
  • 5
  • sorry for putting that in a comment but maybe you'll have more luck with `` - like so: ` ` – Kuba Nov 28 '13 at 08:58
  • if `displayModuleElement` is in reversed relation to `displayModuleBean` then you might try `` but frankly don't think it would change anything. – Kuba Nov 28 '13 at 09:14

2 Answers2

1

EL method arguments are evaluated at the moment the action method is decoded during form submit. They are not evaluated at the moment the JSF component tree is built, or that its HTML output is generated.

In order to ensure that the right EL method argument value is being evaluated, you need in this specific case ensure that the model behind #{displayModuleController.displayModuleBeans} is exactly the same during processing the form submit as it was during rendering (displaying) the form.

In order to achieve that, the backing bean must be view scoped and the getter of that model must be absolutely free of any business logic. The model must be prepared and filled in an one-time init/action method such as @PostConstruct in case you'd like to populate it "on page load" or in an action(listener) method in case you'd like to populate it "on submit" beforehand.

Otherwise, the model may be off because you for example first sorted and then reloaded the model from the DB by unnecessarily performing a DB call in the getter method like as many starters do.


As a completely different alternative, in case you can't ensure the integrity of the model and thus you risk it to be incompatibly changed in between displaying the form and processing the form submit, then you could use <f:param> to pass a static parameter. It will represent exactly that value as it is during dusplaying the form (during render response) and not during processing the form submit.

E.g.

<p:commandButton ... actionListener="#{displayModuleController.setSelectedDisplayModuleBean}">
    <f:param name="id" value="#{displayModuleBean.id}" />
</p:commandButton>

whereby you set it via <f:viewParam name="id">, or @ManagedProperty("#{param.id}"), or externalContext.getRequestParameterMap().get("id") and convert back to concrete DisplayModuleBean based on a DB find() by ID. See also How can I pass selected row to commandLink inside dataTable?

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thanks for your reply. I have my model bean in SessionScope, isn't that a 'level higher' than ViewScope (same instance is taken as long as user session is active)? I tested with ViewScope, but I'm afraid because I use CDI and therefore choose scope definition from javax.enterprise.context instead of javax.faces.bean package everything stopped working like it did before ;) – LadyAni Nov 28 '13 at 13:33
  • Yes, but this construct would still fail if the model has incompatibly changed by other means in between displaying the form and processing the form submit. – BalusC Nov 28 '13 at 13:35
  • Okay, so session scope is okay and I will ensure that the exactly same list is delivered. Thanks for your suggest, I will check that. – LadyAni Nov 28 '13 at 13:38
  • Got it. My fault was to keep the displayModuleBeans in a TreeMap and in getDisplayModuleBeans() (that's called more times than I thought) return new ArrayList(moduleBeans.values()). Changing the map to a list that is once instantiated fixed the whole stuff. Thank you very much BalusC, I hit the accept button. – LadyAni Nov 28 '13 at 13:57
0

If you are dealing with Entities You might as well pass unique ID as an argument to the BackingBean, write a select method that takes ID as a parameter and sets selected Object as an Instance of your @WindowScoped BackingBean. Then you access your instances like so:

 #{myBean.instance.propertyName}

This way you'll be sure that you use the correct instance.

Kuba
  • 2,069
  • 23
  • 30
  • Aren't you confusing EL method arguments with static parameters such as ``? Static parameters are evaluated with `toString()` and inlined in generated HTML output during view render time. That indeed wouldn't work for "complete" entities. Your answer is namely not making much sense for the question in its current form. – BalusC Nov 28 '13 at 11:37
  • exactly, in current form. She could have one ModalPanel to edit selected instance, and access it via EL. She would have to set the ID of an instance with lets say `` and calling the `selectInstance()` method. I hope it makes sense. – Kuba Nov 28 '13 at 11:52
  • Uhm, a `` doesn't make any difference. That would still be evaluated during processing the form submit. It's only useful if you don't have EL 2.2 feature of passing method arguments. – BalusC Nov 28 '13 at 11:56
  • ok, My logic was 1).to have a form for editing current instance along with a table on one page, editing form is in a modal-panel. 2). select an instance in Backingbean with ajax and update the edit form. 3). do some editing and persist the edit form with another button. – Kuba Nov 28 '13 at 11:59
  • I suggest to stop doing wild guesses and *carefully* read my answer including its links until you get the adrenaline rush of "I finally understood it!". – BalusC Nov 28 '13 at 11:59
  • with all due respect, I know you are very knowledgeable guy and I am not trying to undermine your answer (just upvoted it in fact). But wild guess is a bit too far, since I am currently working on a project that works exactly this way and it works well. – Kuba Nov 28 '13 at 12:06
  • EL 2.2 method argument passing as currently used by OP has exactly the same effect as `` as previously used when EL 2.2 wasn't available. So, ultimately, you're not answering/improving anything. – BalusC Nov 28 '13 at 12:10
  • but I did not say that `` is any superior to method argument passing. What I said is to pass ID as argument. – Kuba Nov 28 '13 at 12:13