Execute JS function with value from #ManagedBean - jsf

I have a backend restservice call, returning a value, with which I have to execute a JS function (for simplicity, I took "alert" here, in the frontend. This has to be implemented in JSF, and I'm having a hard time.
And, this is the catch, for performance reasons, I want the backend rest-callto be executed on click.
Here is (amongst many other things), what I have tried:
<p:commandLink action="#{viewingSessionBean.prepareViewingSession(document)}" oncomplete="alert('#{viewingSessionBean.name(document)}')">
<p:graphicImage value="documentViewerPopup.png"/>
</p:commandLink>
Here the bean (shortended to make the point clearer):
#ManagedBean
#ViewScoped
public class ViewingSessionBean implements Serializable {
private String name;
public String prepareViewingSession(Document document) {
name = restClient.call()
hashMap.put(document.getBlobId(), name);
return null; // don't navigate away...
}
public String name(Document document) {
return hashMap.get(document.getBlobId()); // return null if nothing is cached for the document yet there
}
}
I'd like to do something like this (pseudo code... don't have h:commandScript..., too old JSF, no way to upgrade)
<h:commandScript action="alert('#{viewingSessionBean.prepareViewingSession(document)}') />

That's something a bit tricky to accomplish, but stil doable.
One thing you must have in mind first: The JavaScript code you write in a .xhtml is rendered in a 'static' way. But what means 'static'? It means that if you reference a bean variable inside of your JavaScript code, and then update this variable value inside your bean, your printed JavaScript code will not be able to see these changes you just made. In this case you must first update your JavaScript code (using ajax) to get the changes in your variable and only then execute it.
Let's start with your bean:
#ManagedBean
#ViewScoped
public class ViewingSessionBean implements Serializable {
private String variable;
public String getVariable() {
return this.variable;
}
public void updateVariableValue(Document document) {
variable = restClient.call();
}
}
Now, the .xhtml code:
<h:form id="form">
<p:commandLink id="firstLink"
actionListener="#{viewSessionBean.updateVariableValue(document)}"
update=":form:secondLink"
oncomplete="$('#form\\:secondLink').click()"/>
<p:commandLink id="secondLink" onclick="alert('#{viewSessionBean.variable}')" style="display: none;"/>
</h:form>
Note a few things:
First: It was used two commandLinks, and not only one, why? Because at the time of the oncomplete call of the first Link the bean variable is already up-to-date, but your html code is not. So in order to have the updated value of the bean variable we do the following things:
Call the actionListener to update the variable value on the bean;
Make an ajax update on the second Link to get the updated value from the bean;
Call the oncomplete method and call a click to the second Link (now updated with the correct values);
Second: To call the click on the second Link we must escape the two dots on the jQuery call.
Third: The second Link is set with the display: none style to make it invisible in the screen.
Now just some thoughts about it: JSF works pretty well alongside JavaScript, but sometimes we have to make some clumsy tricks like this one to accomplish an "easy" task. I'm not saying that JSF is bad, but I think we could have a more 'out-of-box' approach to these kind of things. Just my opinion though.

Related

Load bundle string (in right language) when value depends on bean condition

I have a Problem with jsf and multiple languages. So my strings are in WEB_INF/classes/texte_<lang>.properties files. And are accessed for example like that
<h:outputLabel value="#{messages.err_text}"/>
which works fine.
The problem is, i have <h:outputLabel... element where i want to show an error message depending on the error. I would like something that works like this:
<h:outputLabel value="#{someBean.errMsg}/>
With a Bean like that
#ManagedBean()
#SessionScoped
public class SomeBean{
public String getErrMsg(){
if(something){
return "#{messages.err_text}"
}else if(somethingElse){
return "#{messages.err_text2}"
}else{
return "#{messages.err_text3}"
}
}
}
Just to be clear it doesn't work that way. I'm looking for a similar solution (or any solution) that works.
Thanks for reading.
Don't do it that way. The model shouldn't be aware of the view. Localization also doesn't strictly belong in the model. The model should instead prepare some state which the view has to be aware of.
One way would be:
public String getErrMsg(){
if (something) {
return "err_text";
} else if (somethingElse) {
return "err_text2";
} else {
return "err_text3";
}
}
<h:outputLabel value="#{messages[someBean.errMsg]}" />
Other way would be returning an enum as demonstrated in the following related questions: Localizing enum values in resource bundle and How to use enum values in f:selectItem(s).
The reason why what you have now is not working, is because the value attribute of the outputText is evaluated as a plain String, and not as an EL expression.
Going by what you are working with now, the best way to proceed is to inject the resource bundle directly into your bean:
#ManagedProperty("#{messages}")
ResourceBundle messages;
And then,
public String getErrMsg(){
if(something){
messages.getString("err_text");
}
}
In case you're not aware, traditionally, error messages are presented using the h:message component.
On an unrelated note to your original question, you should also know that it's not generally advisable to have processing logic buried in your getter. For one thing, the getter is called multiple times during the rendering of your page. Also for this to work properly, you should be able to guarantee that the value something will stay consistent across the entire lifecycle of a single JSF request

How do bean managed transactions work?

I am new both to EJB and Bean Managed Transactions. After scrapping the Internet, I found that I could write a EJ session Bean which does transactions the "bean-managed way", like this:
#TransactionManagement(value=TransactionManagementType.BEAN)
#Stateless
public class OperationBean {
#Resource
private UserTransaction userTransaction;
public void operation() {
try{
userTransaction.begin();
Op1();
Op2();
Op3();
userTransaction.commit();
} catch(Exception e){
userTransaction.rollback();
}
}
}
However, I do not understand what happens if an exception is thrown by Op3(). How are Op1() and Op2() undone?
Another question is how do I bind this to JSF? I need to write a form in JSF that sends its data to the server and the OperationBean does 3 operations based on the received data. These operations do involve database operations(3 updates) and do not make sense individually.
Thanks!
When you call userTransaction.begin(), simply saying JTA begins transaction on database level.
Now all the data modifications you perform are done inside transaction.
If everything is OK, execution comes to userTransaction.commit() and database fixes transaction.
If something's going wrong, you call userTransaction.rollback() in catch block and database drops all the modifications you do after begin().
In two words it is difficult to explain how database transactions work, but basically database isolates all changes during transaction from other clients until commit() or rollback() is called and prevents external updates of data you are working with.
In JSF you can create #ManagedBean and inject your OperationBean into it with #EJB annotation.
You should get something like this
#ManagedBean
public class Operation {
#EJB
private OperationBean operationBean;
public void doOperation() {
operationBean.operation();
}
}
and in your view
<h:form>
<h:commandButton action="#{operation.doOperation}" value="Do Operation"/>
</h:form>
So you're doing it right. Assuming you really need bean managed transactions, not container managed.

ApplicationScoped Bean with postconstruct method

I have an application scoped bean to hold the information in my database. After its instantiation it should fetch the data, so I annotated the method with #PostConstruct. As soon as I request the jsf page where this bean is referenced the server log explodes! I think it somehow recurses and the only stacktrace I get is that a System Exception occurred during the repBean.acceptVisitor(Visitor); method. The server log then gets several GB big and I have to manually delete it in order to have free disk space. If I delete the #PostConstruct annotation there are no exceptions. After calling the update() method from another bean the repositoryContent variable is updated properly and contains the information. The only problem then is that my jsf page doesn't display the content for some strange reason.
#ManagedBean(eager=true)
#ApplicationScoped
public class IndexBean implements Serializable {
private ArrayList<ViewFolder> repositoryContent;
#EJB
RepositoryService repBean;
#PostConstruct
public void update() {
RepositoryVisitor Visitor = new RepositoryVisitor();
repBean.acceptVisitor(Visitor);
repositoryContent = Visitor.getList();
}
}
This is not normal behaviour.
One of the following lines
RepositoryVisitor Visitor = new RepositoryVisitor();
repBean.acceptVisitor(Visitor);
repositoryContent = Visitor.getList();
is indirectly evaluating the EL expression #{indexBean} which in turn causes the bean being constructed once again, because it is not been put in service yet. It would only be put in service (and thus available as a concrete #{indexBean}) when the #PostConstruct finishes. This all causes an infinite loop.
You might need to do some refactoring, or to pass the application scoped bean instance itself to the method call so that it can be used directly instead of being referenced by an EL expression.

Execute a bean's method before it may be used in the JSF page

A request scoped bean collects data, from all many other request beans & business logic. This bean is used through the EL expressions in the page but before this request scoped bean may be used in the page, it needs to build a directory using the collected data (This is done after all collection is over but before the bean properties may be used in page).
How can I execute the building of the directory in this bean after all collection but before it is used through the EL expressions in the page without using <f:event>? I need to build it only once.
#ManagedBean(name="namesDirectory")
#RequestScoped
public class NamesDirectory {
public void addForPersonNameRetrieval(Integer id) { // this is used to collect the data in bean
peopleNamesMap.put(id,null);
.......
}
public void buildDirectory(){ // used, when all collection is over, to build the diirectory
.......
}
public String getPersonName(Integer id) { // used in the JSF page through EL expressions
name = peopleNamesMap.get(id);
}
}
Here buildDirectory() needs to be executed at the end of all collection but before using getPersonName() in the JSF page
You have got several options. You could rebuild the directory after every insert or before every retrieval, however this may cause unnecessary rebuilds. You could rebuild the directory only when needed and called:
Add a flag requiresRebuild and default it to true.
Set it to true in addForPersonaNameRetrieval.
Set it to false in buildDirectory.
Call buildDirectory in getPersonName if a rebuild is necessary.

Input File component error messages

I'm facing a serious problem with ice:inputFile component.
When an error occurred while uploading process (like : invalid file name error, empty file name error, exceeding max size error), i use ice:message tag to show these error messages.
I use ice:panelPopup and display the ice:inputFile component inside it.
The problem is : when i toggle the uploading popup the error message still appears, i need any way to clear these messagses.
Please help me, any help is appreciated......................... :)
I'm not 100% sure, if I understood your question correctly, however I guess that the immediate keyword, applied on the action, which triggers the popup, will help you.
<ice:commandLink
action="#{this.popup}"
immediate="true">
<h:outputText value="foo" />
</ice:commandLink>
In regular JSF Life Cycle, action events are normally fired after the Process Validations phase. Additionally, values will be updated from the UI to the model.
The immediate property, which is available to basically every JSF component which can cause any kind of event, bypasses validation and, depending on the event type, also the Model Update phase.
alt text http://img43.imageshack.us/img43/3900/jsfimmediatecomponents.png
(Geary, Horstmann, 2008. Core JavaServer Faces - Second Edition. Prentice Hall)
You'll find more information on this topic in Suns JSF Tutorial: The immediate Attribute
Here are two things that have worked for me.
Bind your ice:inputFile component to a property on your backing bean and manually call the reset method on the property when you close the popup pane.
<ice:inputFile binding="#{Bean.uploadedFile}"/>
class BackingBean {
private UICommand uploadedFile;
public UICommand getUploadedFile() { return uploadedFile; }
public void setUploadedFile(UICommand uploadedFile) { this.uploadedFile = uploadedFile; }
public void onClose(ActionEvent event) {
((InputFile) uploadedFile).reset();
}
}
-OR-
Add an actionListener to your ice:inputFile component. This will stop the inputFile component from adding its own validation errors to the context. You can implement whatever validation you need in the actionListener method and display the validation errors using an ice:messages tag. I've found that this works better than relying on inputFile's validation because it gives you complete control over the error message text/style and because the error messages clear automatically when the popup pane goes away.
<ice:inputFile actionListener="#{Bean.onFileUpload}"/>
public class BackingBean {
public void onFileUpload(ActionEvent event) {
FileInfo info = ((InputFile) event.getSource()).getFileInfo();
switch (info.getStatus()) {
case FileInfo.SAVED :
// handle uploaded file
case FileInfo.SIZE_LIMIT_EXCEEDED :
// file too big error
...
}
}
}

Resources