How to use component binding in JSF right ? (reque

2019-01-19 22:48发布

问题:

Mojara 2.1.21

I've updated my question based on comments. I have two situation where a component is bound to server session bean. (Additional links with information: Binding attribute causes duplicate component ID found in the view and https://stackoverflow.com/a/12512672/2692917)

Version 1:

single.xhtml:

 <h:outputText value=... binding="#{mysessionbean.out}" />

java:

 @SessionScoped @Named public class Mysessionbean {
    UIOutput out;
    //getter and setter ....
 }

Version 2:

template.xhtml:

 <h:outputText value=... binding="#{mysessionbean.out}"

view1.xhtml:

 <ui:composition template="template.xhtml" />

view2.xhtml:

 <ui:composition template="template.xhtml" />

java:

 @SessionScoped @Named public class Mysessionbean {
    UIOutput out;
    //getter and setter ....
 }

Version 1 is ok. (At least I've not encounter any errors so far). But in version 2 the duplicate id error is occured if I navigate from one page to another. Why does it happen ? Is it safe to use (request-scoped) component (in version 1) with session scoped binding ? Are there another use cases to consider ?

Edit: Functional requirement 1:

I want to use Primefaces datatable in a view. I need some info from this datatable. (Such as selected row or row index). So binding the datatable helps me to retrieve this info.

Functional requirement 2:

Components binding in composite components. They will be bound to session scoped bean. (And used mainly on one page, but what if I used it on another page ?

Requirements 3

The situation as in "Version 2". Template with primefaces menu and session scoped binding. For this I've used the EL-Binding.

回答1:

In JSF 2.x, unless you want to manipulate components programmatically (which is at its own also rather fishy), there is no sensible real world use case to bind components to a backing bean. For sure not if they are further not been used in the backing bean itself, or if it are solely their attributes which are been flattened out.


As to the functional requirement of getting the current row of the data table, there are much better ways listed here, How can I pass selected row to commandLink inside dataTable?, for example if your environment supports EL 2.2:

<h:dataTable value="#{bean.items}" var="item">
    <h:column>
        <h:commandLink value="Foo" action="#{bean.foo(item)}" />

The two last requirements are totally unclear. At least, if you're doing something like:

<x:someComponent binding="#{bean.someComponent}" />

with in bean

someComponent.setSomeAttribute(someAttribute);
someComponent.setOtherAttribute(otherAttribute);

then you should instead be doing

<x:someComponent someAttribute="#{bean.someAttribute}" otherAttribute="#{bean.otherAttribute}" />

Or, if you intend to be able to use the component somewhere else in the view like so

<h:inputText ... required="#{not empty param[bean.save.clientId]}" />
...
<h:commandButton binding="#{bean.save}" ... />

and the instance is further nowhere been used in the bean, then just get rid of the unnecessary property altogether:

<h:inputText ... required="#{not empty param[save.clientId]}" />
...
<h:commandButton binding="#{save}" ... />

If there is really, really no way for some unclear reason, then split all request scoped properties of the session scoped bean out into a separate request scoped bean which you in turn bind to form actions. The session scoped one can just be injected as a @ManagedProperty of the request scoped one.


See also:

  • Binding attribute causes duplicate component ID found in the view
  • How does the 'binding' attribute work in JSF? When and how should it be used?


回答2:

We ran into a similar problem and I just want to share our solution:

Problem: In a view there was a (extended largely customized) datatable.

<x:dataTable binding="#{bean.someSomeDataTable}" />

After navigating to another page and back we wanted the datatable to have the exact same state. Previously we solved that by binding the datatable to to backing bean. This worked fine with JSPs. With Facelets we could not do that (Duplicate ID errors). So we used the binding, but only saved/restored the state of the datatable component.

public HtmlDataTable getSomeDataTable()
{
 HtmlDataTable htmlDataTable = new HtmlDataTable();
 if (tableState != null)
   htmlDataTable.restoreState(FacesContext.getCurrentInstance(), tableState);
 return htmlDataTable;
}

public void setSomeDataTable(HtmlDataTable table)
{
  tableState = table.saveState(FacesContext.getCurrentInstance());
}


标签: jsf jsf-2 scope