knockoutjs submit with ko.utils.postJson issue - asp.net-mvc

I followed the http://blog.stevensanderson.com/2010/07/12/editing-a-variable-length-list-knockout-style/ article to submit data using ko.utils.postJson and navigate to a different view from the controller
I used ko.utils.postJson(location.href, {model: ko.toJson(viewModel)}); to submit the data but the model submitted to the server has empty properties.
ko.utils.postJson(location.href, {model: viewModel}); failed too.
The client viewModel has additional properties than the server model but I believe if it works with $ajax post method, it should work with KO post
It worked if I pass the model as under
ko.utils.postJson(location.href,
{model: {P1:this.p1(), P2:this.p2(), P3: this.p3()}});
Do I have to map each property before submission? Its also really confusing when to use () for viewModel properties
Server Code
[HttpPost]
public ActionResult SearchProperty([FromJson]MyModel model)
{
try
{
return View("XYZ", model);
}
catch (Exception e)
{
}
}

Knockout provides a utility function that will turn an object containing observables into a plain JavaScript object. The utility function is ko.toJS. So, if you did:
{ model: ko.toJS(viewModel) }
Then, it would handle unwrapping all of your observables.
Additionally, there is another function ko.toJSON that will do a ko.toJS and then do JSON.stringify on the result. This is useful when you really need JSON instead of a JavaScript object.

Related

MVC3 (Razor) Json Get deserialized data in the Controller

I need help again with Asp.Net MVC (Razor View Engine).
In my View (Index) I have
#model IEnumerable<Movie>
I want to pass the Model to the Controller: I stringify the model in this way:
<script type="text/javascript">
function postData(){
var urlact='#Url.Action("createDoc")';
var model ='#Html.Raw(Json.Encode(Model));
$.ajax({
data: JSON.stringify(model),
type:"POST",
url:urlact,
datatype:"json",
contentType:"application/json; charset=utf-8"
});
}
</script>
Everything seems to work, cause I know the stringified data is:
'[{"ID":1,"Title":"The Lord of the Rings: The Fellowship of the Ring","ReleaseDate":"\/Date(1007938800000)\/","Genre":"Fantasy","Price":93000000.00},{"ID":2,"Title":"The Lord of the Rings: The Two Towers","ReleaseDate":"\/Date(1039042800000)\/","Genre":"Fantasy","Price":94000000.00},{"ID":3,"Title":"The Lord of the Rings: The Return of the King","ReleaseDate":"\/Date(1070233200000)\/","Genre":"Fantasy","Price":94000000.00}]';
The problem is: in Controller, methodName "createDoc" (as declared in the script) I cannot access to the stringified data.
Following some samples founded on the web, my method is something like this:
[HttpPost]
public ActionResult createDoc(IEnumerable<Movie> movies)
{
//...using movies list
return View();
}
Why can't I access to the stringified data? How can I do it, is there some method to call to deserialize the model in the Controller method?
Also, can I use the serialize() method instead of the stringify() one? If so, what's the syntax, View & Controller side?
Thank you.
You've already got stringified data in your JavaScript variable model. You only need to call JSON.stringify on objects which aren't strings.
If you want to post the data to your action without modifying model, just pass in model without the JSON.stringify and the ModelBinder will take care of deserializing it to IEnumerable<Movie> for you.
If you want to use model as something other than a string, you'll want to call JSON.parse on the string. In other words:
var model = JSON.parse('#Html.Raw(Json.Encode(Model))');
Then, you'd want to keep your JSON.stringify call.
Finally, stringify is a method on a browser-specific object JSON, whereas serialize is a method on the ASP.NET MVC-specific Json object. Two different worlds, same name.

How can I accept JSON requests from a Kendo UI data source in my MVC4 application?

I am using the Kendo UI grid in my MVC3 application and am quite pleased with it. I am using a Telerik provided example, excerpt below, to format the data posted by the grid's DataSource ally, and all is good. However, I don't want to have to rely on code like this. I would like to get Kendo and MVC talking without the 'translator', i.e. this code:
parameterMap: function(data, operation) {
var result = { };
for (var i = 0; i < data.models.length; i++) {
var model = data.models[i];
for (var member in model) {
result["models[" + i + "]." + member] = model[member];
}
}
return result;
}
This function is a 'hook' that allows me to manipulated data before Kendo ajaxes it out. By default, the Kendo DataSource sends content-type form-encoded, but not quite right for the MVC model binder. Without this, I can still use a FormCollection and do my own binding, but that is not on.
When I configure the DataSource to send JSON, and change my mapping function to look like this
parameterMap: function(data, operation) {
return JSON.stringify(data);
}
I get the following data being send in the request, but now I have no idea how to get MVC to bind to this. Right now my only hope is to grab Request.Params[0] in the action method, and deserialize this JSON myself.
I don't think I should have to write any code to get two HTTP endpoints to communicate properly using JSON in this day and age. What am I doing wrong, or, what should I be looking at on my side, i.e. the receiver of the requests. I would really prefer to minimize my intervention on the client side to maybe just the stringify call.
No idea if this is still a problem or not since this is a rather old question, but I had a scenario where I was shipping up json data to my controller and I had to give it a "hint" on what the name was so that model binding would work correctly:
public JsonResult GetDatByIds([Bind(Prefix="idList[]")]List<Guid> idList)
In my scenario, kendo was serializing my data and giving it a name of idList[] in the form post rather than just idList. Once I gave it the model binding hint, it worked like a charm. This might be the same for your scenario.

Asp.Net MVC Passing an object from Url.Action in View to Controller

While there appears to be similar questions I do not believe I found one where somebody was passing the entire model from view to controller, the closest I found was passing a data value in the model to the controller... which is not what I want to do...
I want to pass the model object to the applicable controller action result as a parameter
and do what I want to do with the data in the model object from within the controller...
code abbreviated...
in the view i am using Url.Action(string, string, object) to pass the controller method name, and the route to it as the 2nd parameter, and the entire model object as the 3rd parameter...
my third parameter is the problem, the Url.Action(string, string) over load works fine with the same values, so I don't have any problem getting to the controller action result method, with the values I am using...
view code snippet...
$('#ControllerActionResult').click(function (e) {
window.location = '<%: Url.Action("ControllerActionResult", TheRoute, new { pModel = Model } ) %>';
});
controller code snippet...
public ActionResult ControllerActionResult(object pModel)
{
}
My error is "CS1502: The best overloaded method match for 'System.Web.Mvc.UrlHelper.Action(string, string, object)' has some invalid arguments" and the window location line is highlighted...
Am I missing something obvious?
I don't think you can do that. Url is trying to build a url, not call the action method directly. You can pass individual key value pairs via the anonymous object, which Url can then use to build a link. Model binding can take care of putting the key value pairs into the incoming model for you.
Also, is TheRoute a string as well?
If you need a Url you don't have many alternatives. Either pass all the values to rebuild the model, or just pass a key value to retreive the model from the database again (or maybe session / viewdata / tempdata, if you're using that).
There might be several issues in your code. But I will answer what you want to know, how to send data to controller from js. You have to first send "model" in json format, possibly with jquery.ajax. For example,
$.ajax({
url: '#Url.Action("ControllerActionResult")',
type: 'POST',
data: JSON.stringify(model),
dataType: 'json',
processData: false,
contentType: 'application/json; charset=utf-8',
success: OnSuccess
});
In controller, you have to have a defined class for the "model" and that should be the parameter of your controller.
[HttpPost]
public ActionResult ControllerActionResult(Model model) {
if (Request.IsAjaxRequest()) {
//to do
}
}
Otherwise, MVC cannot find a right controller to call.
try with following code it works for me
Javascript:
var location ='#url,action(string ,obj)'; window.location=location;
Controller:
public ActionResult index(string obj){return view();}
hope this works for you.

Assign values to ViewData from client using MVC

I inherited an MVC app and am a true novice at it coming from an ASP.NET environment. My problem is I can't manage to move variable data between my partial views and controllers. In ASP.NET this was pretty straight forward, not the case in MVC. So the following code fires when a Tab is selected from the client but I need to capture the selectedTabIndex value from the client and pass it to the controller.
function onTabSelect(e) {
var selectedTabIndex = 0;
selectedTabIndex = $(e.item).index();
alert(selectedTabIndex);
}
I considered using the ViewData object but there doesn't appear to be a way to make perform this task of assignment from within the function. So the following code would seem to be a ridiculous task and it fails anyway. (Remember, I am an extreme novice at this)
function onTabSelect(e) {
var selectedTabIndex = 0;
<% =ViewData["selectedTabIndex"]%> = selectedTabIndex;
}
I also considered using cookies but that doesn't seem to be a practical method either. In ASP.NET I could access the client controls using the .find method but this is a steep learning curve for me.
What are my alternatives?
If different tabs can be selected by the user between Save operations, you might need to consider binding some kind of click function (using jQuery) to set the selectedTabIndex javascript variable. Alternatively, you could set a hidden input's value to the selected tab index.
In either case, if you need the value in your controller (to set ViewData, ViewBag, some model data, etc) when a Save operation is submitted, you could submit the data via $.ajax and return some JSON from your controller
$('#SaveButton').click(function() {
$.ajax({
url: '/Controller/Save',
type: 'POST',
// you might need to serialize additional data you want to save here
// but you could create any JSON object before calling $.ajax
data: {"selectedTabIndex": selectedTabIndex}, // data to POST
dataType: 'json', // this indicates the type of data returned from controller
success: function(data) {
// you didn't really describe how to programatically set a tab,
// so "setToTab" is a guess
$('#tabID').setToTab(data.selectedTabIndex);
}
});
}
And your controller might look something like
public ActionResult Save(int selectedTabIndex)
{
// again, you might need different parameters to complete your Save
return JsonResult(new { selectedTabIndex: selectedTabIndex });
}
Data is sent to a controller via a HTTP POST. Create a hidden input <input type="hidden" name="selectedTabIndex"/> and set the value with javascript prior to POST. The controller can extract this value from the Form parameters, or it can be autopopulated in the Action method if the method contains a parameter matching the input name.
This is a non-ajax alternative to the answer provided by David.

Request.Form not populated when using the HTTP PUT method (ASP.NET MVC)

I'm attempting to process the body of an HTTP PUT request, but it seems that the MVC engine (or perhaps the ASP.NET stack underpinning it) isn't automatically parsing & populating the request's Form collection with the body data.
This does work as expected when doing a POST.
Note that the request's InputStream property does contain the expected data, and obviously I can build my own key/value collection using that, however I would have expected PUT to work the same way as a POST.
Am I missing something here?
Example action method:
[AcceptVerbs(HttpVerbs.Put)]
public ActionResult Purchase(int id, FormCollection data)
{
// Do stuff with data, except the collection is empty (as is Request.Form)
}
Quote from the doc:
The Form collection retrieves the
values of form elements posted to the
HTTP request body, with a form using
the POST method.
So instead of using Request.Form I would recommend you writing a custom model class that will hold the request data and pass it as action parameter. The default model binder will automatically populate the properties from the key/values passed in the request stream:
[AcceptVerbs(HttpVerbs.Put)]
public ActionResult Purchase(MyCustomModel model)
{
// Do stuff with the model
}
Asp.net does not support PUT out of the box for custom requests. If you are using not the built in capabilities to generate the PUT url try adding X-HTTP-Method-Override with value of PUT in headers, form, or query string.

Resources