Pass a parameter to dropzone save method using JSF - jsf

I have written the question about how to use dropzone.js with JSF (Use dropzone with JSF) and it was correctly answered by BalusC.
However I want to pass a parameter to the save() method and I am not able to do it. I have the dropzone component in a page similar to this:
http://localhost:8080/application/image-album.xhtml?albumId=1
And in that page I have:
<h:form id="uploadForm" enctype="multipart/form-data" styleClass="dropzone">
<div class="fallback">
<h:inputFile id="file" value="#{uploadImageController.part}"/>
<h:commandButton id="submit" value="submit" />
</div>
</h:form>
And in the UploadImageController I have:
#PostConstruct
public void init() {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
albumId = Long.valueOf(externalContext.getRequestParameterMap().get("albumId"));
}
So theoretically I could use the albumId in the save() method. However the init() method is being called three times, the first time with the value 1 and the other two with the value null so it fails by NullPointerException.
Any workaround to this?

GET request parameters can be set as bean property using <f:viewParam>.
<f:metadata>
<f:viewParam name="albumId" value="#{bean.albumId}" />
</f:metadata>
If you're using a #ViewScoped bean, then this will be remembered across all JSF POST form submits (postbacks) on the same view. If you're however using a #RequestScoped bean, then bean properties can be retained across postbacks using <h:inputHidden>.
<h:form ...>
<h:inputHidden value="#{bean.albumId}" />
...
</h:form>
This only doesn't work properly when there's a conversion/validation failure on the form. If you're using conversion/validation on the very same form, then better use plain HTML <input type="hidden">.
<h:form ...>
<input type="hidden" name="albumId" value="#{bean.albumId}" />
...
</h:form>
The <f:viewParam> will take care that the bean property is properly set. There's no need to manually fiddle with getRequestParameterMap() the old fashioned JSF 1.x way.
See also:
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
How to retain f:viewParam values after postback with validation failed
How to choose the right bean scope?

Related

Passing "get" parameters doesn't work, parameter not visible in the link

I'm a beginner to JSF and I want to code a little searchbar on my future website.
I made two pages : index.xhtml and search.xhtml, and I try to pass get parameters from index.xhtml to search.xhtml, so I made this little formular :
<!-- index.xhtml -->
<h:form id="Form_search">
<h:inputText class="search_bar_text" binding="#{se}"></h:inputText>
<h:button class="search_bar_button" outcome="search">
<f:param name="search" value="#{se.value}" />
</h:button>
</h:form>
To summarize, I want to send the content of an inputText to search.xhtml
But there's a problem : when I click on the submit button, no parameters are passed, so instead of having /search.xhtml?search=foobar I only have /search.xhtml.
I also tried this, but this doesn't work either :
<!-- index.xhtml -->
<h:form id="Form_search">
<h:inputText class="search_bar_text" binding="#{se}"></h:inputText>
<h:button class="search_bar_button" outcome="search.xhtml?search=#{se.value}">
</h:button>
</h:form>
Can someone explain to me the reason of this problem and how I can fix it?
The <f:param value> and <h:button outcome> are evaluated during rendering the HTML output, not during "submitting" of the form as you seem to expect. Do note that there's actually no means of a form submit here. If you're capable of reading HTML code, you should see it in the JSF-generated HTML output which you can see via rightclick, View Source in webbrowser.
Fix it to be a true GET form. You don't need a <h:form>, <h:inputText>, nor <h:button> here at all. You don't want a POST form. You don't seem to want to bind the input to a bean property. You don't want a plain navigation button.
<form id="form_search" action="search.xhtml">
<input name="search" class="search_bar_text" />
<input type="submit" class="search_bar_button" />
</form>
Yes, you can just use plain HTML in JSF.
If you really, really need to use JSF components for this purpose for some reason, then you could also use this POST-redirect-GET-with-view-params trick.
First add this to both index.xhtml and search.xhtml:
<f:metadata>
<f:viewParam name="search" value="#{bean.search}" />
</f:metadata>
Then use this form:
<h:form id="form_search">
<h:inputText value="#{bean.search}" styleClass="search_bar_text" />
<h:commandButton styleClass="search_bar_button" action="search?faces-redirect=true&includeViewParams=true" />
</h:form>
This would perhaps make sense if you intend to use JSF validation on it. But even then, this doesn't prevent endusers from manually opening the URL with invalid params. You'd then better add validation to <f:viewParam> itself on search.xhtml.
See also:
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for? (scroll to bottom of answer)
How do I process GET query string URL parameters in backing bean on page load?

lose view page parameter

i have page my.xhtml:
<f:metadata>
<f:viewParam name="id"/>
</f:metadata>
...
<h:form>
Current id is: "#{id}"
<h:commandButton action="#{bean.doSomething}" value="Do some logic..">
<f:param name="id" value="#{id}"/>
</h:commandButton>
</h:form>
and Bean.java:
#ManagedBean
#ViewScoped
public class Bean {
....
public void doSomething(){
//do some logick, don't use id parameter
}
}
When I get to page first time with id=10 I can see on page Current id is: "10"..
When I click on button page is reload and I can see on page Current id is: "10". again.
But when I click on button third time I can see on page Current id is: ""., i lose id parameter and I don't understand why?
I know I can do this with save parameter value in bean
(by add to f:viewParam:
<f:metadata>
<f:viewParam name="id" value="#{bean.value}/>
</f:metadata>
), but can I do this without save parameter value in bean?
h:button works with f:param but h:commandButton does not. In this case, your best is to bind the view parameter to a bean property as you explain the last. The #ViewScoped bean will retain its state as long as you call void action methods.
You could also pass it as a parameter to the action method (there are several ways to do that), but this doesn't make sense for a method which has nothing to do with that value.
See also:
Passing parameters to action methods in JSF
Communication in JSF

Reset inputText after Button Click with JSF

Is it possible to reset the value of an inputText after clicking on the commandButton in JSF? The inputText UIElement provides the method ResetValue so I tried something like this:
<h:inputText id="measurementadd" binding="#{inputTextMeasurement}">
<f:validateRegex pattern="[a-zA-Z ]*"/>
<f:ajax event="keyup" render="measurementaddmessage submit" execute="#this"/>
<h:inputText>
<p:commandButton id="submit" action="#{Bean.addMeasurement(inputTextMeasurement.value)}"
value="submit" update="dataTable measurementadd measurementaddmessage"
disabled="#{empty inputTextMeasurement.value or facesContext.validationFailed }" >
<f:ajax event="mouseup" execute="#{inputTextMeasurement.resetValue()}" />
</p:commandButton>
<h:messages for="measurementadd" id="measurementaddmessage"/>
But after clicking the Button the inputTextMeasurement doesn't reset it's value.
Does someone know a good workaround for this?
I'm searching for a solution without JS and JAVA, so a realization in JSF would be very cool.
Your mistake is here in the execute attribute:
<f:ajax event="mouseup" execute="#{inputTextMeasurement.resetValue()}" />
The execute attribute should represent a space separated collection of client IDs to include in the process/decode of the ajax request. However, you specified a listener method there.
You need the listener attribute instead:
<f:ajax listener="#{inputTextMeasurement.resetValue()}" />
(and I omitted event as it defaults here to click which is already the right one)
Interesting detail is that the other <f:ajax> in the same piece of code used the exeucte attribute the right way.
Unrelated to the concrete problem, have you looked at <p:resetInput>? This saves an ajax listener method in the bean. Replace the whole <f:ajax> with
<p:resetInput target="measurementadd" />
Why dont we just use
<input type="Reset"/>
This one is works fine for me! ???
I have solved my problem as below
<p:commandButton id="submit" action="#{Bean.addMeasurement(inputTextMeasurement)}">
Sending back bean UIInput component. Get and Reset value in back bean.
public void addMeasurement(UIInput
String msr = (String) inputTextMeasurement.getValue()
inputTextMeasurement.resetValue();
}

Does f:viewParam only pass query string in url when first page uses the same managed bean as the second page?

Let's use a search page and a results page for example. If i have a ViewScoped bean that handles my search page and my results page, i'm able to pass parameters through the url using something like this:
search.xhtml
<p:commandButton value="Search" type="submit" action="#{searchBacker.search}" >
backing bean
#ManagedBean(name="search")
#ViewScoped
public class searchBacker extends AbstractBacking {
private String firstName = null;
private String lastName = null;
private String results = null;
public String search() {
return "results?faces-redirect=true&includeViewParams=true";
}
public void getResults() {
MyDAO dao = new MyDAO();
results = dao.getResults(firstName, lastName);
}
//getters and setters
}
results.xhtml
<f:metadata>
<f:event type="preRenderView" listener="#{searchBacker.getResults}" />
<f:viewParam name="firstName" value="#{searchBacker.firstName}"/>
<f:viewParam name="lastName" value="#{searchBacker.lastName}"/>
</f:metadata>
Now lets say i have two managed beans - one for the search page and one for the results page.
Will the query string still be built in the url with 2 different managed beans or does this only work when using the same managed bean for both pages?
UPDATE
I have the same <f:viewParam> on my search.xhtml and results.xhtml page, but the only difference is that my f:viewParam value points to a different backer in my results.xhtml than in my search.xhtml. When i do this, no params get passed through the url. When I point my f:viewParam value in results.xhtml to the same backer that i use in search.xhtml, the param gets passed through the url just fine, but the value doesn't exist in the results backer where i need it. If i have duplicate f:viewParams in my results.xhtml page - one with the search backer and one with the results backer, everything works fine. Is having 2 of the same f:viewParams with both managed beans the correct way to do this?
Examples:
results.xhtml - params get passed through url, but are not available in my resultsBacker
<f:metadata>
<f:viewParam name="firstName" value="#{searchBacker.firstName}"/>
<f:viewParam name="lastName" value="#{searchBacker.lastName}"/>
</f:metadata>
results.xhtml - no params get passed through url
<f:metadata>
<f:viewParam name="firstName" value="#{resultsBacker.firstName}"/>
<f:viewParam name="lastName" value="#{resultsBacker.lastName}"/>
</f:metadata>
results.xhtml - params get passed through url and are available in my resultsBacker, but seems clunky. Is this the correct way to do this or am i still missing something?
<f:metadata>
<f:viewParam name="firstName" value="#{searchBacker.firstName}"/>
<f:viewParam name="firstName" value="#{resultsBacker.firstName}"/>
<f:viewParam name="lastName" value="#{searchBacker.lastName}"/>
<f:viewParam name="lastName" value="#{resultsBacker.lastName}"/>
</f:metadata>
I suggest you to implement two #ViewScoped managed beans, one for the search page and the other for the results page. You should also have two xhtml pages, each one related with a bean. Obviusly its page will have its own url (as it seems you're doing right now with the same bean).
You can make the second page's bean expect two parameters, firstName and lastName. After, in the preRenderView method, when parameters are already set into the second managed bean, query your DB with that values. So how to achieve the transition between the beans? An outcome should be enough.
<p:button outcome="results">
<f:param name="firstName" value="#{searchBean.firstName}">
<f:param name="lastName" value="#{searchBean.lastName}">
</p:button>
This makes JSF build an url with the params you need. After you can do exactly the same that you're doing right now, but using your second bean to get your params (I strongly suggest you not to use a getter method for the preRenderView method):
<f:metadata>
<f:event type="preRenderView" listener="#{resultBacker.initialize}" />
<f:viewParam name="firstName" value="#{resultBacker.firstName}"/>
<f:viewParam name="lastName" value="#{resultBacker.lastName}"/>
</f:metadata>
includeViewParams works only if both the source and target view have the desired view parameters declared as <f:viewParam>.
So, in your parituclar case, you need to put the <f:viewParam>s with very same name in both the search.xhtml and results.xhtml. Under the covers, the includeViewParams namely only grabs the view params of the current view and then only applies the ones which are also declared in the target view.
See also:
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
Unrelated to the concrete problem, you seem to effectively want a GET form. In that case, there is a better way for that than performing a POST-Redirect-GET with parameters. Look at the bottom of the above "See also" link.

Retaining GET request query string parameters on JSF form submit

I have 3 pages:
main.xhtml
agreement.xhtml
generated.xhtml
The agreement.xhtml needs two parameters to load correctly: serviceId and site. So, a normal url looks like this: /app/agreement.xhtml?site=US&serviceId=AABBCC.
I have this button on agreement.xhtml
<h:form>
<h:commandButton value="Generate License File" action="#{agreement.generateMethod}" />
</h:form>
The #RequestScoped bean #{agreement} has this method:
public String generateMethod(){
.......
return "generated";
}
I need that, on click, the generateMethod() method is executed, and after it's done, the user is redirected to the generated.xhtml page. What's happening is that, on click, the page browser sends the user to /app/agreement.xhtml and, since it's not sending the parameters site and serviceId, it crashes.
I tried making the generateMethod() return a "generated?faces-redirect=true", but still nothing. Any ideas?
Your concrete problem is caused because a JSF <h:form> submits by default to the current request URL without any query string. Look closer at the generated HTML output, you'll see
<form action="/app/agreement.xhtml" ...>
You'd thus explicitly need to include those request parameters yourself. There are several ways to solve this. If you weren't sending a redirect, then you could just add them as hidden inputs to the JSF form.
<h:form>
<input type="hidden" name="site" value="#{param.site}" />
<input type="hidden" name="serviceId" value="#{param.serviceId}" />
...
</h:form>
Only, those parameters won't reappear in URL in browser's address bar. This isn't a problem if you're only using using ajax on the same page. The <h:inputHidden> is by the way not suitable as it will confusingly lose its value when a conversion or validation error occurs on the form.
In order to get them to reappear in URL, you need <f:viewParam> and includeViewParams. In order to get includeViewParams to work, you need to declare the following in both the source page agreement.xhtml ...
<f:metadata>
<f:viewParam name="site" value="#{agreement.site}" />
<f:viewParam name="serviceId" value="#{agreement.serviceId}" />
</f:metadata>
... and the target page generated.xhtml:
<f:metadata>
<f:viewParam name="site" value="#{generated.site}" />
<f:viewParam name="serviceId" value="#{generated.serviceId}" />
</f:metadata>
Now you can send a redirect including the view parameters as follows:
public String generateMethod() {
// ...
return "generated?faces-redirect=true&includeViewParams=true";
}
Do note that the bean should be #ViewScoped in order to keep those parameters alive between opening the page with the form and submitting the form, also on validation errors. Otherwise, when sticking to a #RequestScoped bean, you should be retaining them as <f:param> in the command components:
<h:commandButton ...>
<f:param name="site" value="#{generated.site}" />
<f:param name="serviceId" value="#{generated.serviceId}" />
</h:commandButton>
There's no way to set them for <f:ajax> inside input components, your bean should then really be #ViewScoped.
Alternatively, if you happen to use JSF utility library OmniFaces already, then you could also just replace the <h:form> by <o:form> as follows (see also showcase example):
<o:form>
That's basically all. This will generate a <form action> with current query string included.
<form action="/app/agreement.xhtml?site=US&serviceId=AABBCC" ...>
Those request parameters are then just available in the request parameter map of the form submit. You don't need additional metadata/viewparams and you also don't need to send a redirect and your bean can be kept #RequestScoped, if necessary.
public String generateMethod() {
// ...
return "generated";
}
See also:
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
How to navigate in JSF? How to make URL reflect current page (and not previous one)
Your generateMethod would have to return
return "generated?site=US&serviceId=AABBCC&faces-redirect=true";
You can even replace & with & but escape it in your xhtml.
In your generated.xhtml you can catch the parameters that are being passed with <f:viewParam> like this
<f:metadata>
<f:viewParam name="site" value="#{yourBean.site}"/><!--Make sure you have a setter-->
<f:viewParam name="serviceId" value="#{yourBean.serviceId}"/><!--Make sure you have a setter-
</f:metadata>
<h:head>

Resources