This time I faced with a problem of mapping the client side knockout.js' viewModel and the server side MVC's Model.
So the point is:
I have a knockout viewmodel and some methods in it.
For example one of them looks like this:
this.search = function () {
$.ajax({
url: "#Html.Raw(#Url.Action("Search"))",
type: 'POST',
beforeSend: function () {
},
complete: function () {
},
data: ko.toJSON(this),
cache: false,
contentType: false,
processData: false,
success: function (result) {
alert(result);
}
});
};
The knockout viewModel and the MVC's Model have the same fields, the only difference is the first letter of each field: the knockout 's field start with a small letter and the MVC's Model field start with a Capital letter, for example: someField - SomeField
So in my case I 'm trying to make a post to the server using the mentioned above search method. Before doing it I even check whether the viewModel has the proper data, and I successfully displayed this.startDate()
but when I put the breakpoint on the server side of my Search action I can see that I receive no data...
That's more than strange.
Recently I successfully implemented implemented a project where I used knockout and I did not have this problem.
I even put [Serializable] on top of the sever side Model but no result.
Please advice what could effect on this and how can I fix it?
Thanks.
The MVC model binder is case sensitive. Adjust one of the models to match the other, or use KO mappings.
Well, it's getting more and more weird...
I created the test knockout ViewModel (I'm using several VMs on a page):
var testViewModel = function () {
this.Name = ko.observable("");
this.testsearch = function () {
$.ajax({
url: "#Html.Raw(#Url.Action("Test"))",
type: 'POST',
beforeSend: function () {
},
complete: function () {
},
data: ko.toJSON(this),
cache: false,
contentType: false,
processData: false,
success: function (result) {
alert(result);
}
});
};
}
var testVM = new testViewModel();
ko.applyBindings(testVM, $("#testSection")[0]);
This is the HTML section:
[section id="testSection" style="background-color: white;"]
[input data-bind="value: Name" /]
[button type="button" class="btn btn-default" data-bind="click: testsearch"]Test[/button]
[/section]
This is my Server side Model:
[Serializable]
public class TestDataModel
{
public string Name { get; set; }
}
And this is my action :
public JsonResult Test(TestDataModel vm)
{
return Json("");
}
And In my action I receive null...
I'm completely stucked now...
Related
I have below code in Controller
// POST api/PersonalDetails
[ResponseType(typeof(PersonalDetails))]
[HttpPost]
public IHttpActionResult PostPersonalDetails(PersonalDetails personaldetails)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.PersonalDetails.Add(personaldetails);
db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = personaldetails.AutoId }, personaldetails);
}
and below code in view
<script type="text/javascript">
$("#btnAdd").click(function () {
var PersonalDetails = {
"FirstName": $("#FirstName").val(),
"LastName": $("#LastName").val(),
"Age": $("#Age").val(),
"Active": $("#Active").val()
};
$.ajax({
type: "POST",
url: 'http://localhost:28206/api/PersonalDetails/PostPersonalDetails',
data: JSON.stringify(PersonalDetails),
dataType: "json",
processData: true,
success: function (data, status, xhr) {
alert(status);
},
error: function (xhr) {
alert(xhr.responseText);
}
});
});
</script>
Now, when I am clicking on the button that fires up btnAdd click method. The controller PostPersonalDetails method is executing but personaldetails object is null. I am not able to retrieve values of the form.
How to get values of the PersonalDetails object formed in the click event.
Okay, I solved this problem and have written an article to help others.
Inserting record into database using ASP.NET MVC with Web API
Hope this will be helpful for others looking for similar kind of problem.
Thanks
I am trying to post an object from jquery to MVC controller. The object is passed successfully but all the properties are null (or false for bools).
fwiw, if I JSON.stringify myObect then it does not pass at all, theObect in the controller is null.
I am using MVC4, .net 4.5, jQuery 1.9.1
Any help appreciate.
jQuery function
var myObject =
{
Property1: true,
Proerty2: true
};
$.ajax({
type: 'POST',
url: '/myController/StartProcess/',
data: { theObject: myObject }
});
Controller
private async void StartProcess(myObject theObject)
{
// theObect can be seen successfully but property1 and property2 are false
// if I change them to strings they are null
...
}
Class
public class myObject
{
public bool Property1 { get; set; }
public bool Property2 { get; set; }
}
EDIT:
The solution was:
$.ajax({
type: 'POST',
url: '/myController/StartProcess/',
data: myObject
});
If anyone can shed some light as to why this works and nothing else does it would be greatly appreciated. It is not a great solution because I have to put all my parameters in myObject, I cannot pass any additional parameters using this technique. also curious as to why all the info I find online, including official tutorials, say to use data: JSON.Strinify(myObect) but for me this causes all the properties of myObject to be null (or false).
Thanks to Roar all the same, at least I can move past this.
Get this JSON library and stringify() the object like this:
$.ajax({
type: 'POST',
url: '/myController/StartProcess/',
data: JSON.stringify(myObject)
});
try this
$.ajax({
type: 'POST',
url: '/myController/StartProcess/',
data: myObject
});
If you tried to POST your object to an API controller, it would probably work. I had some trouble with this myself. If you're using jQuery, you need to specify that you're sending JSON so the MVC controller will correctly interpret the data.
You could try this:
$.ajax({
contentType: 'application/json',
data: { theObject: myObject },
dataType: 'json',
type: 'POST',
url: '/myController/StartProcess/'
});
Here's what can also make all properties null :
public ActionResult GetPaymentView(CardModel Card)
{
}
If the view is a collection of a model, when you pass a serialized form of one element in the collection to ajax call, the controller expects the same name instance as the class name. I assume that this is the same way without collection but never tried. In this code example we serialize one element of the collection
$.ajax({
url: '/Shipments/GetPaymentView',
type: 'POST',
data: $('#' + ID).serialize(),
success: { onSuccess(); },
error: { onError(jqXHR, textStatus, errorThrown); }
});
The reason why this happens is because the view model is a collection of the CardModel and the serialization is adding CardModel before each properties like this : CardModel.ID=foo&CardModel.bar The model binder takes it as granted and tries to match the instance sent with the property of the controller which it can't and instantiate a new instance for you hence all properties are nulls.
Try adding contentType: "application/json; charset=utf-8" to your ajax call.
OK, finally figured it out. Here is a full and proper solution showing how to pass additional parameters along with the object:
jQuery:
var myString= "my paramter";
var myObject =
{
Property1: true,
Property2: true
};
var DTO = { param1: myString, param2: myObject };
$.ajax({
contentType: "application/json; charset=utf-8",
type: 'POST',
url: 'myController/StartProcess',
data: JSON.stringify(DTO)
});
Controller:
[HttpPost] // notice this additional attribute!
private async void StartProcess(string param1, myObject param2)
{
// param2 parameters are all true! param1 shows correctly too.
...
}
Class
public class myObject
{
public bool Property1 { get; set; }
public bool Property2 { get; set; }
}
I need to display a Treeview in my MVC3 application. There will be a self referencing hierarchical table (Folders) and another table linked to it (Documents.) (So Folders can have N-subFolders and any folder/sub folder can have many documents.)
I have looked into using third party vendors such as Telerik, DJME and MVC Controls Toolkit. While all nice packages, I'm uneasy about the licences, and since i'm new to MVC (and programming in general,) I find their documentation lacking to get the right display working.
I've also looked at the heavily referenced blogs on TreeViews:
TreeViewHelper
and the Recursive Partial View
In addition to the other less referenced articles (The top 3 are also very informative):
http://tpeczek.com/2010/01/asynchronous-treeview-in-aspnet-mvc.html
http://mikehadlow.blogspot.com/2008/10/rendering-tree-view-using-mvc-framework.html
http://www.tek-tips.com/viewthread.cfm?qid=1637392&page=4
http://weblogs.asp.net/jigardesai/archive/2008/02/04/display-hierarchical-data-in-asp-net-mvc-framework.aspx
http://www.jigar.net/articles/viewhtmlcontent311.aspx
http://help.syncfusion.com/ug_82/ASP.NETMVCUI_Tools/CreatingATreeViewControl.html
I would like to use either the TreeViewHelper or the Recursive Partial View Method.
However, in the TreeViewHelper, I can't make it pull data from the second table (ie. I can only make it list the Files, but I'm not sure how to have it list the Documents for each File.)
For the Recursive Partial View, I'm still at a loss in how to convert this to MVC3 and also general implementation. I did find a post (forums.asp.net/t/1652809.aspx/1?treeview+with+mvc+3) that gives an explanation of how to convert a bit of it to MVC3, but i'm still unclear of what to do with it. I keep getting the error for the Partial view: Cannot implicitly Convert type 'void' to type 'object'
Like I said before I'm new to MVC3 and would like insight in which method would work best for my scenario and how to implement it.
In case anyone is wondering, the way I solved this problem was to use a recursive partial view. The problem I has having with it was that I didn't have the self referencing relationship set up in SQL/EF (I just had the ParentID field which wasn't linked to the Primary Key.) I also integrated jsTree as this has a lot of slick functionality such as search.
Like I said in the comment above, #Html.Action and #Html.Partial work instead of #Html.RenderAction and #Html.RenderPartial.
give a look to the edit/add/delete/node move templated TreeView of my Mvc Controls Toolkit here: http://mvccontrolstoolkit.codeplex.com/wikipage?title=TreeView
$(document).ready(function () {
BindChart();
});
function BindChart() {
$("#org").jOrgChart({
chartElement: '#chart',
dragAndDrop: true
});
}
$(".cardadd").live("click", function ()
{
var data = { id: 0 , ParentId:$(this).parent().data('cardid')};
OpenForminWindow('divfrmChartMember', 'divChartMember', 'frmChartMember', chart.ChartMember, data, '', 400, 1000);
});
$(".cardedit").live("click", function () {
var data = { id: $(this).parent().data('cardid')};
OpenForminWindow('divfrmChartMember', 'divChartMember', 'frmChartMember', chart.ChartMember, data, '', 400, 1000);
});
$(".cardremove").live("click", function () {
});
function OpenForminWindow(popupId, targetDivId, formid, url, data, callbackfunc, heigth, width) {
$.ajax({
type: "GET",
url: url,
data: data,
cache: false,
success: function (data) {
$('#' + targetDivId).html(data);
$('#' + formid).removeData('validator');
$('#' + formid).removeData('unobtrusiveValidation');
$('#' + formid).each(function () { $.data($(this)[0], 'validator', false); }); //enable to display the error messages
$.validator.unobtrusive.parse('#' + formid);
if (callbackfunc)
return callbackfunc();
}
});
$("#" + popupId).dialog({
modal: true,
height: heigth,
width: width,
beforeClose: function (event, ui) {
if (typeof refresh !== 'undefined' && refresh == true)
ReloadCurrentPage();
}
});
}
$('#frmChartMember').live('submit', function (e) {
SubmitAjaxForm($(this).attr('id'), chart.AddMember, ReloadChart);
e.preventDefault();
});
function SubmitAjaxForm(formId, url, callBack) {
$.ajax({
url: url,
type: 'post',
cache: false,
data: $('#' + formId).serialize(),
success: function (data) {
return callBack(data);
},
});
}
function ReloadChart(result) {
ClosePopup('divfrmChartMember');
$.ajax({
type: 'GET',
url: chart.ChartList,
cache: false,
success: function (result) {
$("#orgChart").html(result);
BindChart();
}
});
}
function ClosePopup(divid) {
$("#" + divid).dialog("close");
}
public class ChartController : Controller
{
//
// GET: /Chart/
ChartContext ctx = new ChartContext();
public ActionResult Index()
{
return View();
}
public ActionResult OrgChart()
{
return PartialView("_OrgChart", ctx.Cards.ToList());
}
public ActionResult ChartMember(int id, int? ParentId = null)
{
Card card = new Card();
if (id > 0)
card = ctx.Cards.Find(id);
else
card.ParentId = ParentId;
return PartialView("_ChartMember", card);
}
public ActionResult SaveMember(Card card)
{
if (card.id == 0)
ctx.Cards.Add(card);
else
ctx.Entry(card).State = System.Data.EntityState.Modified;
ctx.SaveChanges();
return Json(true, JsonRequestBehavior.AllowGet);
}
}
I am finally experimenting and trying to learn MVC after years of asp.net.
I am used to using asp.net AJAX PageMethods where you can pass an object that automagically gets parsed to whatever type the parameter is in that method.
Javascript:
PageMethods.AddPerson({First:"John",Last:"Doe"});
Code-Behind:
[WebMethod]
public static Result AddPerson(Person objPerson)
{
return Person.Save();
}
How would do this using MVC and jQuery?
Did just have to send strings and parse the json to object?
That depends on how complex your form data is going to be. Let's use a jQuery example:
$.ajax({
url: '\Persons\AddPerson', // PersonsController, AddPerson Action
data: { First: "John", Last: "Doe" },
type: 'POST',
success: function(data, status)
{
alert('Method called successfully!');
}
});
So we post two pieces of data. If the Person class has two properties called 'First' and 'Last', then the default ASP.NET MVC Model Binder should have no problems putting this form data into those properties (everything else will be defaulted).
Of course, you could always make a custom model binder for the Person type, and then you can take whatever form values you want and put them into any property at all, or call some other kind of logic.
I have a post that covers AJAX calls to ASP.NET MVC action methods. It covers the following combinations:
HTTP GET, POST
jQuery methods $.get, $.getJSON, $.post
Sending parameters to the action methods
Returning parameters (strings and JSON) from the action methods
Posting form data
Loading a MVC partial view via AJAX
AJAX calls to ASP.NET MVC action methods using jQuery
When you POST a form via ajax to an action method on your controller, the ModelBinder architecture kicks in to parse the posted form values into business objects for you. You can leverage modelbinding in a few different ways.
public ActionResult MyAction(MyObject obj)
{
}
In the above example, the modelbinder implicitly tries to create a MyObject from the information it received in the request.
public ActionResult MyAction(FormCollection stuff)
{
MyObject obj = new MyObject();
TryUpdateModel(obj);
}
Here we are explicitly trying to bind the posted form data to an object that we created. The ModelBinder will try to match the posted values to the properties of the object.
In either of these cases, you can query the ModelState object to see if there were any errors that occurred during translation of the posted values to the object.
For an introduction to model binding, see here.
For advanced modelbinding to lists and dictionaries, see Phil Haack's post.
You could do something like this:
var person = {};
person["First"] = $("#FirstName").val();
person["Last"] = $("#LastName").val();
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "/Admin/AddPerson",
data: JSON.stringify(person),
dataType: "json",
success: function(result) {
},
error: function(result) {
}
});
and then on your admin controller:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddRelease(Person p)
{
// Code to add person
}
The JSON.stringify method is available from here. You could also use a model rather than the Person object as a parameter that way you could handle all of your validation.
I guess I am a cheater and do the following:
$("#ProgressDialog").dialog({
autoOpen: false,
draggable: false,
modal: true,
resizable: false,
title: "Loading",
closeOnEscape: false//,
// open: function () { $(".ui-dialog-titlebar-close").hide(); } // Hide close button
});
$("form").live("submit", function (event) {
event.preventDefault();
var form = $(this);
$("#ProgressDialog").dialog("open");
$.ajax({
url: form.attr('action'),
type: "POST",
data: form.serialize(),//USE THIS to autoserialize!
success: function (data) {
$("#dialog").dialog({height:0});
},
error: function (jqXhr, textStatus, errorThrown) {
alert("Error '" + jqXhr.status + "' (textStatus: '" + textStatus + "', errorThrown: '" + errorThrown + "')");
},
complete: function () {
$("#ProgressDialog").dialog("close");
}
});
});
});
<div id="ProgressDialog" style="text-align: center; padding: 50px;">
<img src="#Url.Content("~/Content/ajax-loader.gif")" width="128" height="15" alt="Loading" />
</div>
In doing an auto-refresh using the following code, I assumed that when I do a post, the model will automatically sent to the controller:
$.ajax({
url: '<%=Url.Action("ModelPage")%>',
type: "POST",
//data: ??????
success: function(result) {
$("div#updatePane").html(result);
},
complete: function() {
$('form').onsubmit({ preventDefault: function() { } });
}
});
Every time there is a post, I need to increment the value attribute in the model:
public ActionResult Modelpage(MyModel model)
{
model.value = model.value + 1;
return PartialView("ModelPartialView", this.ViewData);
}
But the model is not passed to the controller when the page is posted with jQuery AJAX request. How can I send the model in the AJAX request?
The simple answer (in MVC 3 onwards, maybe even 2) is you don't have to do anything special.
As long as your JSON parameters match the model, MVC is smart enough to construct a new object from the parameters you give it. The parameters that aren't there are just defaulted.
For example, the Javascript:
var values =
{
"Name": "Chris",
"Color": "Green"
}
$.post("#Url.Action("Update")",values,function(data)
{
// do stuff;
});
The model:
public class UserModel
{
public string Name { get;set; }
public string Color { get;set; }
public IEnumerable<string> Contacts { get;set; }
}
The controller:
public ActionResult Update(UserModel model)
{
// do something with the model
return Json(new { success = true });
}
If you need to send the FULL model to the controller, you first need the model to be available to your javascript code.
In our app, we do this with an extension method:
public static class JsonExtensions
{
public static string ToJson(this Object obj)
{
return new JavaScriptSerializer().Serialize(obj);
}
}
On the view, we use it to render the model:
<script type="javascript">
var model = <%= Model.ToJson() %>
</script>
You can then pass the model variable into your $.ajax call.
I have an MVC page that submits JSON of selected values from a group of radio buttons.
I use:
var dataArray = $.makeArray($("input[type=radio]").serializeArray());
To make an array of their names and values. Then I convert it to JSON with:
var json = $.toJSON(dataArray)
and then post it with jQuery's ajax() to the MVC controller
$.ajax({
url: "/Rounding.aspx/Round/" + $("#OfferId").val(),
type: 'POST',
dataType: 'html',
data: json,
contentType: 'application/json; charset=utf-8',
beforeSend: doSubmitBeforeSend,
complete: doSubmitComplete,
success: doSubmitSuccess});
Which sends the data across as native JSON data.
You can then capture the response stream and de-serialize it into the native C#/VB.net object and manipulate it in your controller.
To automate this process in a lovely, low maintenance way, I advise reading this entry that spells out most of native, automatic JSON de-serialization quite well.
Match your JSON object to match your model and the linked process below should automatically deserialize the data into your controller. It's works wonderfully for me.
Article on MVC JSON deserialization
This can be done by building a javascript object to match your mvc model. The names of the javascript properties have to match exactly to the mvc model or else the autobind won't happen on the post. Once you have your model on the server side you can then manipulate it and store the data to the database.
I am achieving this either by a double click event on a grid row or click event on a button of some sort.
#model TestProject.Models.TestModel
<script>
function testButton_Click(){
var javaModel ={
ModelId: '#Model.TestId',
CreatedDate: '#Model.CreatedDate.ToShortDateString()',
TestDescription: '#Model.TestDescription',
//Here I am using a Kendo editor and I want to bind the text value to my javascript
//object. This may be different for you depending on what controls you use.
TestStatus: ($('#StatusTextBox'))[0].value,
TestType: '#Model.TestType'
}
//Now I did for some reason have some trouble passing the ENUM id of a Kendo ComboBox
//selected value. This puzzled me due to the conversion to Json object in the Ajax call.
//By parsing the Type to an int this worked.
javaModel.TestType = parseInt(javaModel.TestType);
$.ajax({
//This is where you want to post to.
url:'#Url.Action("TestModelUpdate","TestController")',
async:true,
type:"POST",
contentType: 'application/json',
dataType:"json",
data: JSON.stringify(javaModel)
});
}
</script>
//This is your controller action on the server, and it will autobind your values
//to the newTestModel on post.
[HttpPost]
public ActionResult TestModelUpdate(TestModel newTestModel)
{
TestModel.UpdateTestModel(newTestModel);
return //do some return action;
}
I think you need to explicitly pass the data attribute. One way to do this is to use the
data = $('#your-form-id').serialize();
This post may be helpful.
Post with jquery and ajax
Have a look at the doc here..
Ajax serialize
you can create a variable and send to ajax.
var m = { "Value": #Model.Value }
$.ajax({
url: '<%=Url.Action("ModelPage")%>',
type: "POST",
data: m,
success: function(result) {
$("div#updatePane").html(result);
},
complete: function() {
$('form').onsubmit({ preventDefault: function() { } });
}
});
All of model's field must bo ceated in m.
In ajax call mention-
data:MakeModel(),
use the below function to bind data to model
function MakeModel() {
var MyModel = {};
MyModel.value = $('#input element id').val() or your value;
return JSON.stringify(MyModel);
}
Attach [HttpPost] attribute to your controller action
on POST this data will get available