Reputation: 10479
I've got a model for my Page Creation:
public class PageCreateModel : ActionModel
{
public IList<KeyValuePair<Guid, string>> AvailablePermissions { get; set; }
public IList<KeyValuePair<Guid, string>> AvailableUsers { get; set; }
public IList<KeyValuePair<Guid, string>> AvailableGroups { get; set; }
public string Heading { get; set; }
public bool ShowHeading { get; set; }
public string Description { get; set; }
public ICollection<string> RouteUrls { get; set; }
public IList<KeyValuePair<Guid, string>> SelectedEditingPermissions { get; set; }
public IList<KeyValuePair<Guid, string>> SelectedEditingUsers { get; set; }
public IList<KeyValuePair<Guid, string>> SelectedEditingGroups { get; set; }
}
And I am using knockout mapping to convert this into a knockout model on page load:
var mappedModel = ko.mapping.fromJS(@Html.Raw(JsonConvert.SerializeObject(Model)));
Upon posting and using this code:
mappedModel.save = function(form) {
mappedModel.AvailablePermissions([]);
mappedModel.AvailableUsers([]);
mappedModel.AvailableGroups([]);
console.log(ko.toJS(mappedModel));
ko.utils.postJson('@Url.Action("Create", "Page")', { pageCreateModel: ko.toJS(mappedModel) });
};
It goes to this Action:
[HttpPost]
public ActionResult Create(PageCreateModel pageCreateModel)
{
return View(HydrateModel(pageCreateModel));
}
At this point my standard property values get posted find. But my collections (so far on my page I've only added SelectedEditingUsers
) have empty objects in the collection. For instance if on the page I add 2 users to the collection, and I post it. The MVC model's SelectedEditingUsers will have a collection of two, but those objects contain an Empty Guid and null for the value.
Here is the data being sent to the server from Chrome console:
pageCreateModel:{"AvailablePermissions":[],"AvailableUsers":[],"AvailableGroups":[],"Heading":"Test","ShowHeading":true,"Description":null,"RouteUrls":null,"SelectedEditingPermissions":[],"SelectedEditingUsers":[{"Key":"d81f409a-5fed-4330-8640-004bede4e6fb","Value":"User1"},{"Key":"5628ad64-567b-499d-bee1-cb6c3dc397eb","Value":"User2"}],"SelectedEditingGroups":[],"ActionSuccess":false,"ActionMessage":null,"ko_mapping":{"ignore":[],"include":["_destroy"],"copy":[],"observe":[],"mappedProperties":{"AvailablePermissions[0].Key":true,"AvailablePermissions[0].Value":true,"AvailablePermissions1.Key":true,"AvailablePermissions1.Value":true,"AvailablePermissions[2].Key":true,"AvailablePermissions[2].Value":true,"AvailablePermissions[3].Key":true,"AvailablePermissions[3].Value":true,"AvailablePermissions[4]...[etc]
How can I fix it so that the full model gets properly received by MVC? I need to use postJSON so I can use RedirectToAction and other similar things.
EDIT: Trying the AJAX call instead:
mappedModel.save = function(form) {
mappedModel.AvailablePermissions([]);
mappedModel.AvailableUsers([]);
mappedModel.AvailableGroups([]);
//mappedModel.__ko_mapping__([]);
//console.log(ko.toJS(mappedModel));
$.ajax({
url: '@Url.Action("Create", "Page")',
type: 'POST',
data: ko.toJSON(mappedModel),
contentType: 'application/json; charset=utf-8',
success: function(data) {
alert("Success!");
}
});
//ko.utils.postJson('@Url.Action("Create", "Page")', { pageCreateModel: ko.toJS(mappedModel) });
//ko.utils.postJson($("form")[0], { pageCreateModel: ko.toJS(mappedModel) });
//ko.utils.postJson('@Url.Action("Test", "Page")', { ko.toJS(mappedModel) });
};
And I still get the same problem:
And here is the POST from that:
{"AvailablePermissions":[],"AvailableUsers":[],"AvailableGroups":[],"Heading":"Test","ShowHeading":true,"Description":null,"RouteUrls":null,"SelectedEditingPermissions":[],"SelectedEditingUsers":[{"Key":"5628ad64-567b-499d-bee1-cb6c3dc397eb","Value":"User1"},{"Key":"6d7439aa-7728-4add-953f-28b306fff5d0","Value":"User2"}],"SelectedEditingGroups":[],"SelectedViewingPermissions":[],"SelectedViewingUsers":[],"SelectedViewingGroups":[],"ActionSuccess":false,"ActionMessage":null,"ko_mapping":{"ignore":[],"include":["_destroy"],"copy":[],"observe":[],"mappedProperties":{"AvailablePermissions[0].Key":true,"AvailablePermissions[0].Value":true,"AvailablePermissions1.Key":true,"AvailablePermissions1.Value":true,"AvailablePermissions[2].Key":true,"AvailablePermissions[2].Value":true,"AvailablePermissions[3].Key":true,...etc"
Upvotes: 2
Views: 987
Reputation: 1038720
ko.utils.postJson
doesn't set the Content-Type request header to application/json
. It will simply send the request as form encoded value. So use $.ajax
instead which allows you to specify the correct content type header:
mappedModel.save = function(form) {
mappedModel.AvailablePermissions([]);
mappedModel.AvailableUsers([]);
mappedModel.AvailableGroups([]);
$.ajax({
url: '@Url.Action("Create", "Page")',
type: 'POST',
data: ko.toJSON(mappedModel),
contentType: 'application/json; charset=utf-8',
success: function(data) {
...do something
}
});
};
The Content-Type request header is used by ASP.NET MVC when trying to read the request in order to know how is this request being serialized.
In addition to that you might want to replace the IList<KeyValuePair<Guid, string>>
types with IList<MyViewModel>
where MyViewModel
would be a view model class exposing two public properties: Key
and Value
. I am not sure that the JSON serializer would cope well with those KeyValuePair<Guid, string>
type.
Upvotes: 4