I have an user view model that has the following properties:
public User user;
public List<Language> Languages;
I send the above model to the view and use html helpers to build the form, so I end up with something like:
<form action="/Users/Edit/5" method="post"><input id="user_UserId" name="user.UserId" type="hidden" value="5" />
First Name
Last Name
Email
<br />
<input id="user_Email" name="user.Email" type="text" value="test#gmail.com" />
Language
-
en
en
Now, I try to read the POST in something that initially was something like :
[AcceptVerbs( HttpVerbs.Post )]
public ActionResult Edit( int UserId, FormCollection form ) {
and cannot get the user.UserId variable, user.FirstName variable etc.
Any idea what needs to be done to be able to read this kind of POST request. I'm kind of reluctant to modifying my ViewModel as it is very simple and easy to maintain as it is.
Thank you.
I had a similar problem some time ago. This article was helpful:
Editing a variable length list
Apparently the easy answer is to use Prefix, something like:
public ActionResult Edit([Bind(Prefix="user")] int UserId, FormCollection form ) {
}
However, I'm still getting the
The parameters dictionary contains a
null entry for parameter 'UserId' of
non-nullable type 'System.Int32' for
method 'System.Web.Mvc.ActionResult
Edit(Int32,
System.Web.Mvc.FormCollection)'
Any idea how to fix that?
Related
Sorry if this is an obvious question, but I didn't had much luck so far.
I am having an input of a submit type in my View:
<input type="submit"
value="Remove Question"
class="btn btn-outline-danger"
formaction=#Url.Action("Survey_RemoveQuestion",
new Survey_Question_Wrapper() {
Survey = Model,
Question = Model.Questions[i] })/>
In my controller I have a handler, which looks like this:
public ActionResult Survey_RemoveQuestion(Survey_Question_Wrapper s)
{
s.Survey.Questions.Remove(s.Question);
return View("SurveyEdit", s.Survey);
}
The Survey_Question_Wrapper has 2 constructors: a default empty one and the one, who accepts 2 parameters and assigns them to fields.
The problem which I am struggle with, is that the Survey_RemoveQuestion method
is invoked with an object, build with the default constructor, so his fields are null's.
I believe there is something obvious I am missing. Many thanks in advance.
No, the problem is not relevant with Survey_Question_Wrapper constructors. You are trying to pass the complex types to controller via GET. You can't send the complex types directly like that.
You should serialize it and send it as string. (I used Json.Net, you can use another library)
<input type = "submit"
value="Remove Question"
class="btn btn-outline-danger"
formaction=#Url.Action("Survey_RemoveQuestion",
new
{
s = JsonConvert.SerializeObject(new Survey_Question_Wrapper
{
Survey = Model,
Question = Model.Questions[i]
}
)
})/>
And controller part looks like;
public ActionResult Survey_RemoveQuestion(string s)
{
//Deserialize it
var obj = JsonConvert.DeserializeObject<Survey_Question_Wrapper>(s);
obj.Survey.Questions.Remove(obj.Question);
return View("SurveyEdit", obj.Survey);
}
Also, if you want to send complex types to server, its proper way to perform it using POST instead of GET.
In the jsp file:
<sf:form ... action="queryUser" modelAttribute="user_a">
<sf:input path="name"/>
<input type="submit" id="submit1"/>
</sf:form>
<sf:form ...action="addUser" modelAttribute="user_b">
<sf:input path="name"/>
<input type="submit" id="submit2"/>
</sf:form>
In the Java file:
#Controller
#RequestMapping("/user")
#SessionAttributes("user_a")
public class UserController
{
...
RequestMapping("/addUser")
public void function(#ModelAttribute("user_a") User user_a,#ModelAttribute("user_b") User user_b,BindingResult bindingResult)
{
...
}
}
Here is the problem: when I click the submit2.
the request entity user_b will be passed to both user_a and user_b!!
Who knows how to distinguish them??
I think I figured out the problem.
When in the case like in the problem:
RequestMapping("/addUser")
public void function(#ModelAttribute("user_a") User user_a,#ModelAttribute("user_b") User user_b,BindingResult bindingResult)
{
...
}
The only possibility that you use two same-type objects in one controller's function and do not want to modify certain one at the same time is that one of them has already been filled previously, and you want to use it in this function. Or you agree to modify both of them (in this case, you would pass two different entities).
So, in the situation that I encountered, just do not list the object in the function's parameters. And you can access the ready-made model attribute by codes like:
RequestMapping("/addUser")
public void function(Model model,#ModelAttribute("user_b") User user_b,BindingResult bindingResult)
{
// if this is a session attribute, it will not be changed.
User user_a = model.get("user_a");
//more codes go here
}
In conclusion, spring MVC framework will bound one valid object of the request to all the same-type variables when there is only one valid object and there are multiple same-type objects in the function's parameter list.
One sentence principle:
Binding operation of a variable take place when and only when you list it in the function's parameter list.
I'm trying to send some data from the client side to the server, and have it processed into a file download.
I'm using a simple HTML form because I want to initialize a file download (and not AJAX).
one of the form fields is an array of items. (the other two are name and description strings).
I'm serializing this field to a string (JSON.stringify) before submitting the form.
on the server side I tried a million techniques (#ModelAttribute vs. #RequestBody, different jackson mapping bean configurations) to either convert this to a single type or to three separate types (String + String + List/Array).
the examples I found were only for AJAX...
can anyone supply a working example or a description of one?
=======
Update:
I've implemented a workaround by JSON.stringify-ing the collection and passing it in one of the inputs,
and on the server side I have:
#RequestMapping(method = RequestMethod.POST, value = "exportSectionsToExcel")
public HttpEntity<byte[]> createExcelWorkBook(#ModelAttribute ExportSectionsListForm exportSectionsListForm) {
Section[] sectionObjects = gson.fromJson(exportSectionsListForm.getSections(), Section[].class);
...
with ExportSectionsListForm object containing strings only:
public class ExportSectionsListForm {
private String name;
private String url;
private String rssUrl;
private String sections;
...
(omitting ctor, getters and setters)
additionally, I found this promising link:
http://viralpatel.net/blogs/spring-mvc-multi-row-submit-java-list/
but didn't try it - seems like I'll need to dynamically generate input elements for this to work, but it might actually be the right solution. has anyone tried this?
The #ModelAttribute tag will try to build the object based on form postings. Since you are serializing your form values to JSON, this wont work. #RequestBody simply gives you a String representing the request body. So, you could get the String representing the JSON being passed in, then demarshal the JSON using Jackson of FlexJSON (or whatever JSON library you use). I am not sure this is the best approach, though.
I would question why you need to serialize the form to JSON to begin with. Spring handles forms with Lists/Maps just fine. Simply submit the form using the #ModelAttribute, making your "array" and List, or whatever you are expecting, on the Controller. So, if I am interpreting your example correctly, my ModelAttribute would look like:
public class ExportSectionsFormBean {
private String name;
private String url;
private String rssUrl;
private List<String> sections;
/* getters/setters */
}
Then my Controller method would look like:
#RequestMapping(method = RequestMethod.POST, value = "exportSectionsToExcel")
public HttpEntity<byte[]> createExcelWorkBook(#ModelAttribute ExportSectionsFormBean exportSectionsFormBean ) {
/* Do whatever with your */
}
On the form side, using the Spring JSTL tags, simply make your "sections" fields look like:
<form:input path="sections[0]" />
<form:input path="sections[1]" />
Or, if you'd rather use HTML, then
<input type="text" name="sections[0]" id="sections0" />
<input type="text" name="sections[1]" id="sections1" />
Which is what gets generated by the above JSTL tags. As long as the values for "sections" is put in the HTTP request as 'section[#]=value', you are all set.
I have been working on the same issue. And if i have several inputs witht eh same name such as:
<input name="somename"/>
<input name="somename"/>
<input name="somename"/>
and i have a form mapped to my method like this:
#ModelAttribute("ReturnsAndExchangesForm") ReturnsAndExchangesForm returnsAndExchangesForm
and in that form i have getters and setters for a property named:
String[] somename , spring is passing those values into that array nicely!
My domain object does not keep the values that are not explicitly referenced in the JSP file between a GET and a POST operation on the same controller. Here is a sample with error checking omitted
I have a domain object.
class foo
{
private int fieldA;
private String fieldB;
// .. getters and setters omitted
}
Controller
#Controller
public class MyController
{
#Autowired
private IDaoService daoService;
#RequestMapping(value = "/display", method = RequestMethod.GET)
public String newForm(#RequestParam("id") Long id, Model model, Principal principal) throws Exception
{
// check that the user has permissions
...
// get the object
Foo foo = daoService.read(id);
// at this point foo.fieldA is equal to the input id
model.addAttribute("foo", foo);
// return the JSP path
}
#RequestMapping(value="/update", method = RequestMethod.POST)
public String update(#ModelAttribute("foo") Foo foo,
BindingResult result,
Principal principal,
Model model) throws Exception
{
// ERROR - at this point, fieldA is null
}
}
JSP
<form:form method="post" commandName="foo">
<fieldset>
<legend>Invest</legend>
<div class="fm-req">
<label for="fm-name">Field B</label>
<spring:bind path="fieldB">
<input id="fm-name" type="text" name="${status.expression}" value="${status.value}" ></input>
</spring:bind>
</div>
<div id="fm-submit" class="fm-req">
<INPUT type="submit" value="Submit" name="Submit" />
</div>
</fieldset>
</form:form>
I would have thought that the JSP gets the object created in newForm that has fieldA set ( and possibly fieldB ). The user has the option to change fieldB and then hit submit.
I've done lots of reading of the Spring docs and checked web sites, but cannot find out why the foo.fieldA is null on the update method in the controller.
From what I understand about Spring MVC this appears to be a standard pattern, but please feel free to correct me.
Thanks in advance,
You can use one from following :
Use Ralph's way of hidden field.
Change type of Foo.fieldA to private Integer Foo
Reason May be: Foo.fieldA is creating problem because, NULL value is set to int type fieldA.
That is the expected behavior.
Both instances (in newForm and update) of the object foo (in java class names should be start with upper case) are complete independend of each other.
So eighter create a hidden field, or put it into the session.
I would recommend the hidden field:
I have a really odd issue with ASP.Net MVC.
I have a form, which is posting 3 text values to an action method called create user (for simplicity sake, say it is the following);
public ActionResult CreateUser(string FirstName, string LastName, string Email)
{
var s = FirstName + LastName + Email;
return RedirectToAction("Index");
}
Say also my form is
<% using (Html.BeginForm("CreateUser", "User"))
{ %>
<%=Html.TextBox(("FirstName")) %>
<%=Html.TextBox(("LastName")) %>
<%=Html.TextBox(("Email")) %>
<div><input type="submit" value="Submit" /></div>
<% } %>
Now in my action method, on the user controller, the values FirstName, LastName and Email are all null!
However, if I copy the same method to another controller (Game), and update the form to post there, the values in the method are not null! I am totally stumped with this one.
Both Controllers are the same - they inherit the same base class, have the same attributes applied to them etc.
EDIT: Got it working (not sure what the underlying issue was).
I had a custom attribute on my Index method on the User controller (this essentially parsed the HttpContext.Current.User.Identity.Name property and automatically passed it into the method). For some reason, this was problematic on the Index method, once I removed it everything started working as intended!
This was my Index method before:
[Authorisation]
public Action Index(string userName){...}
and after
public Action Index() {...}
By the sounds of things (works when you change the controller it posts to) it'll probably have something to do with 'User' being a reserved word of some type.
It kinda makes sense, User is used in the asp.net framework to refer to the current IPrincipal object.
So yeah, rename your controller to something different.
HTHs,
Charles
Try add a breakpoint inside CreateUser and take a look at the content of Request.Form (or QueryString), or ValueProvider. The keys might be different.