How to get checked checkbox value from html page to spring mvc controller - spring

im using spring mvc framework with thymeleaf template engine
the problem is , i have 1 page with multiple check box iterated sing thymeleaf th:each iterator.When i clicked multiple check boxes i want to pass check box values to the controller method..
html content
<table>
<tr th:each="q : ${questions}">
<h3 th:text="${q.questionPattern.questionPattern}"></h3>
<div>
<p >
<input type="checkbox" class="ads_Checkbox" th:text="${q.questionName}" th:value="${q.id}" name="id"/>
</p>
</div>
</tr>
</table>
*Controller*
#RequestMapping(value = Array("/saveAssessment"), params = Array({ "save" }))
def save(#RequestParam set: String, id:Long): String = {
var userAccount: UserAccount = secService.getLoggedUserAccount
println(userAccount)
var questionSetQuestion:QuestionSetQuestion=new QuestionSetQuestion
var questionSet: QuestionSet = new QuestionSet
questionSet.setUser(userAccount)
questionSet.setSetName(set)
questionSet.setCreatedDate(new java.sql.Date(new java.util.Date().getTime))
questionSetService.addQuestionSet(questionSet)
var list2: List[Question] = questionService.findAllQuestion
var limit=list2.size
var qustn:Question=null
var a = 1;
for( a <- 1 to limit ){
println( a );
qustn= questionService.findQuestionById(a)
questionSetQuestion.setQuestion(qustn)
questionSetQuestion.setQuestionSet(questionSet)
questionSetQuestion.setCreatedDate(new java.sql.Date(new java.util.Date().getTime))
questionSetQuestionService.addQuestionSetQuestion(questionSetQuestion) } "redirect:/teacher/Assessment.html" }

I think you pretty much have it. With a checkbox, you can only send one piece of information back with the form...that being the value. So if you are trying to determine which checkboxes are checked when the user clicks the submit button, then I would have the checkboxes all use one name...like "id" (exactly like you have). Value is the actual id of the question (again like you have). Once submitted, "id" will be a String array which includes all the values of the checkboxes that were checked.
So your controller method needs to take param called "ids" mapped to parameter "id" which is a string[]. Now for each id, you can call questionService.findQuestionById.
(I'm not a Groovy guru so no code example sry :)

I have used JSTL with JSP and thymeleaf was something new. I read the THYMELEAF documentation.
There is a section which explains multi valued check boxes.
<input type="checkbox"
class="ads_Checkbox"
th:text="${q.questionName}"
th:value="${q.id}" name="id"/>
In the above code we are not binding the value to the field of the command object. Instead try doing this
<input type="checkbox"
class="ads_Checkbox"
th:text="${q.questionName}"
th:field="*{selectedQuestions}"
th:value="${q.id}" />
here the selectedQuestions is an array object present in the spring command object.

Related

how to do binding in Spring annotated request parameter?

i have a controller that is using annotation for request mapping and requestParam.
the controller is working fine. However when submitting a command object with array, spring will crap out saying array index out of bound. i am guessing there is something wrong with binding but don't know how to fix it.
to be more specific, in eclipse i would set debugger at the beginning of the controller, and when submitting the form (by hitting a input submit button) eclipse debugger will not trigger and i will see array index out of bound error in console.
the controller is something like this:
#RequestMapping(value = {"/internal/pcsearch.dex", "/external/pcsearch.dex"},
method = {RequestMethod.POST, RequestMethod.GET})
public ModelAndView executeProductCatalogSearch(
HttpServletRequest request,
#RequestParam(value = "cat" ,required = false) String cat,
#RequestParam(value = "brand" ,required = false) String brand,
#ModelAttribute("command") ProductCatalogCommand cmd
){
[edit]
and the jsp is like:
<form name="pForm"
id="pForm"
action="<c:url value="psearch.dex"><c:param name="cat" value="${cat}"/></c:url>"
method="POST"
style="display:inline;">
...
...
<c:forEach var="model" items="${models}" varStatus="modelLinkStatus">
<script>
var modelImg<c:out value="${modelLinkStatus.index}"/>Src = '<c:out value="${model.altModelImage}"/>';
</script>
<spring:bind path="command.models[${modelLinkStatus.index}].modelSkusDisplayed">
<input type="hidden" name="<c:out value="${status.expression}"/>" id="<c:out value="${status.expression}"/>" value="<c:out value="${status.value}"/>"/>
</spring:bind>
<spring:bind path="command.updateCartButton">
<input type="submit" value="<spring:message code="orderEntryMessages.ecatalog.button.addToCart" text="Add to Cart" htmlEscape="yes" />" name="<c:out value="${status.expression}"/>" id="<c:out value="${status.expression}"/>" class="sub_buttons"/>
</spring:bind>
...
and the command object declare the model array as:
private List<ModelLink> models = new ArrayList<ModelLink>();
where modelLink is a custom ds.
the first foreach tag handle the the model command object and the 2nd part is the submit button i clicked on.
i think you should use AutoPopulatingList as models to bind list to view and controller. for example please refer link. This might resolve your problem of index.

MVC3 Ajax.BeginForm with PartialView and persistent routedata issue

I have a main view and the URL for this view has a Action/Controller/Area and id value, something like:
http://localhost:56513/Incident/IncidentHome/Index/8c02a647-a883-4d69-91be-7ac5f7b28ab7
I have a partialview in this main view, one that calls methods in the controller via Ajax. This partial view needs to know the ID value of the url for the parent page. I found how to do this is through 'ParentActionViewContent'. Something like:
using (Ajax.BeginForm("UpdatePersonalStatusPanel", "Status", new { area = "Tools" , id = ViewContext.ParentActionViewContext.RouteData.Values["id"].ToString() }, new AjaxOptions { UpdateTargetId = "divPersStatus" }))
{
<p style="text-align: center;">
<span class="editor-label">#Html.LabelFor(m => m.StatusText)</span> <span class="editor-field">#Html.EditorFor(m => m.StatusText)</span>
<input type="submit" value="Change Current Status" />
</p>
}
Now, this works fantastic for calling the controller method. The ID is passed correctly so that the controller can then see it in the routedata. I use the id to perform a database call, and then return the partialview again. The problem is on the return. I get a 'Object reference not set to an instance of an object' on the ViewContext.ParentActionViewContext.RouteData.Values["id"].ToString() bit in the ajax.beginform , and my targetid doesn't refresh.
Clearly I must be doing something wrong. Does someone else have a better way to see the parent view's routedata through Ajax?
If I'm understanding you correctly, this partial view calls itself. So ParentActionViewContext works the first time because the first time your main view calls an action using this partial view. However, later an ajax call directly returns this partial view. When the partial view is invoked directly there is no Parent View action hence the null reference on ParentActionViewContext.
Rather than deal with with route data I recommend including the id in the model of your partial view.
new { area = "Tools" , id = Model.Id }

MVC3 Drop Down or ListBox with dynamic check boxes

I have an MVC3 C#.Net web app. I have a requirement to display a list of check boxes (either in a drop down or a List Box) dynamically based on a table in our db. The table can contain 1:500 entries. I then need to pass the selected check boxes to the Controller in order to perform an action on each selection. Any ideas on an implementation?
There are many ways to go about this but here is a general demo.
You can pass a list of the checkbox values and descriptions either on the Model (as this example does), ViewData[""] dictionary or ViewBag (MVC3+).
Then in your view loop through them and add them to your form using the name="chxBxGroupName" to group them.
Now create a controller action to post to that takes a List of the value type (in this example int) with the parameter naming matching the name="chxBxGroupName".
It will post a list of checked values.
The post page will just print out:
123
456
// This is your landing page. It gathers the data to display to the user as checkboxes.
public ViewResult MyPageWithTheCheckboxes()
{
// For example: Assume a Dictionary with the checkbox value and description
// Replace with DB call, etc.
return View(new Dictionary<int, string> { { 123, "Foo" }, { 456, "Bar" } });
}
<%# Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage<Dictionary<int,string>>" %>
<!-- Rest of HTML page... -->
<form id="frm1" action="<%=Url.Action("MyPost")%>" method="post">
<% foreach (var item in Model) { %>
<input type="checkbox" id="chxBx<%=item.Key%>" name="chxBxGroupName" value="<%=item.Key%>"/>
<label for="chxBx<%=item.Key%>"><%=item.Value%></label>
<br/><br/>
<% } %>
<input type="submit" value="Go!"/>
</form>
<!-- Rest of HTML page... -->
public ContentResult MyPost(List<int> chxBxGroupName)
{
return Content(string.Join(Environment.NewLine, chxBxGroupName ?? new List<int>()), "text/plain");
}
the answer provided by Jay accomplishes exactly what you need. If you want to put the items in a list you can do it by surrounding the markup with a div control lie below
<div style="height:40px;overflow:auto;">
<% foreach (var item in Model) { %>
<input type="checkbox" id="chxBx<%=item.Key%>" name="chxBxGroupName" value="<%=item.Key% >"/>
<label for="chxBx<%=item.Key%>"><%=item.Value%></label>
<br/><br/>
<% } %>
</div>
unfortunately you cant have checkboxes in a <select />, but if you really wanted it to look like a select list you could add some JQuery that processes onclick of a textbox and shows the div. This obviously would require some jQuery and might not be worth it

ActionMethod param is 0 every time

I've got a form (here's some of its code):
#model Discussion
#{
ViewBag.Title = "Edit Discussion";
Layout = "~/Views/Shared/_App.cshtml";
}
#using (Html.BeginForm("Update", "Discussion", FormMethod.Post, new { id = Model.discussionId, #class = "update" }))
{
... rest of the view code
}
My related controller's update method has:
[HttpPost]
[ValidateInput(false)]
public ActionResult Update(FormCollection col, int id = 0)
{
... rest of code
}
when the form is submitted, I keep getting an id of 0 instead of the ID I'm seeing from the model that when I debug is clearly there inside being used during the form rendering. IT's just when I submit, it's not passing the id correctly.
Am I doing something wrong in terms of syntax here? the new{} in the Html.BeginForm I guess I don't understand how the new anonymous type is matching up to this id when the form is submitted when it's a collection of id and a class here as you can see.
When you do the new {id = Model.discussionId ...} you are setting the id attribute of the form element. To get the id to come across properly you would have to make it an input of the form. So inside the form you would put a hidden input element with something like this: #Html.Hidden("id", Model.discussionId)
So your current form is rendering something like this:
<form id="theDiscussionId" class="update" action="/Discussion/Update">
... rest of the view code
</form>
And you need it to be like this:
<form class="update" action="/Discussion/Update">
<input type="hidden" name="id" value="theDiscussionId" />
... rest of the view code
</form>

ASP.NET MVC 3 - Validation Question

Good evening everyone I have a question regarding validation of drop-down list values. I have a view that is bound to a view model type called ReservationData.
This object contains a property CustomerVehicles of type List<VehicleData>. VehicleData has two int properties VehicleMakeId and VehicleModelId.
On my view I am trying to loop over the number of items in the CustomerVehicles collection and displaying two dropdowns for each, a vehicle make dropdown and a vehicle model dropdown using DropDownListFor.
When I try to submit and validate I do not see any validation errors displayed on the screen.
Just in case you are wondering I have added a ValidationMessageFor for each dropdown as well. I am not sure if this is an issue with the structure of my view model and its complexity and how the controls need to be named or how the ids need to be set. Any help would be greatly appreciated.
Here is the code for the looping over the collection:
#for (var i = 0; i < Model.CustomerVehicles.Count(); i++)
{
var vehicleNumber = i + 1;
<div class="vehicle-selection-wrapper">
<div class="content-container">
<h3>
Vehicle #vehicleNumber</h3>
<img class="vehicle-image" alt="manufacturer image" src="#Url.Content("~/Content/images/default-vehicle.gif")" /><br />
#Html.LabelFor(m => m.CustomerVehicles[i].VehicleMakeId)
#Html.DropDownListFor(m => m.CustomerVehicles[i].VehicleMakeId
, new SelectList(Model.VehicleMakes, "Id", "Name")
, #UIDisplay.Dropdown_DefaultOption, new { #class = "long-field" })<br />
#Html.ValidationMessageFor(m => m.CustomerVehicles[i].VehicleMakeId)<br />
#Html.LabelFor(m => m.CustomerVehicles[i].VehicleModelId)
#Html.DropDownListFor(m => m.CustomerVehicles[i].VehicleModelId
, new SelectList(new List<CWR.Domain.VehicleModel>(), "Id", "Name")
, #UIDisplay.Dropdown_DefaultOption, new { #class = "long-field" })
#Html.ValidationMessageFor(m => m.CustomerVehicles[i].VehicleModelId)
</div>
</div>
}
Ok so I also noticed that in the generated HTML the selects that are generated are missing the HTML5 data-val attributes that are associated to elements to handle validation. Here is the generated HTML
<select class="long-field" id="CustomerVehicles_0__VehicleMakeId" name="CustomerVehicles[0].VehicleMakeId"><option value="">-- Select --</option>
</select><br />
<span class="field-validation-valid" data-valmsg- for="CustomerVehicles[0].VehicleMakeId" data-valmsg-replace="true"></span><br />
<label for="CustomerVehicles_0__VehicleModelId">Model</label>
<select class="long-field" id="CustomerVehicles_0__VehicleModelId" name="CustomerVehicles[0].VehicleModelId"><option value="">-- Select --</option>
</select>
<span class="field-validation-valid" data-valmsg-for="CustomerVehicles[0].VehicleModelId" data-valmsg-replace="true"></span>
Additionally in my VehicleData class the VehicleMakeId and VehicleModelId properties are decorated with a Required attribute.
UPDATE:
Ok so I was testing and noticed that if I keep my code identical except I swap the Html.DropdownListFor calls with Html.TextboxFor calls then the validation works. What could be causing this? Could it be a framework bug with the unobtrusive validation?
UPDATE: Contains Fix
So after posting this same question on the ASP.NET Forums, I was able to get a solution. In the post you will be able to see that there is a bug in the unobtrusive validation framework and how it handles validation of dropdownlists. The user counsellorben does a good job in explaining the problem as well as a solution (including sample code) that will assist others in avoiding this issue in the future, or at least until Microsoft builds in a fix in to the framework.
Thank you everyone for your assistance.
I too have come across this obviously massive oversight regarding client side validation with dropdownlists in MVC 3 and the best solution I can offer is to put the missing HMTL attributes in yourself.
In your view model create a property like this.
public Dictionary<string, object> CustomerVechicleAttributes
{
get
{
Dictionary<string, object> d = new Dictionary<string, object>();
d.Add("data-val", "true");
d.Add("data-val-required", "Please select a Vechicle.");
return d;
}
}
Then in your code, enter
#Html.DropDownListFor(m => m.CustomerVehicles[i].VehicleMakeId
, new SelectList(Model.VehicleMakes, "Id", "Name")
, #UIDisplay.Dropdown_DefaultOption,
**Model.CustomerVechicleAttributes** })
Just add the Model.CustomerVechicleAttributes as htmlAttributes to your dropdownlist.
This will inject the necessary attributes that are missing. You will of course need to add any other attributes you may need like your class attribute.
Hope this helps.
This is the simpliest way I found to do it, just adding data-val-*-* attributes in HtmlAttributes of DropDownListFor, inside the view. The following method works with RemoteValidation too, if you do not need remote validation, simply remove the elements containing data-val-remote-*:
#Html.DropDownListFor(m => m.yourlistID, (IEnumerable<SelectListItem>)ViewBag.YourListID, String.Empty,
new Dictionary<string, object>() { { "data-val", "true" },
{ "data-val-remote-url", "/Validation/yourremoteval" },
{ "data-val-remote-type", "POST" }, { "data-val-remote-additionalfield", "youradditionalfieldtovalidate" } })
I hope it may help. Best Regards!
you should try to add data annotations on your view model properties first so you could see the validation messages.
you might find what you need here
http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.aspx
or create custom ones if needed.
what exactly do you need to validate?
I had exactly the same problem with the field getting correctly validated in TextBoxFor but not in DropDownListFor.
#Html.DropDownListFor(m => m.PaymentTO.CreditCardType, Model.CreditCardTypeList, "Select Card Type", new { style = "width:150px;" })
Since I had another DropDownListFor working on the same page, I knew that it wasn’t a generic DropDownListFor problem. I also have a complex model and parent object PaymentTO wasn’t initialized. When I set viewTO.PaymentTO = new PaymentTO(); in the Controller, the validation for the DropDownListFor started to work. So there is probably a problem with DropDownListFor, but the fix can be as simple as initializing the object in the controller.

Resources