JSF: Reload page after data change - jsf

Using a DataModel<MyObject>, I fill a data table according to this response
Now at the end of each line I have a delete button which calls a certain method of my bean. The data gets cleanly deleted. But as the data has been changed after the deletion, I'd like to reload the page in order to reflect the changes.
My attempt was to add a navigation rule in faces-config.xml:
overview
/overview.jsp
deletedsubscription
/overview.jsp
If I have <redirect /> or not, either way it's not reloading or doing anything else at all. The data is deleted, therefore the bean's method is actually called.
My button looks like this:
<h:dataTable border="1" value="#{overviewBean.overviewModel }" var="item" first="0">
<h:column id="column13">
<f:facet name="header">
<h:outputText value="#{messages.overviewDeleteItem }"></h:outputText>
</f:facet>
<h:commandButton action="#{overviewBean.deleteItem}" value="X"/>
</h:column>
</h:dataTable>
Setting the attribute type="submit" actually solves the problem. The pages gets reloaded.
My question now: is the submit really required? Doesn't JSF (Apache MyFaces) have some mechanism of using AJAX to eliminate the line just deleted?
Thanks for trying to help a JSF-newbie.

Just remove the item from the backing list of the datamodel. The changes will be reflected in the model.
Basically:
private List<MyObject> overviewList;
private DataModel overviewModel;
public OverviewBean() {
overviewList = overviewDAO.list();
overviewModel = new ListDataModel(overviewList);
}
public void deleteItem() {
MyObject myObject = (MyObject) overviewModel.getRowData();
overviewDAO.delete(myObject);
overviewList.remove(myObject); // See?
}
A redirect thereafter is not necessary. If the action method returns void (or null), it will go to the same page anyway.
Ajaxical capabilities have been introduced in JSF 2.0, but if I am not wrong, you're still on JSF 1.x. Your best bet is then adopting a 3rd party component library like Ajax4jsf (currently part of RichFaces), for the case that you consider this necessary.

Related

create links dynamically

I have a user-defined text, such as
#SessionScoped
public class MyBean {
private String text = "Life’s but a walking shadow, a poor player
that struts and frets his hour upon the stage and
then is heard no more.";
public String getText() {
return text;
}
}
Of course the text is not static, but will be loaded from somewhere else. I want the text to be displayed one the page, as in
<h:form id="myForm">
<h:outputText value="#{myBean.text}" />
</h:form>
Now have a logic in the bean which marks certain words, e.g. every noun, in the text. These words should be rendered as links, as if they were commandLinks.
That is, the form should be submitted and I should be able to find out which link was clicked.
Something similar was already asked here, here and here, but I am not sure if the solutions given there suit my case.
My best guess right now is to split the text at the marked words into a list of snippets in the bean, e.g.
List<TextSnippet> textSnippets;
class TextSnippet {
private String precedingText;
private String markedWord;
...
}
such that each text snippet ends with a marked word. Then I would be able to iterate over the list in the xhtml, e.g.
<h:form id="myForm">
<ui:repeat var="snippet" value="#{myBean.textSnippets}">
<h:outputText value="#{snippet.precedingText}" />
<h:commandLink action="#{myBean.clickedOn(snippet.markedWord)}">
<h:outputText value="#{snippet.markedWord}">
</h:commandLink>
</ui:repeat>
</h:form>
However, I feel that this tightly couples the bean (logic of splitting) to the view. Any better ideas?
What I would personally do is try to keep the jsf tree small and implement something like the lines below that I think is more performant (disclamer: no full code coming )
Prepare the text serverside in a bean as This is a <div class="linkedWord">specific</div> word that needs a link and so is <div="linkedWord">this</div>
Output this in plain html via an <h:outputText value="#{myBean.text}"> (for escaping!)
Add a jquery dynamic eventhandler on the class="linkedWord" (so it works for each link) and call a javascript function
In that javascript function read the content of the div (or maybe add the text as a data- attribute aas well (like <div class="linkedWord" data-word="specific">specific</div>
and call a <h:commandScript> (JSF 2.3 and up) or a o:commandScript for previous JSF versions (or the `p:remoteCommand) and pass the content of the div (or the value of the attribute) as a parameter to a serverside method.
Keep in mind that there is no explicit reason to do everything in a 'JSF' way. Using client-side features and some small integration with JSF is very valid usage. People not doing this often 'blame' JSF but they themselves are effectively the cause of the less optimal behaviour)
See also:
Event binding on dynamically created elements?
http://omnifaces.org/docs/javadoc/2.6/org/omnifaces/component/script/CommandScript.html
https://javaserverfaces.github.io/docs/2.3/vdldocs/facelets/h/commandScript.html
You seem to go the right way, but I think I can suggest you some improvements. Don't know your exact requirements, but your current structure limits the marked word (which I guess acts as a mere link) to be at the end of the paragraph. What would happen if you have text after it? What about having two marked words? This class might suit better:
class TextSnippet {
private String text;
private String linkUrl;
...
}
You'll need to build the List<TextSnippet> the way you do, but evaluate the links before, so ui:repeat can access them.
Then, iterate over it. Instead of performing a POST to evaluate where to go, you've got it already, so you can use a h:link if you want to point to somewhere in your application or h:outputLink if it's outside it:
<ui:repeat var="snippet" value="#{myBean.textSnippets}">
<h:outputText value="#{snippet.text}" rendered="#{empty snippet.linkUrl}" />
<h:link outcome="#{snippet.linkUrl}" rendered="#{not empty snippet.linkUrl}">
<h:outputText value="#{snippet.text}">
</h:link>
</ui:repeat>

p:dataTable how prevent f:viewParam being invoked on 1st rowEdit then “tick save” using JSF at XHTML level (not in Java in backing bean)

EDIT: 2017-04-28 The exact same problem (different circumstances/application) is described here: Process f:viewParam only on page load
Primefaces 6.1.RC2
JSF Mojarra 2.3.0
I already have a Java backing-bean based workaround (explained below) for the problem the following behaviour of p:dataTable causes, but I am not very happy with that workaround, and I would like to understand the behavior of p:dataTable row editing better and if possible I would like to find a purely XHTML-level solution to my problem. (BTW I am otherwise very experienced with p:dataTable, which I have used for some very complex applications for some years.)
It is not about an error or bug in p:dataTable, but the way it behaves during row editing causes me a problem in one situation.
The following code examples are completely simplified and adapted for this forum.
I have an entity Element, which has a relationship List<Link> getLinks(), where Link is also an entity.
Element has an editor edit.xhtml.
The aim is to have an composite component links_editor.xhtml that can be embedded in the edit.xhtml.
There is a CDI-compliant #ViewScoped #Named backing bean Manager.
The edit.xhtml relies on an f:viewParam to load an Element for editing:
<f:view>
<f:metadata>
<f:viewParam name="id" value="#{manager.id}"/>
</f:metadata>
</f:view>
Where in the backing bean Manager:
public void setId(Long id) {
if (id != null) {
//load an Element from database for editing by id
And in the links_editor.xhtml:
<cc:implementation>
<div id="#{cc.clientId}">
<p:growl id="testgrowl"/>
<p:dataTable
id="links_table"
editable="true"
var="link"
value="#{cc.attrs.element.links}"
>
<p:ajax
event="rowEdit"
listener="#{cc.attrs.manager.onLinkRowEdit}"
update="#{cc.clientId}:testgrowl"
/>
<p:column headerText="Link title">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{link.name}" />
</f:facet>
<f:facet name="input">
<p:inputText id="name" value="#{link.name}"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Link URL">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{link.urlAsString}" />
</f:facet>
<f:facet name="input">
<p:inputText id="url" value="#{link.urlAsString}"/>
<p:message
for="url"
display="icon"
/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column>
<p:rowEditor />
</p:column>
</p:dataTable>
The row edit listener:
public void onLinkRowEdit(RowEditEvent event) {
Link link = (Link) event.getObject();
try {
checkLink(link); //throws if URL string malformed
JsfUtil.addInfoMessage("DEBUG: Link: "+link);
} catch (LocalUpdateException ex) {
JsfUtil.addErrorMessage(ex.getMessage());
}
}
(where JsfUtil obviously just leverages FacesContext.getCurrentInstance().addMessage(...))
The issue/concern:
If I edit a Link row in the p:dataTable a first time and then use the "tick save" the onLinkRowEdit listener is invoked, but the diagnostics show that the value appear not to have changed. The reason is that this f:viewParam is invoked:
<f:viewParam name="id" value="#{manager.id}"/>
This (via routes not shown in detail) loads the Element entity again from database via setId(Long id), so that in the composite component edit_links.xthml this essentially resets #{cc.attrs.element.links}, so any changes are discarded.
The interesting thing is that if (without reloading the entire #ViewScoped page) one edits the same p:dataTable row a second time that f:viewParam is NOT invoked, and thereafter it works as desired.
A workaround (rather hacky) is to "block" any attempt to reload the Element by id within the view scope backing bean Manager:
public void setId(Long id) {
//HACK/WORKAROUND: prevent reload of Element by id
if (Objects.equals(id, this.id)) {
return;
}
if (id != null) {
//load an Element from database for editing by id
To be clear, I am aware of the usual strategies for using #PostConstruct and/or lazy database fetching in getters of frequently accessed info under JSF in backing beans. And I don't want to abandon here the f:viewParam approach entirely (and it works well for other situations the same Manager bean is also used for).
My interest is specifically about Primefaces p:dataTable:
Q1: Why does p:dataTable need to call the f:viewParam during the 1st row edit then "tick save", when the row information (in this cases element.links) is clearly already available ?
Q2: Why does p:dataTable NOT need to call the f:viewParam during the 2nd row edit then "tick save" ?
Q3: Is there a JSF XHTML-based way of preventing p:dataTable from calling the f:viewParam at all during a rowEdit then "tick save" (including the 1st go) ?
UPDATE: 2017-04-21: There is now a mini test web app for NetBeans 8.2 demonstrating the problem at:
https://github.com/webelcomau/Webel_PrimeFaces_test_p50445_dataTable_fviewParam
Please just download the master ZIP-archive, unzip it, and open it in NetBeans IDE 8.2. You don't need to Git-clone the project. Make sure you have Glassfish-4.1.1 set as the server for the project.
Both the README there and the web app test page itself give precise steps for reproducing the problem (or the behavior that concerns me).
I have invested some effort in analysing this because I use p:dataTable "embedded" in edit forms together with f:viewParam a lot, and I want to understand this matter better, even if it is not an actual problem with p:dataTable.

Disable and empty an input field after an AJAX call using JSF and Richfaces

I am using richfaces 4.2.0.Final and have the following situation: within a rich:dataTable, in which each row describes an article in a shopping cart, I have an input field
in which the user can input the quantity she wants to order. As soon as the user focuses on this input field, I have to perform some controls on the server (using Ajax) and if
the controls fail, I must empty the field and disable it.
My solution:
<rich:dataTable var="article" value="#{cart.articles} >
...
<rich:column>
<h:panelGroup id="orderQty">
<h:inputText id="qtyInput" value="#{article.qty}" disabled="#{article.controlsFailed}">
<a4j:ajax event="focus" bypassUpdates="true"
listener="#{requestBean.doAjaxControls(article)}"
execute="#this" render="qtyInput " />
</h:inputText>
</h:panelGroup>
#RequestScoped
#Named
public class RequestBean{
public void doAjaxControls(Article article){
boolean everyThingOK = doControls();//....
if (!everyThingOK){
article.setControlsFailed(true);
article.setQty(null);
} else {
article.setControlsFailed(false);
}
}
}
Before coming to this solution I tried several other combinations of execute/render, without succeeding in what I need (for example, I tried to use execute="#none" as I don't want
the value of qty to be updated on the server when I perform the ajax call, but this won't work).
My problem is I know this solution is not perfect: when I focus on a position for which the control will fail, and I am faster to type in a quantity than the server performing the controls, the field will be disabled and the server value for article#qty still set to null, but I will see the value I typed in until the next rendering of qtyInput will happen.
More strangely, if I execute this code on JBoss EAP 6.0.0.GA (AS 7.1.2.Final-redhat-1, which includes the module jboss-jsf-api_2.1_spec-2.0.2.Final-redhat-1),
every quantity typed in before doAjaxControls() is done will be cleared: this strange behaviour is fortunately not present with JBoss EAP 6.0.1.GA (AS 7.1.3.Final-redhat-4, jboss-jsf-api_2.1_spec-2.0.7.Final-redhat-1).
Do you know if/how could I improve my solution?
Thanks in advance for helping!

Opening a new window if condition true in managed bean

I want to implement a situation where the user enter a URL, and if a specified condition is true in my managed bean this URL will be opened in a new web page.
I found this possibility:
The “h:link” tag is useful to generate a link which requires to interact with the JSF “outcome” , but lack of “action” support make it hard to generate a dynamic outcome.
The “h:commandLink” tag is suck, the generated JavaScript is really scary! Not recommend to use this tag, unless you have a solid reason to support. But it supports the “action” attribute, which is what “h:link” lack of.
The “h:outputLink” is useful to generate a link which does not require to interact with the JSF program itself.
At last, it will be perfect if the “action” attribute is added into the “h:link“.
But I didn't find a way to launch the open web page from my managed bean after the condition is verified.
I'm using JSF2.0, Facelets and PrimeFaces 3.4.
To open the target in a new window using one of those link components, you need to specify target="_blank" attribute, but this will already open the target in a new window at the moment you click the link and does thus not depend on the response. You basically need to open the target in a new window at the moment the response has been arrived. The only way is returning a JavaScript window.open() call to the response so that it get executed in the webbrowser.
In standard JSF, you could just render JavaScript's window.open() conditionally.
<h:form>
<h:inputText value="#{bean.url}" />
<h:commandButton value="submit" action="#{bean.submit}">
<f:ajax execute="#form" render="#form" />
</h:commandButton>
<h:outputScript rendered="#{bean.valid}">window.open('#{bean.url}')</h:outputScript>
</h:form>
with
private String url;
private boolean valid;
public void submit() {
valid = validate(url);
}
// ...
In PrimeFaces, you could use RequestContext#execute() to specify JavaScript code which needs to be executed on complete of the response.
<h:form>
<p:inputText value="#{bean.url}" />
<p:commandButton value="submit" action="#{bean.submit}" />
</h:form>
with
private String url;
public void submit() {
if (validate(url)) {
RequestContext.getCurrentInstance().execute("window.open('" + url + "')");
}
}
// ...
Unrelated to the concrete problem: the ranty statements which you cited there are seemingly written by someone who know nothing about HTTP/HTML basics (limitations of GET vs POST and so on). Please take them with a good grain of salt.

JSF validation for client side injected elements

I know there is a property in asp.net (probably this EnableEventValidation of "<%# Page%> tag) .Which, once caused problem when i try to add select items to a component using javascript ,I want to know how jsf handling this. That is,
if i send a h:select* like below and client add a new item "option3 " to item list, is jsf detect this automaticly before update model values .
<h:selectOneMenu id="type"
value="#{foo.value}"
required="true"
requiredMessage="Type is required"
style="width:100px">
<f:selectItem value="option1}"/>
<f:selectItem value="option2}"/>
</h:selectOneMenu>
I think what you need to understand regarding JSF is that the client/server parts of the components are tightly coupled together. You are probably better off thinking of them strictly as one entity, and forget about fiddling with one side only, reverting to custom Javascript when that is the only solution left.
The other way to think of it is that the server side renders the client side, not vice versa! So whenever you need to update a component the update must be done on the server side first, which will propagate to the client side (the browser).
In your example the proper way to add and element to the select* items is to store the selectable items in a data structure within a bean (probably #ViewScoped), and then do a partial update via AJAX for the select* component or its container component, when the server side gets the chance to become aware of the changes and can update the client side properly as well.
Sure, you can hack your way through Javascript only, but then why use JSF? The whole point of JSF is to avoid the need for hacks like this.
Remember, JSF is not JSP, which is basically a println macro for html output. JSF stores the page components' representation on the server side, mirroring the browser's representation.
Check the Primefaces showcase for examples on how to do partial updates. More specifically this is the example you could be looking for. This is available in standard JSF2, for JSF 1.2 you must use a component library to get AJAX support.
You should not add the new option by JavaScript, but you should add the new option by JSF. JSF needs to know about the new option somehow in order to allow the submitted value. The new option really needs to be served by <f:selectItem(s)>. Otherwise you will face Validation error: Value not valid all the time when submitting the option value which is added by JS. This is after all just a safeguard of JSF to prevent clients from manipulating the request and submitting values which they are not supposed to submit.
The following kickoff example should work:
<h:form>
<h:selectOneMenu id="menu" value="#{bean.item}">
<f:selectItems value="#{bean.items}" />
</h:selectOneMenu>
<h:inputText id="newItem" value="#{bean.newItem}" />
<h:commandButton value="add" action="#{bean.addNewItem}">
<f:ajax execute="#this newItem" render="menu" />
</h:commandButton>
<h:commandButton value="submit" action="#{bean.submit}" />
</h:form>
with a #ViewScoped managed bean something like follows:
private String item;
private List<String> items = Arrays.asList("option1", "option2");
private String newItem;
public void addNewItem() {
items.add(newItem);
}
// ...

Resources