I need to perform a web service (method) call just before load of a jsf page. The call will return a list of input fields that have to be displayed on my jsf page. The user can fill in the form and on click of next I need the values entered on the form to be sent back to another web service (method).
My approach was to have a request scoped bean for the jsf page(which consists of a blank form and a binding to the bean), and perform the web service call in the setter method of my form method and dynamically create UIInput fields
//call web service
//Loop
UIInput input = new HtmlInputText();
//set unique Id
form.getChildren().add(input);
//End Loop
It does create the Input fields, but if I perform browser back or refresh it keeps adding Input fields. So clearly my approach is wrong.
Also I found out that when I try to get the values for these dynamically created Input fields on Submit action like
List<UIComponent> dynamicFields = form.getChildren();
for(int i=0;i<form.getChildCount();i++){
if("javax.faces.Input".equals(componentFamily)){
UIInput input = (UIInput)dynamicFields.get(i);
System.out.println("Input Field: ID = "+input.getId() + " , Value="+ input.getValue());
}
}
The Id of the fields is printed properly, However value is always null. Clearly doing it all wrong.
Kindly let me know when and at what point do I create fields and how do I capture those values
P.S Am using JSF 2.0, Jdeveloper, Glassfish and/or Weblogic Server
From your question I was not able to be sure about what kind of data you expect to get from your webservice, and what kind of component you want to render it in. My answer below assumes that you will always receive a list of String and that you will display them in text boxes.
One possible approach would be to call your webservice and fetch the data in a #PostConstruct method, put this data into a list, and then render the data in a data table. Code below.
Bean:
#ManagedBean(name="bean")
#ViewScoped
public class YourBean implements Serializable {
private static final long serialVersionUID = 1L;
private List<String> values = new ArrayList<String>();
//The method below #PostConstruct is called after the bean is instantiated
#PostConstruct
public void init(){
//fetch data from source webservice, save it to this.values
}
public void save(){
for(String s: this.values)
// send s to destination webservice
}
public List<String> getValues(){
return this.values;
}
public void setValues(List<String> values){
this.values = values;
}
}
XHTML excerpt:
<h:form>
<h:dataTable value="#{bean.values}" var="s">
<h:column>
<h:inputText value="#{s}" />
</h:column>
</h:dataTable>
<h:commandButton value="Save" action="#{bean.save}" />
</h:form>
This problem because the scope of your bean you are binding on it if it is #RequestScoped this means that every time you refresh or call the page you are going to invoke the post constuctor (#PostConstuct) method again so do the job of the creation again and for the null value of the input fields you should add to every input field value expression to store the value in it.
private String inputValue; //setter() getter()
UIInput input = new HtmlInputText();
#PostCostruct
public void addInput()
{
// your previos create and add input fields to the form + setting value expression
Application app = FacesContext.getCurrentInstance().getApplication();
input.setValueExpression("value",app.getExpressionFactory().createValueExpression(
FacesContext.getCurrentInstance().getELContext(), "#{bean.inputValue}", String.class));
}
The correct answer if you are using binding don't use Request scope use Session Scope and it will work with you and get data not null when retrieve values.
Related
I'm dynamically generating a form based on data received from an RPC call into a FormFieldData object which has details about the field to be rendered such as, Field Name, expected length and type of input, if the field is a required field or not and valid input Regex in some cases etc.
I'd like to be able to perform validation on the field depending on above attributes.
Here's an example:
private void renderTextField(FormFieldData field){
FormGroup formGroup = new FormGroup();
FormLabel formLabel = new FormLabel();
if(field.isRequired()){
formLabel.setText(field.getName()+"*");
}else{
formLabel.setText(field.getName());
}
formGroup.add(formLabel);
TextBox textBox = new TextBox();
textBox.addChangeHandler(new ChangeHandler(){
#Overrride
public void onChange(ChangeEvent event){
//TODO - find a way to get the text entered in TextBox
// and perform validation on it
//and set the TextBox Style to "Validation-error"
}
});
formGroup.add(textBox);
form.add(formGroup);
}
There're similar methods to render dropdowns, Numeric fields, radio button fields etc. which would need similar validation.
The problem is I can't access the text from the TextBox inside the onChange method without declaring it final, which I can't do because I might be rendering multiple text fields. I don't know much about ChangeEvent and if there's a way to get the text from the that.
I'd really appreciate any pointers to a way to do this in real time as the data is entered into the form, other than having to iterate through the fields and their corresponding FormFieldData object when the form is submitted.
First off, you can make the variable final, no problem.
If you don't want to do that for whatever reason, you can get the TextBox from the event like this:
textBox.addValueChangeHandler(new ValueChangeHandler(){
#Overrride
public void onValueChange(ChangeEvent event){
TextBox box = (TextBox) event.getSource();
// Do whatever you need to here
}
});
You are probably also looking for ValueChangeHandler instead of ChangeHandler.
I am creating a form dynamically, and I need to post it and get the values in SpringController
for(var i=0;i<datArray.length;i++){
element[i] = document.createElement("input");
element[i].setAttribute("type", "text");
element[i].setAttribute("name", "text");
element[i].setAttribute("placeholder",datArray[i]);
element[i].setAttribute("id", datArray[i]+"id");
var foo = document.getElementById("fooBar");
//Append the element in page (in span).
foo.appendChild(element[i]);
}
About Pic - this is my dynamic form drawn in Select onChange
On Every dropdown Changed I am generating different text boxes dynamically. I need to post the dynamic text boxes and get the values in the Controller Spring in JAVA.
How to get dynamically posted Values in controller?
Any Idea?
Are you always sending the same model Object? I mean, does your form element always has the same name attribute?
if yes, you can just create a pojo class with attributes maching your names and use a RequestAttribute annotation.
If no, there is no way, you will just have to use the old requestparameter.
UPDATE
If you dont know what parameters are submitted, loop into all parameters :
List<String> requestParameterNames = Collections.list((Enumeration<String>) request.getParameterNames());
for (String parameterName : requestParameterNames) {
String attributeName = parameterName;
String attributeValue = request.getParameter(parameterName);
//DO YOUR STUFF
}
//DO YOUR STUFF
Question is pretty self explanatory. I want to send 2 different arrays of objects through a POST form without ajax to my controller.
I changed my question to using ajax and using a get request due to the size of the params. Currently getting a 400 (Bad Request). I have no idea why. Please take a look...
I have objects:
var phone = {phoneId:"", phoneNumber:"", phoneType:""};
var schedule = {scheduleId:"", time:"", day:""};
Which I place into a javascript arrays:
var phones = [phone1, phone2, phone3];
var schedules = [schedule1, schedule2];
and I use ajax to send:
var data = {
index: id,
schedules: schedules,
phones: phones
}
var url = "/myController/myUrl"
$.getJSON(url, data, function(result){
if(result.ok){
$('#messageAlertSuccess').show();
} else {
$('#messageAlertError').show();
}
});
I created wrapping classes to map them like so:
public class PhoneWrapper(){
private String phoneId;
private String phoneNumber;
private String phoneType;
}
And of course the scheduleWrapper follows the same convention.
Here's the method in my controller:
#ResponseBody
#RequestMapping(value="/myUrl", method=RequestMethod.GET)
public Result doSomething(#RequestParam("index") int index,
#RequestParam("phones") Set<PhoneWrapper> phoneWrappers,
#RequestParam("schedules") Set<ScheduleWrapper> scheduleWrappers,
Model model,
HttpSession session){
//do stuff here.
}
I am currently getting a 400. So what's wrong?
Update: here's the url that the .getJSON jquery method is building:
http://localhost:8080/myApp/myController/myUrl?index=9&schedules%5B0%5D%5BscheduleId%5D=1&schedules%5B0%5D%5BfromDay%5D=Monday&schedules%5B0%5D%5BtoDay%5D=Friday&schedules%5B0%5D%5BfromTime%5D=08%3A30%3A00&schedules%5B0%5D%5BtoTime%5D=16%3A00%3A00&schedules%5B1%5D%5BscheduleId%5D=5&schedules%5B1%5D%5BfromDay%5D=Saturday&schedules%5B1%5D%5BtoDay%5D=Monday&schedules%5B1%5D%5BfromTime%5D=09%3A00%3A00&schedules%5B1%5D%5BtoTime%5D=13%3A00%3A00&phones%5B0%5D%5BphoneId%5D=6&phones%5B0%5D%5BphoneNumber%5D=787-788-1111&phones%5B0%5D%5BphoneType%5D=PHONE&phones%5B1%5D%5BphoneId%5D=106&phones%5B1%5D%5BphoneNumber%5D=787-795-4095&phones%5B1%5D%5BphoneType%5D=FAX
I see a few things that don't look right
unless you have getters and setters in your wrappers (DTO is a better name), i don't use them for my DTOs for xhr calls, you need to change
public class PhoneWrapper(){
private String phoneId;
private String phoneNumber;
private String phoneType;
}
to have public fields vs private
public class PhoneWrapper(){
public String phoneId;
public String phoneNumber;
public String phoneType;
}
Your js arrays are not arrays but objects;
var phones = {phone1, phone2, phone3};
var schedules = {schedule1, schedule2};
Here they are as arrays
var phones = [phone1, phone2, phone3];
var schedules = [schedule1, schedule2];
Make sure you naming is the same of both the js and java sides. I find it very helpful to turn on the debugging when troubleshooting these problems. log4j -
<logger name="org.springframework.web.servlet.mvc" >
<level value="debug" />
</logger>
EDIT
So after the question was updated with more info I notice that it was the same problem as Binding a list in #RequestParam
I would say that you are almost there! The first thing the you need is a wrapper to hold the two Set<> parameters since spring is not able to map a collection directly to parameters (yet?).
Also, there are two ways to handle this kind of requests:
use a json request and #Requestbody with a single javascript object in the request body an map this into a java class (automatically by spring). This means you need to change a little how the data is send down and this approach has one side effect: you cannot merge data simply by defining the parameter as a model attribute.
a second possibility is to stay with the post form submit. Also here you need to create the wrapper and use this one as a requestparam. Either one per Set<> parameter like #Sotirios mentioned in his answer or one parameter which holds both sets. Then you need to modify your submit data to send the phone and schedule information like input fields. I haven't used sets in this case but
lists and the parameter names would look like phoneWrapper[0].phoneId.
The advantage of the second approach is that you can merge the request data with existing values so you do not need to send down a complete phone information all the time.
var phones = {phone1, phone2, phone3};
var schedules = {schedule1, schedule2};
These two are not arrays (square brackets), but objects (curly brackets).
Compare with
var phones = ["phone1", "phone2", "phone3"];
var schedules = ["schedule1", "schedule2"];
and if you are to pass actual object references (phone1, phone2, phone3, schedule1 and schedule2 are object variables) then you need to use
var phones = [phone1, phone2, phone3];
var schedules = [schedule1, schedule2];
For spring the map request parameters to Class instance fields, they have to match the name of the parameter.
So with
<input type="hidden" name="someParameter" value="123"/>
and
public class SomeClass {
private String someParameter;
// getters and setters
}
a Spring controller will be able to be injected with a SomeClass instance whose field someParameter has the value 123 that comes from the html hidden input request parameter. This is also known as a command object.
A javascript array has no meaning to either html or http.
As for the solution, I would keep your class PhoneWrapper, use javascript to populate 3 <input> elements, and change the method definition to
#RequestMapping(value=MY_URL, method=RequestMethod.POST)
public String doSomething(#RequestParam("index") int index,
PhoneWrappers phoneWrappers,
ScheduleWrappers scheduleWrappers,
Model model,
HttpSession session){
Notice there are no more array [] brackets. (You would do the same for ScheduleWrappers).
My understanding so far is on our controller request mapping method we can specify RedirectAttributes parameter and populate it with attributes for when the request gets redirected.
Example:
#RequestMapping(value="/hello", method=GET)
public String hello(RedirectAttributes redirAttr)
{
// should I use redirAttr.addAttribute() or redirAttr.addFlashAttribute() here ?
// ...
return "redirect:/somewhere";
}
The redirect attributes will then be available on the target page where it redirects to.
However RedirectAttributes class has two methods:
addAttribute()
addFlashAttribute()
Have been reading Spring documentation for a while but I'm a bit lost. What is the fundamental difference between those two, and how should I choose which one to use?
Here is the difference:
addFlashAttribute() actually stores the attributes in a flashmap
(which is internally maintained in the users session and removed
once the next redirected request gets fulfilled)
addAttribute() essentially constructs request parameters out of
your attributes and redirects to the desired page with the request
parameters.
So the advantage of addFlashAttribute() will be that you can store pretty much any object in your flash attribute (as it is not serialized into request params at all, but maintained as an object), whereas with addAttribute() since the object that you add gets transformed to a normal request param, you are pretty limited to the object types like String or primitives.
Assume you have 2 controllers.If you redirect from one controller to
another controller the values in model object won't be available in the
other controller. So if you want to share the model object values
then you have to say in first controller
addFlashAttribute("modelkey", "modelvalue");
Then second controller's model contains now the above key value pair..
Second question ? What is difference between addAttribute and addFlashAttribute in RedirectAttributes class
addAttribute will pass the values as requestparameters instead of model,so when you add some using addAttribute you can access those values from request.getParameter
Here is the code.I have used to find out what is going on :
#RequestMapping(value = "/rm1", method = RequestMethod.POST)
public String rm1(Model model,RedirectAttributes rm) {
System.out.println("Entered rm1 method ");
rm.addFlashAttribute("modelkey", "modelvalue");
rm.addAttribute("nonflash", "nonflashvalue");
model.addAttribute("modelkey", "modelvalue");
return "redirect:/rm2.htm";
}
#RequestMapping(value = "/rm2", method = RequestMethod.GET)
public String rm2(Model model,HttpServletRequest request) {
System.out.println("Entered rm2 method ");
Map md = model.asMap();
for (Object modelKey : md.keySet()) {
Object modelValue = md.get(modelKey);
System.out.println(modelKey + " -- " + modelValue);
}
System.out.println("=== Request data ===");
java.util.Enumeration<String> reqEnum = request.getParameterNames();
while (reqEnum.hasMoreElements()) {
String s = reqEnum.nextElement();
System.out.println(s);
System.out.println("==" + request.getParameter(s));
}
return "controller2output";
}
Javadoc description:
"A FlashMap provides a way for one request to store attributes intended for use in another. This is most commonly needed when redirecting from one URL to another -- e.g. the Post/Redirect/Get pattern. A FlashMap is saved before the redirect (typically in the session) and is made available after the redirect and removed immediately."
I have been trying for last 3 days still i am not able to solve my problem
I have Person Class
#SuppressWarnings("rawtypes")
#OneToMany(cascade = CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="person")
#JoinColumn(name="person_id")
public Set<Book> books = new HashSet<Book>();
class Book
book_id
person_id
In my JSP form i have
<c:forEach items="${BookList}" var="var1" varStatus="counter">
<input type="checkbox" name="books[${counter.index}].book_id" value="${var1.book_id}" >${var1.book_name}</input>
</c:forEach>
I am inserting the books in table depending upon the check boxes
The book list is populated from refrenceData model.
COntroller
#RequestMapping(value = "/persons/add", method = RequestMethod.GET)
public String getAdd(Model model) {
logger.debug("Received request to show add page");
// Create new Person and add to model
// This is the formBackingOBject
model.addAttribute("personAttribute", new Person());
// This will resolve to /WEB-INF/jsp/addpage.jsp
return "hibernate/addpage";
}
#RequestMapping(value = "/persons/add", method = RequestMethod.POST)
public String add(#Valid #ModelAttribute("personAttribute") Person person, BindingResult result) {
logger.debug("Received request to add new person");
if (result.hasErrors())
return "hibernate/addpage";
else
personService.add(person);
// This will resolve to /WEB-INF/jsp/addedpage.jsp
return "hibernate/addedpage";
}
Now if i have single Book object then this works ok and data is entered in DB but if i have set then it says invalid property book[1]
After searching a lot on SO and Google i leart that i have two option
PropertyEditor
AutoPopulatingList
I don't know how to use them in my case. Can anyone help me , where do i have to use them and how to use it
Look at this question Bind objects in a Set collection
You need to use another type of Collection. I'd recommend to use a List instead of a Map. When you send from the form a parameter with a name like:
name="books[0].book_id"
SpringMVC will look in the property called books (which is a Set for you) and then it will try to get the first element by doing books.get(0). Set don't have a get because Set has not an order.
For the implementation of the list you can use AutoPopulatingList. It is an implementation of a lazy List which will create an object if it doesn't exist. For example if you invoke books[0].id and you haven't added a book in the position 0 of the list it will throw a NullPointerException, but if you use AutoPopulatingList it will create a new Book and addd it in that position if that position is empty.
public List<Book> books = new AutoPopulatingList<Book>(new ElementFactory<Book>() {
#Override
public Book createElement(final int index) throws ElementInstantiationException {
//call the constructor as you need
return new Book();
}
});
if you you are going to instanciate it with the default constructor of Book (that is Book()), you can use a syntax like this one:
public List<Book> books = new AutoPopulatingList<Book>(Book.class);
When I have such complicated form i honestly prefer to use JSON and submit it using AJAX.
{"person":{"id":1,"books":[{"person_id":2,"book_id":3},{"person_id":2,"book_id":6},{"person_id":3,"book_id":4}]}
#RequestMapping(value = "/persons/add", method = RequestMethod.POST)
#ResponseBody
public String add(#RequestBody Person person){
//ad your business logic
}
Your code will be validate by de-serializer and you will be able to save it.
You can reed more about that in this post:
http://blog.springsource.com/2010/01/25/ajax-simplifications-in-spring-3-0/
Binding of Set isn't possible with Spring MVC as Sets do not have indexes to work with. Although you can iterate through sets in JSP and show the results.
The solutions might be -
Use another type of collection like List.
Wrap your Set in a POJO, use your Set for showing its containing values in JSP. Once you want to post the form containing your selection, add new property in your POJO which is String(or similar) and provide this property as your PATH in JSP tag, which will get the selection data from JSP. Then in backend code, fill your set with this value.
In case, your POJO is the also an Entity for your database creation using Hibernate, simply put #Transient on top of it. Hibernate will ignore this property while creating table.