How to pass a object from ajax to the server in MVC? - asp.net-mvc

I've got two models, there are.
public class CreateAssignmentViewModel {
...
public List<CreateAssignmentSelectedItem> SelectedItems { get; set; }
}
public class CreateAssignmentSelectedItem {
...
}
Now I've got a view where contains CreateAssignmentViewModel, as you can see above this class contains a property where is a List<CreateAssignmentSelectedItem>
#model Contoso.MvcApplication.Models.Assignment.CreateAssignmentViewModel
#{
ViewBag.Title = "Create Assignment";
...
}
#using (Html.BeginForm()) {
...
}
Inside of the Html.BeginForm, I've got a partial view. And in it I've got a button using ajax where updates the partial view.
Look the following events. Where says data: I do not know what to enter to access only the property SelectedItems
var addQuestionToAssignmentContent = function (questionId)
{
$.ajax({
url: "/Assignment/AddItemToAssignmentContent",
type: "post",
data: { model: $(this).serialize() /* HERE I DON'T KNOW TO ACCESS THE */, itemId: questionId },
success: function (response) {
var $target = $("#assignmentContent");
var $newHtml = response;
$target.replaceWith($newHtml);
}
});
};
public ActionResult AddItemToAssignmentContent(List<CreateAssignmentSelectedItem> model, string itemId)
{
...
PartialView(..);
}
How can I do to pass only the object in the method?

First, give your form an ID:
#using (Html.BeginForm("actionName", "controllerName", FormMethod.Post, new{id = "frmUpdate"})) {
Second, change your code to be like this:
var f = $("#frmUpdate");
$.ajax({
url: f.attr('action'),
type: f.attr('method'),
data: f.serialize(),
//etc..
I use this in most cases and it works just nice. The data should automatically be bound to the model you have in your update action. So, for example... if you have a #model of type MyModel then in the update action it should look something like this:
[HttpPost]
public ActionResult Update(MyModel updatedModel)

Sometimes I work with a front end guy and he might not adhere to pass in the correct model, he might change the form fields or whatever. In this case I just let him serialize the form and pass it to the action an any way he wants.
I then use the FormCollection object to get the data I need.
Your json call
var addQuestionToAssignmentContent = function (questionId)
{
$.ajax({
url: "/Assignment/AddItemToAssignmentContent",
type: "post",
data: { model: $(this).serialize() /* HERE I DON'T KNOW TO ACCESS THE */, itemId: questionId },
success: function (response) {
var $target = $("#assignmentContent");
var $newHtml = response;
$target.replaceWith($newHtml);
}
});
};
Get a form collection object
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddItemToAssignmentContent(FormCollection collection)
{
vars someValue = collection.GetValue("somefield").AttemptedValue;
}
But if I would have control of front-end as you do then as Matt suggested you should use an pass a model;

Related

Submit MVC ListBoxFor values to controller

I have a multiselect ListBoxFor control as shown in mvc view
#using ExampleViewModel
#using (Html.BeginForm("SaveExample", "Example", FormMethod.Post, new { #id
= "exampleForm" }))
{
#Html.ListBoxFor(x => x.AssignedContainers, new
MultiSelectList(Model.RegisteredContainers, "ID", "Description", null),
new { #class = "fieldNoFocusRequiredListBox", #size = 15,
id="RegisteredContainers" })
}
View model code looks like this:
public class ExampleViewModel
{
public int[] AssignedContainers { get; set; }
public List<Container_Sizes> RegisteredContainers { get; set; }
}
Controller code:
public ActionResult SaveExample(ExampleViewModel model)
{
// code
return Json(true, JsonRequestBehavior.AllowGet);
}
I was able to bind the listbox with model property RegisteredContainers. I do some some jQuery validation and then submit the form via ajax like this:
function SaveProduct() {
if (!ValidateProductForm()) {
return;
}
$.ajax({
type: "POST",
data: $('#exampleForm').serialize(),
url: '/Example/SaveExample/',
success: function (result) {
},
error: function (jqXhr, error, errorThrown) {
}
});
}
When the break point hits the controller ExampleViewModel -> AssignedContainers is null. Please note that i used ICollection/IEnumerable/List for this property AssignedContainers but no luck. Also when i see $('#exampleForm').serialize() in debugger watch i see ".....&AssignedContainers=17" as there is one item in the list box but received null on controller.
Do i need any updates to model binder or what is going wrong here?

MVC:Why my view didn't change when I changed the model and return view(model)?

My model is called Student which has three properties:Id,Name,score. In my view I use model binding,and in my action I search student and return student information, but even I use ModelState.Clear() it looks like this code does not work,the view always show the student which id=0.
Model:
public class Student
{
public int Id{get;set;}
public string Name{get;set;}
public int Score{get;set;}
}
View:
#project.bll.Student
#Html.TextBoxFor(model=>model.Name)
#Html.TextBoxFor(model=>model.Score)
$.ajax({
url: "#Url.Action("GetStudent","Student")",
type: "post",
data: { "id": $("#Id").val() },//id is set to be 0 or 1 or 2
success: function (result) {
alert(result);
}});
Controller:
public ActionResult GetStudent(int id=0)
{
//ModelState.Clear();
return View(StudnetRepository.GetStudentById(id));
}
If you want to use a Model in your View, you must use the keywork #model at the start
so your View must be
#model YourNamespace.Student
#Html.TextBoxFor(model=>model.Name)
#Html.TextBoxFor(model=>model.Score)
<script>
$.ajax({
url: "#Url.Action("GetStudent","Student")",
type: "post",
data: { "id": $("#Id").val() },//id is set to be 0 or 1 or 2
success: function (result) {
alert(result);
}});
</script>
than controller must instantiate the model
public ActionResult GetStudent(int id=0)
{
var model = new Student();
//get the student with repository
//valorize the studend with model.Id, name etc
return View(model);
}

How to pass many forms to controller

In my project I have multiple forms on same page which I want to pass in one go to controller.
How to achieve that?
<script>
function onSaveButtonClicked() {
var form = $("#SaveForm").serialize();
var form2 = $("#SaveForm").serialize();
$.ajax({
url: '#Url.Action("Filter","SearcherEngine")',
type: 'post',
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify({ model: form, model2: form2 }),
cache: false,
success: function (result) {
alert(result);
},
error: function (xhr, ajaxOptions, thrownError) {
alert(thrownError);
}
});
};
[HttpPost]
public ActionResult Filter(MyViewMOdel model,MyViewModel2 model2)
{
}
What makes this complex is the different view models per form. As a result, you cannot simply use an array and map to a list of a common class.
Keep in mind that model binding is done based on the structure of the object passed (posted in this case). So what you need to do is create a model that can hold the structure of what you want to pass in c#, and then also create that same structure in javascript to pass in.
public class ViewModelSet
{
public MyViewModel model1 { get; set; }
public MyViewModel1 model2 { get; set; }
}
Now you need to recreate this structure with the exact same naming for properties in javascript
var form1 = ...;
var form2 = ...;
var modelSet = {};
modelSet.model1 = form1;
modelSet.model2 = form2;
Next pass this in (only the name of the parameter must match the name of the expected parameter server side)
data: { model : modelSet },
And expect this to be passed server side
public ActionResult FilterNCTS(ViewModelSet model)
{
//Now you should be able to have access to nested models
// TODO: work with model.model1
...
}
I joined both models in one, and wrapped partial views around one form.
class MyModel
{
...
}
#model MyModel;
#using(Html.BeginForm())
{
Html.RenderPartial("Path",Model);
Html.RenderPartial("Path",Model);
}

MVC: Result from JSON Automatically fill View

I am stuck in publishing the result from JSON so left the success portion blank.
View
#model MvcApplication2.Models.About
#{
ViewBag.Title = "About";
}
<p> #Html.DisplayFor(m=>m.test) </p>
<p> #Html.DisplayFor(m=>m.test1) </p>
Model
public class About
{
public string test { get; set; }
public string test1 { get; set; }
}
Controller
public class HomeController : Controller
{
public JsonResult About()
{
ViewBag.Message = "Your app description page.";
About ab = new About()
{
test = "a",
test1 = "b"
};
return Json(ab, JsonRequestBehavior.AllowGet);
}
}
JQuery in external file
$(document).ready(function () {
var itemName = "#btn-about";
$(itemName).click(function () {
$.ajax({
type: 'GET',
dataType: 'Json',
url: '/Home/About',
success: function (data) {
var option = '';
},
error: function (xhr, ajaxOption, thorwnError) {
console.log("Error")
},
processData: false,
async: true
});
});
});
=> I am a bit confused now. Altough I get a result in JSON format using AJAX, I want to publish it in this View 'About'. The View already have #model defined, so as soon as I get the result, I want the view to load it automatically as I don't think its a good option to create html controls in Javascript.
=> Is it possible or do I have to fill control one by one.
=> I am new in to MVC, so could you let me know any good suggestion.
Controller:
public ActionResult About()
{
var model = repo.GetModel();
return PartialViewResult("about", model);
}
jQuery:
$.ajax("/Controller/About/", {
type: "GET",
success: function (view) {
$("#aboutDiv").html(view);
}
});
In Main View:
<div id="aboutDiv"><div>
You need to give your elements some id or class that will allow you to interact with them easily on the client. Then, when you get your response, take the values from the JSON data and update the elements (using the id/class to find it) with the new value. I'm assuming you don't have any special template defined for your strings, adjust the selectors in the code as necessary to account for it if you do.
View
<p class="testDisplay"> #Html.DisplayFor(m=>m.test) </p>
<p class="test1Display"> #Html.DisplayFor(m=>m.test1) </p>
Client code
$(document).ready(function () {
var itemName = "#btn-about";
$(itemName).click(function () {
$.ajax({
type: 'GET',
dataType: 'Json',
url: '/Home/About',
success: function (data) {
$('.testDisplay').html(data.test);
$('.test1Display').html(data.test1);
},
error: function (xhr, ajaxOption, thorwnError) {
console.log("Error")
},
processData: false,
async: true
});
});
});
Instead of returning the data you will have to return the view as string and the use jquery to replace the result.
Controller:
public JsonResult About()
{
var model = // Your Model
return Json((RenderRazorViewToString("ViewNameYouWantToReturn", model)), JsonRequestBehavior.AllowGet);
}
[NonAction]
public string RenderRazorViewToString(string viewName, object model)
{
ViewData.Model = model;
using (var sw = new StringWriter())
{
var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
var viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
viewResult.View.Render(viewContext, sw);
viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);
return sw.GetStringBuilder().ToString();
}
}
Then using jquery you can replace the result in container for eg: div as follows:
$.ajax({
type: 'GET',
dataType: 'Json',
url: '/Home/About',
success: function (result) {
$("#divId").replaceWith(result);
},

MVC ViewModel issue

I have a viewmodel that has 2 properties, first property is a Model object and the second property is a List . In my View i have 2 parts.
First part populates the data for the first object, Firstname,lastname,email and some other stuff.
The second part of my view is a webgrid that a user adds multiple address.
Now what is my problem, i have a JSON action on my controller that gets the data from the form, adds them to the viewmodel List property, but nothing happens.
I checked that the data is coming from the view, added to the viewmodel but each time the viewmodel is empty.
[Authorize]
public JsonResult addAddress(Address addr, CustomerViewModel model)
{
if (model.CAddress== null)
model.CAddress= new List<Address>();
model.CAddress.Add(addr);
return Json(model, JsonRequestBehavior.AllowGet);
}
I am using Javascript :
function AddAddress()
{
var addID = $("#lstID option:selected").val();
var addName = $("#lstAddName option:selected").text();
var Address =
{
addID : addID.toString(),
addName : addName.toString()
};
$.ajax({
type: "POST",
url: "#Url.Action("addAddress","Customer")",
dataType: "json", contentType: "application/json; charset=utf-8",
data: JSON.stringify(Address),
success: function (data) {} }); };
Alright, start by writing a real view model, not some hybrids:
public class CustomerViewModel
{
public List<AddressViewModel> Addresses { get; set; }
... some other properties you already had
}
public class AddressViewModel
{
public string Id { get; set; }
public string Name { get; set; }
}
then adapt your controller action to take your real view model, and not some hybrids and mixtures between view models and domain models:
[Authorize]
[HttpPost]
public ActionResult AddAddress(CustomerViewModel model)
{
return Json(model);
}
and finally adapt your AJAX call:
function AddAddress() {
$.ajax({
url: '#Url.Action("AddAddress", "Customer")',
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({
addresses: [
{
id : $('#lstID').val(),
name : $('#lstAddName option:selected').text()
}
],
someOtherPropertyOnYourViewModel: 'some other value'
}),
success: function (data) {
}
});
}

Resources