Keeping a variable value on two different pages using jsf managed beans [duplicate] - jsf-2.2

This question already has answers here:
Creating master-detail pages for entities, how to link them and which bean scope to choose
(2 answers)
Closed 7 years ago.
My site has a page with a datatable. This datatable has a button called 'Edit', where the user can click to edit the data of a single row. When the use clicks on it, he gets redirected to another page, where the data of the selected item will be displayed for him to edit.
The way I make it right now is with a SessionScoped bean, where I can keep the value for the selectedItem variable. However, it feels gross to use SessionScoped here.
Simplified Code:
<h:form>
<p:dataTable id="dataTable" var="item" value="#{exampleController.itens}">
<p:column headerText="Name">
<h:outputText value="#{item.name}" />
</p:column>
<p:column>
<p:commandLink title="Edit" action="/pages/anotherPage?faces-redirect=true">
<f:setPropertyActionListener value="#{item}" target="#exampleController.selectedItem}" />
</p:commandLink>
</p:column>
</p:dataTable>
</h:form>
What is a better way of doing this?
Thank you.

You should try view params, that way you win two things:
Your url becomes friendly, (somethinh like http://localhost/view?param=value)
You can remove your ugly session bean
To do this you need in your action:
<p:commandLink title="Edit" action="/pages/anotherPage?faces-redirect=true">
<f:param name="foo" value="#{item}"/>
</p:commandLink>
And in your edit view:
<f:metadata>
<f:viewParam name="foo" value="#{viewBean.item}"/>
</f:metadata>
More info with the great Balus Balus - Communication in JSF

Related

How to dynamically show/hide components under p:tab via ajax?

Forgive me I am not even sure my question is correctly stated. I am trying to unravel relationship between p:tab and h:panelGroup. I have very shallow understanding of JSF. I have following code.
<p:tabView id="view">
<p:tab id="A">
...
<p:ajax event="change" update="C,D" listener="#{bean.captureValue}"/>
</p:tab>
<p:tab id="B" titleStyleClass="x">
<h:panelGroup id="C">
<h:panelGroup rendered="#{bean.checkValue eq 'Yes'}"/>
<f:facet name="title"><table>...</table></f:facet>
<div>....</div>
</h:panelGroup>
</h:panelGroup>
<h:panelGroup id="D">
<h:panelGroup rendered="#{bean.checkValue eq 'No'}"/>
<f:facet name="title"><table>.....</table></f:facet>
<div>....</div>
</h:panelGroup>
</h:panelGroup>
</p:tab>
</p:tabView>
So within component id="A", a user selects a value from drop down menu, bean captures it and dynamically show or hide component id="C" or "D" based on the value.
First time try, I didn't have any h:panelGroup tags. I used rendered attribute directly from p:tab component however I realized that unless I refresh the entire page, the bean.checkValue wouldn't know latest value captured. By reading many articles in this forum, I realized I have to wrap it with h:panelGroup which in turn worked by showing either h:panelGroup "C" or "D" based on the value selected from p:tab tag with id="A".
However the contents of f:facet tag is not visible anymore. It has html table tag which contains h:outputText with static value and p:graphicImage. I am not sure why and hope someone can solve this mystery.
Update:
Thanks to Arthur. I was able to fix the issue with his help. I paste here code that performs expected output.
<p:tabView id="view">
<p:tab id="A">
...
<p:ajax event="change" update="view" listener="#{bean.captureValue}"/>
</p:tab>
<p:tab id="B" titleStyleClass="x">
<f:facet name="title">
<ui:fragment rendered="#{bean.checkValue eq 'Yes'}"/>
<table>...</table>
</ui:fragment>
</f:facet>
<ui:fragment rendered="#{bean.checkValue eq 'Yes'}"/>
<div>...</div>
</ui:fragment>
<f:facet name="title">
<ui:fragment rendered="#{bean.checkValue eq 'No'}"/>
<table>...</table>
</ui:fragment>
</f:facet>
<ui:fragment rendered="#{bean.checkValue eq 'No'}"/>
<div>...</div>
</ui:fragment>
</p:tab>
</p:tabView>
Facets are representing a named section within a container component. Container for your facets are in both cases <h:panelGroup> and this component doesn't define any facet which you could use. As you don't provide in your sample code any name for the facet (which is mandatory) I only assume that maybe you would like to use a title facet for a tab, as <p:tab> component define facet named "title". Then it should look like
<p:tab id="B">
<f:facet name="title" >
<h:outputText value="Test1" rendered="#{bean.checkValue}"/>
<h:outputText value="Test2" rendered="#{!bean.checkValue}"/>
</f:facet>
</p:tab>
, so you implement rendering logic inside facet value (you decide which title would be displayed. This logic could be also moved to backing bean. Keep in mind that in primefaces sometimes components doesn't handle very well and you could try then use them as an attribute instead of facets as stands in this post
It is also possible that you misunderstand meaning of facets. The best way to explain them are the facets defined i component. Authors of this component wanted to provide for users possibility to define header and footer of datatable. Then you, as a jsf user can compose header for instance, from other different components. You could also check this post where facets are also explained.
One more thing to add is that using <h:panelGroup rendered="#{bean.checkValue}"/> for render logic is considred as bad pattern as it is going to produce a <span> element in your code. Instead you should use <ui:fragment rendered="#{bean.checkValue}"/> which is intended for rendering logic and it won't produce any additional html code

Command Link under tab using Ajax Primefaces

I know that this question may be similar to this one but I didn't understand the answer at all.
I am using a full page layout, in the left layout I have some nested accordion panels, tabs and command links. I want this links to update center layout content form.
Left Layout:
<h:form>
<p:accordionPanel>
<p:tab title="Parent Tab">
<p:accordionPanel>
<p:tab title="Child Tab">
<p:commandLink value="link" update=":contentform" />
</p:tab>
</p:accordionPanel>
</p:tab>
</p:accordionPanel>
</h:form>
Center Layout:
<h:form id="contentform">
<ui:include src="#{layoutUI.viewId}" />
</h:form>
And a simple explanation will help cause the similar question lacks in that :(
The proper use of the built in Ajax functionality of the p:commandLink component is to specify that the link will invoke an Ajax call with the ajax attribute.
<p:commandLink value="link" ajax="true" update=":contentform" />
Using the : in front will signify that you are looking for the ID of a component on the ViewRoot rather than its direct Naming Container so this is correct. The only thing missing is the ajax attribute.

h:commandButtoon and f:ajax does not render a h:dataTable if no action property is provided

I have the followig form with a dataTable and a edit section with input fields to manipulate the table data. I want to refresh the datatable after a the commandButton was clicked:
<f:ajax>
<h:panelGroup id="timesheet_panel">
<h:dataTable id="datatable"
value="#{timesheetController.myTimeSheet}" var="child">
......
<h:column>
<!-- update editor panel data -->
<h:commandLink
action="#{timesheetController.load(child.item['$uniqueid'])}">
<h:outputText value="#{message.edit}" />
<f:ajax
render=":#{component.parent.parent.parent.parent.clientId}:editorpanel" />
</h:commandLink>
</h:column>
</h:dataTable>
<!-- Editor -->
<h:panelGroup id="editor">
<h:inputText value="#{timesheetController.workitem.item['_category']}" />
<h:commandButton action="/mypage"
actionListener="#{timesheetController.process('10')}"
value="Update Tabledata">
<f:ajax render="datatable" />
</h:commandButton>
</h:panelGroup>
</h:panelGroup>
</f:ajax>
Note: I have a h:column with a h:commandLink to update the data shown in the editor panel below the table.
The question is: why is it necessary to provide the action property for the commandButton in the editor panel? If I did not provide the action property the f:ajax render="datatable" will not refresh the datatable.
So it seems to me that only a actionListener can be used here to update backend data. A action method will only work if the result of the action is equal to the current page.
Can anybody explain this behavior?
I am working on GlassFish 3.1.2
To refresh the table you need to put your bean in #ViewScoped at least. Ortherwise, your beed will be recreated after values are set so you'll get to same point.

Primefaces components to update when commandButton is clicked

Lets say we have button
<h:form>
<p:commandButton id="refreshButton" value="refresh all depending components"/>
</h:form>
Along the way I will add components that should be updated when the button is clicked. So using the update="text1,text2" will not suffice, as text3 might be added later on and shouldn't require changes to the refresh button.
<h:outputText id="text1" value="{bean.someValue1}></h:outputText>
<h:outputText id="text2" value="{bean.someValue2}></h:outputText>
... and later ...
<h:outputText id="text3" value="{bean.someValue3}></h:outputText>
What I want to do is to bind the components to the button, rather than the button having dependencies to the components
What you're asking is not possible. As least, not using the standard ways in the view.
But what is possible is to reference a common parent instead.
<p:commandButton ... update="texts" />
...
<h:panelGroup id="texts">
<h:outputText id="text1" ... />
<h:outputText id="text2" ... />
...
<h:outputText id="text3" ... />
</h:panelGroup>
Depending on the concrete functional requirement, which isn't clear from the question, there may be better solutions. But if it boils down to laziness and/or avoiding to "forget" to change the button, then I'm afraid that there's no magic fix.
I did a a temporary quickfix by using
<p:outputPanel autoUpdate="true">
<h:outputText id="text3" ... />
<p:outputPanel />
Guess it performance wise is not perfect, as it will be updated on all ajax events and not just the ones I'm interested in. But luckily this component is interested in all of them any ways, so it is not a problem atm.

JSF ajax commandbutton not updating primefaces picklist

This is the code:
<h:form id="articleForm" >
<p:commandButton value="Select tags" ajax="true" >
<f:ajax execute="#form" render="#form :articleForm:tags" />
</p:commandButton>
<p:pickList id="tags" value="#{articleController.dualListModelForTags}" var="tag" itemLabel="#{tag.tag}" itemValue="#{tag}" converter="distinctTagConverter">
<f:facet name="sourceCaption">Distinct tags</f:facet>
<f:facet name="targetCaption">Connected tags</f:facet>
</p:pickList>
</h:form>
When the commandbutton is clicked, the getDualListModelForTags() in the backing bean is called and executed. In getDualListModelForTags() I make some modifications so I want the picklist to be updated. But the picklist(id=tags) is not rendered again. Only when I refresh the page, are the modifications made to the picklist.
The PrimeFaces <p:commandButton> component doesn't work together with <f:ajax>. You need to use the button's own ajax-targeted attributes instead. Instead of the <f:ajax execute> you should use <p:commandButton process>. But this already defaults to #form, so you can omit it. Instead of the <f:ajax render> you should use <p:commandButton update>. Specifying client IDs which are already covered by #form is unnecessary, so just #form is sufficient. Also the ajax="true" attribute is unnecessary as that's the default already.
So just this should do:
<p:commandButton value="Select tags" update="#form" />
Unrelated to the concrete problem, you're doing the business job inside a getter method. This is a bad idea. Do it in the button's action method instead. You also seem to be using a session scoped bean for view scoped data. This is a bad idea. Put the bean in the view scope instead.

Resources