How to pass checkbox values to controller through ajax in mvc3 - asp.net-mvc-3

I have a property in my class which is of string type.
public string Months { get; set; }
In the view ,I need to create a checkbox list displaying months..
If january is selected 1 should be saved to database.If january and february is selected 1,2 should be saved to database.
I used an ajax form to pass values..It works well for all fields except checkboxlist.
#using (#Ajax.BeginForm("Create", "Rate", null, new AjaxOptions { OnSuccess = "OnSuccessRateCreate", HttpMethod = "POST" }, new { id = "RateForm" }))
{
//fields inside this
#Html.CheckBoxFor(model=>model.Months,new{id="month",value="1"})Jan
#Html.CheckBoxFor(model=>model.Months,new{id="month1",value="2"})Feb
#Html.CheckBoxFor(model=>model.Months,new{id="month2",value="3"})Mar
#Html.CheckBoxFor(model=>model.Months,new{id="month3",value="4"})Apr
}
It shows error:-
Cannot implicitly convert type string to bool.
Pls help...

You have wrong binding. Try to bind the List of this checkboxes
public List<string> Months { get; set; }
#using (#Ajax.BeginForm("Create", "Rate", null, new AjaxOptions { OnSuccess = "OnSuccessRateCreate", HttpMethod = "POST" }, new { id = "RateForm" }))
{
<input type="checkbox" value="0" name="Mounth">
<input type="checkbox" value="1" name="Mounth">
<input type="checkbox" value="2" name="Mounth">
}
works for me

Related

Ajax call breaks binding to object children

Without the ajax call, My main view binds to my parent class and the partial view on main view, binds to a child member of the parent class
parent...
public class Client
{
[ScaffoldColumn(false)]
public int Id { get; set; }
[DisplayName("Name")]
[Required]
[StringLength(120)]
public string Name { get; set; }
// etc...
public virtual Address Address { get; set; }
}
child of parent...
public class Address
{
[ScaffoldColumn(false)]
public int AddressId { get; set; }
[DisplayName("Address")]
[Required]
[StringLength(200)]
public string Street { get; set; }
// etc...
[ForeignKey("Client")]
public int? Id { get; set; }
public virtual Client Client { get; set; }
}
the main view
#using (Html.BeginForm("Create", "Client", FormMethod.Post, new Dictionary<string, object> { { "data-htci-target", "addressData" } }))
{
#Html.AntiForgeryToken()
<div class="row">
#Html.LabelFor(model => model.Name, new { #class = "control-label col-md-2" })
<div class="col-sm-4 col-md-4 col-lg-4">
#Html.Kendo().AutoCompleteFor(model => model.Name).HtmlAttributes(new { style = "width:100%" })
#Html.ValidationMessageFor(model => model.Name)
</div>
</div>
#{ var vdd = new ViewDataDictionary(ViewData) { TemplateInfo = new TemplateInfo() { HtmlFieldPrefix = "Address" } };}
#Html.Partial("_AddressPartial", Model.Address, #vdd)
// yada yada...you can imagine the rest of the very standard view
The partial view's model is Address and all hooks up.
When I post back to the server the Address member is properly filled with entered data from the partial view...
So now...in my partial view, I now load the js to call the async routine to load the IP GEO data for the user - so it pre-fills the city, province, country
Any example of an ajax call will suffice...mine calls an AddressControl, returns a partialview result and replaces a div named addressData with the updated partialview :
$(function() {
var urlGeoIeoip = "http://ip-api.com/json/?callback=?";
$.ajax({
url: urlGeoIeoip,
type: "GET",
dataType: "json",
timeout: 5000,
success: function (geoipdata) {
$.ajax({
url: "/getlocationdata/" + geoipdata.country + "/" + geoipdata.regionName + "/" + geoipdata.city,
type: "GET",
timeout: 5000,
success: function (data) {
//alert(data);
//var $form = $(this);
// var $target = $($form.attr("data-htci-target"));
var $newHtml = $(data);
//alert($target);
$("#addressData").replaceWith($newHtml);
$("#City").data("kendoComboBox").value(geoipdata.city);
$("#State").data("kendoComboBox").value(geoipdata.regionName);
$("#Country").data("kendoComboBox").value(geoipdata.country);
}
});
}
}).fail(function(xhr, status) {
if (status === "timeout") {
// log timeout here
}
});
});
All works great!
BUT
Now, when I post back to the user via the submit button, the Address child member of the parent class is null....
How do I get it to rebind the Address member of the parent class after return of the ajax call?
By generating your input fields in the partial view, the HTML helpers are unaware that your Address model is a property of your initial Client model, so it's generating HTML inputs like:
<input type="text" id="City" name="City" />
<input type="text" id="State" name="State" />
If your POST action method is accepting a Client model then the model binder will look for the properties City and State of the Client model, which don't exist.
You need your HTML input to look like:
<input type="text" id="Address_City" name="Address.City" />
<input type="text" id="Address_State" name="Address.State" />
Instead of using a partial for your Address fields, you should use an Editor Template which will then preserve the parent property as you need in this case.
#Html.EditorFor(x => x.Address)

How do I presist data from the view during EDIT GET to EDIT POST?

I have a dilemma that I hope someone can help me with. During the Edit Get stage of loading and updating a page before it is loaded, I store the checkboxes that are checked like this:
foreach (var course in courses.Select((x, i) => new { Data = x, Index = i }))
{
#: <td>
<br /><br /><br />
<input type="checkbox" id="checkbox" name="selectedCourses" value="#course.Data.CourseID"
#(Html.Raw(course.Data.Assigned ? "checked=\"checked\"" : "")) />
</td>
bool theNewString = course.Data.Assigned;
String a = theNewString.ToString();
assignedCourses.Add(a);
}
At the top of the view I defined the list to store the data like this so that I can be sent in the BeginForm:
#{ List<String> assignedCourses = new List<String>(); }
Then I try to send the list to the Edit POST like this:
#using (Html.BeginForm(new { assigned = assignedCourses }))
In my controller signature looks like this:
[HttpPost]
public ActionResult Edit(int id, List<String> assigned)
The list is loaded at the end of the get stage but the data in the list does not go through to Edit POST. My question is how do I get the list that I created at the end of the edit get stage to persist so that I can use it in my post?
Thanks for any ideas.
I'll try make this as simple as possible. So your Course model is something like this...
public class Course
{
public int Id { get; set; }
public string Name { get; set; }
public bool Assigned { get; set; }
}
...and you want to display some saved values on screen to edit. So starting at the controller, I've dummied some data and set one of the Assigned booleans to true so it is checked when the page loads.
public Controller Courses
{
public ActionResult Edit(int id)
{
var courses = new Course[] {
new Course() { Id = 1, Name = "maths", Assigned = true },
new Course() { Id = 2, Name = "english", Assigned = false },
new Course() { Id = 3, Name = "science", Assigned = false }
};
return View(courses);
}
Now, your page should expect a collection of these courses, so at the top of your page define the type that the View is expecting...
cshtml
#model IEnumerable<ExampleProject.Domain.Course>
...which you can then enumerate through in your View and create your checkboxes.
#using (Html.BeginForm("Edit", "Courses", FormMethod.Post))
{
#foreach(var item in Model)
{
<label for="#item.Id">#item.Name</label>
<input type="checkbox" name="courses" id="#item.Id" value="#item.Id" checked="#item.Assigned" />
}
<button type="submit">Save changes</button>
}
This will render the following html:
<label for="1">maths</label>
<input type="checkbox" name="courses" id="1" value="1" checked="checked">
<label for="2">english</label>
<input type="checkbox" name="courses" id="2" value="2">
<label for="3">science</label>
<input type="checkbox" name="courses" id="3" value="3">
Now you can check what you like and submit your form. In true http fashion your controller action will receive the values were checked on the View:
[HttpPost]
public ActionResult Courses(int id, int[] courses)
{
// courses will contain the values of the checkboxes that were checked
return RedirectToAction("Index"); // etc
}
Hopefully this helps. You can be a bit smarter and use the Html helpers for some more complicated binding (eg. Html.CheckBox, Html.CheckBoxFor) but this should get you going and it's clear to see what's going on.

Bind my form to a Model

I have a ViewModel which contains a List of my Model, like so:
public class OrderConfirm
{
public ICollection<DayBookQuoteLines> SalesLines { get; set; }
public ICollection<DayBookQuoteLines> LostLines { get; set; }
public string Currency { get; set; }
}
I then use this ViewModel in my View like so:
#model btn_intranet.Areas.DayBook.Models.ViewModels.OrderConfirm
#{
ViewBag.Title = "Daybook - Order Confirmation";
}
<h6>Sales Lines</h6>
<div id="SalesOrders">
#using (Ajax.BeginForm("ConfirmSalesOrder", new AjaxOptions()
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "SalesOrders",
OnBegin = "SalesOrderConfirm"
}))
{
#foreach(var item in Model.SalesLines)
{
<p>#item.ItemName</p>
<p>#item.Qty</p>
#* Other Properties *#
}
<input type="submit" value="Submit Sales Order" />
}
</div>
<h6>Lost Lines</h6>
<div id="LostOrders">
#using (Ajax.BeginForm("ConfirmLostOrder", new AjaxOptions()
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "LostOrders",
OnBegin = "LostOrderConfirm"
}))
{
#foreach(var item in Model.SalesLines)
{
<p>#item.ItemName</p>
<p>#item.Qty</p>
#* Other Properties *#
}
<input type="submit" value="Submit Lost Order" />
}
</div>
The problem is, in my [HttpPost] actions, both ConfirmSalesOrder and ConfirmLostOrder. The value of my Model passed as a parameter is null:
[HttpPost]
public ActionResult ConfirmSalesOrder(List<DayBookQuoteLines> quoteLines)
{
// Process order...
return PartialView("Sales/_ConfirmSalesOrder");
}
so quoteLines is null. How can I bind the form to my model?
You don't have any input field in your form that will send the values to the server. You are only displaying them. That's why they are null when you submit the form => nothing is sent to the server.
But if inside this form the user is not supposed to modify any of the values all you need to do is to pass an id to the controller action that will allow you to fetch the model from the exact same location from which you fetched it in your GET action that rendered this form.
In this case your action will look like this:
[HttpPost]
public ActionResult ConfirmSalesOrder(int id)
{
List<DayBookQuoteLines> quoteLines = ... fetch them the same way as in your GET action
// Process order...
return PartialView("Sales/_ConfirmSalesOrder");
}
If on the other hand the user is supposed to modify the values in the form you need to provide him with the necessary input fields: things like textboxes, checkboxes, radio buttons, dropdownlists, textereas, ... And in order to generate proper names for those input fields I would recommend you using editor templates instead of writing foreach loops in your views.
UPDATE:
Seems like the user is not supposed to edit the data so there are no corresponding input fields. In this case in order to preserve the model you could during the AJAX request you could replace the Ajax.BeginForm with a normal Html.BeginForm an then manually wire up the AJAX request with jQuery. The advantage of this approach is that now you have far more control and you could for example send the entire model as a JSON request. To do this you could store the model as a javascript encoded variable inside the view:
<script type="text/javascript">
var model = #Html.Raw(Json.Encode(Model));
</script>
and then AJAXify the form:
$('#formId').submit(function() {
$.ajax({
url: this.action,
type: this.method,
contentType: 'application/json',
data: JSON.stringify({ quoteLines: model }),
success: function(result) {
$('#someTargetIdToUpdate').html(result);
}
});
return false;
});

mvc3 how do I clear the submitted form values

I am new to asp .net mvc3. I am trying to create a failrly simple blog comments section.
I have a CommentsViewModel
public class CommentsViewModel
{
public CommentModel NewComment { get; set; }
public IList<CommentModel> CommentsList { get; set; }
}
The corresponding view is like
<div id="CommentsArea">
#Html.Partial("CommentsList", Model.CommentsList)
</div>
#using (Ajax.BeginForm("Create",
"Comment",
new { id = Model.NewComment.detailsId, comment = Model.NewComment },
new AjaxOptions { UpdateTargetId = "CommentsArea" ,
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace}))
{
<div class="display-label">Add Comment</div>
<div class="display-field">
#Html.EditorFor(model => Model.NewComment.Body)
</div>
<input type="submit" value="Post" />
}
Now when user enters Post button I want the "CommentsArea" to be updated with the new comments list and also the form values to be cleared with empty text.
Here is the Post method:
[HttpPost]
public ActionResult Create(int id, CommentModel newcomment)
{
var newsItem = m_db.NewsList.Single(news => news.Id == id);
if (!string.IsNullOrWhiteSpace(newcomment.Body))
{
newcomment.detailsId = id;
newsItem.Comments.Add(newcomment);
m_db.SaveChanges();
}
return PartialView("CommentsList", newsItem.Comments);
}
Now when user clicks Post button the list gets updated properly,
but the form values are not cleared. i.e. if I posted a comment "New Comments", the comments list gets updated with "New Comments", but that text remains inside the edit box of the form.
How do I clear that text?
just call a js function on success of form submit.
#using (Ajax.BeginForm("Create",
"Comment",
new { id = Model.NewComment.detailsId, comment = Model.NewComment },
new AjaxOptions { OnSuccess="ClearInput", HttpMethod = "Post",}))
on js function render create view again
function ClearInput(){
//call action for render create view
$.ajax({})
}

Create RouteValueDictionary on server and use in aspx?

I am tring to pass a RouteValueDictionary to my aspx so that I can use it as the parameters for an Ajax.BeginForm method. I load it up like so:
RouteValues = new System.Web.Routing.RouteValueDictionary();
RouteValues.Add("FindingId", thisFinding.Id);
RouteValues.Add("ReportId", thisFinding.ReportSection.ReportId);
and then add it to my model without issue. When I put it as the parameter to the BeginForm method it renders the action as this:
/SolidWaste/Finding/LoadSection?Count=3&Keys=System.Collections.Generic.Dictionary%602%2BKeyCollection%5BSystem.String%2CSystem.Object%5D&Values=System.Collections.Generic.Dictionary%602%2BValueCollection%5BSystem.String%2CSystem.Object%5D
Here is the aspx code:
(Ajax.BeginForm(Model.FormModel.Action,
Model.FormModel.Controller,
Model.FormModel.RouteValues,
new AjaxOptions {
HttpMethod = "Post",
InsertionMode = System.Web.Mvc.Ajax.InsertionMode.Replace,
UpdateTargetId = "WindowContent",
}, new { id = FormId })) { %>
<input name="submit" type="submit" class="button" value="" style="float: right;"/>
<% } //End Form %>
Here is the View Model that represents Model.FormModel
public class FormViewModel {
public string Action { get; set; }
public string Controller { get; set; }
public string Method { get; set; }
public RouteValueDictionary RouteValues { get; set; }
}
Any idea why it is not serializing the RouteValueDictionary into the proper URL on the action? I would like to use an object here rather than build the RouteValues by hand with new { field = vale }
Ah, you are using the wrong overload. It's normal. The ASP.NET MVC team really made a mess out of this API. You gotta be careful which method you are invoking. Here's the overload that you need:
<% using (Ajax.BeginForm(
Model.FormModel.Action, // actionName
Model.FormModel.Controller, // controllerName
Model.FormModel.RouteValues, // routeValues
new AjaxOptions { // ajaxOptions
HttpMethod = "Post",
InsertionMode = System.Web.Mvc.Ajax.InsertionMode.Replace,
UpdateTargetId = "WindowContent",
},
new Dictionary<string, object> { { "id", FormId } }) // htmlAttributes
) { %>
<input name="submit" type="submit" class="button" value="" style="float: right;"/>
<% } %>
Notice the correct overload? You were using the one that was taking routeValues and htmlAttributes as anonymous objects, except that you was passing Model.FormModel.RouteValues as a RouteValueDictionary which basically crapped your overload.
Hit F12 while hovering the cursor over the BeginForm and if you are lucky enough and Intellisense works fine for you in Razor views (which rarely happens) you will get redirected to the method you are actually invoking and realize your mistake.

Resources