Trouble with Knockout JSON Model parsing MVC 4 Controller - c#

So I have a ViewModel:
public class PrelimViewModel
{
public int? PrelimId { get; set; }
public int JobId { get; set; }
public string Code { get; set; }
public string Description { get; set; }
public string Comment { get; set; }
public string Unit { get; set; }
public int? Qty { get; set; }
public decimal? BidPrice { get; set; }
public bool Accepted { get; set; }
public int? OriginalPrelimId { get; set; }
public string Option { get; set; }
public List<RefCodeViewModel> Codes { get; set; }
public List<UnitViewModel> Units { get; set; }
public List<OptionLetterViewModel> Options { get; set; }
}
A GetPrelim controller method that returns List<PrelimViewModel>
A ko.mapper of the List of PrelimViewModel client side:
viewModel = ko.mapping.fromJS({ Prelims: data });
ko.applyBindings(viewModel);
Do some work, ready to save:
function savePrelims(elem) {
var $form = $(elem).parents('form');
$.ajax({
url: $form.attr('action'),
type: "POST",
data: ko.toJSON(viewModel),
datatype: "json",
contentType: "application/json charset=utf-8",
success: function(data) { toastr.success('Options Saved!'); },
error: function(data) { }
});
}
And I cannot get my MVC Method to parse the JSON:
public void AddPrelims(List<PrelimViewModel> Prelims)

You have wrapped your list into the Prelims property in your KO viewmodel, but on the server side you are expecting just a list not with an object which has the list in its Prelims property.
So to fix this you just need to send the list in your ajax request:
data: ko.toJSON(viewModel.Prelims()),
However you don't necessary need to wrap your list if you won't have any additional properties on your viewmodel, because you can just do:
viewModel = ko.mapping.fromJS(data);
ko.applyBindings(viewModel);
And then in your view you can bind to $data which is refering the current viewmodel which will be your array:
<div data-bind="foreach: $data">
...
</div>
And in this case you don't have to change your ajax call and data: ko.toJSON(viewModel), should work fine.
However this foreach: $data is kinda strange and it is not the best solution so you are probably better if you stick to your original approach with ko.mapping.fromJS({ Prelims: data }); and sending the correct data back to your controller.

Related

MVC ajax POST info about ApplicationUser

I have an entity that consists of ApllicationUser as a foreign Key:
public class Trades
{
public int ID { get; set; }
public double Price { get; set; }
public double Volume { get; set; }
public string InstrumentName { get; set; }
public ApplicationUser User { get; set; }
}
Then i try to post a trade using AJAX.
var tradeData = {
"Price": 1,
"Volume": 1,
"InstrumentName": "instrumentName",
"User": "#User.Identity.Name"
};
$.ajax({
url: "/api/TradesAPI/",
method: "POST",
data: JSON.stringify(tradeData),
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function () {
alert('executed!');
},
error: function (error) {
alert("Transacion has not been executed");
}
});
Unfortunetely ApplicationUser is not being serialised to ApplicationUSer as it is posted a string. What have I done wrong? Thanks for any help in advance.
If we have a class "A" that contains a reference to "B" and this "B" has also a reference to "A" (even if not direct), the proccess of serialization doesn't work. It's like an "infinite loop".
I suggest you change the ApplicationUser(type of User) to string and use it to get the model (on code-behind), if you need it.
If you need to get the user from within the controller, use the User property of Controller.
If you need it from the view, would populate what you specifically need in the ViewData, or you could just call User.
Ex. #User.Identity.Name
Thank you Indrit Kello. I changed my model so I have
public class Trades
{
public int ID { get; set; }
public double Price { get; set; }
public double Volume { get; set; }
public string InstrumentName { get; set; }
public string UserId { get; set; }
}
I decided to take info about user on server in API controller insted of taking data about User in a View.
public void CreateTradeAPI(Trades trade)
{
trade.UserID =User.Identity.Name;
_context.UsersTrades.Add(trade);
_context.SaveChanges();
}
And I have what i wanted :)

Issue while sharing the same model with multiple partial views

I am facing an issue while sharing the same model between a view and its multiple partial views.
I have a main view MainView which has its own model MainViewModel. In this MainView, I have a few controls which are bound to properties in the MainViewModel.
On a button click I am opening a partial view from this MainView. Say SubView1. It is a partial view and it consists of several controls which are bound to the properties in MainViewModel. At some point user enters some values in this partial view SubView1 and clicks on a button to submit the data. During this time, I am posting the data to the controller like this :
$.ajax({
type: "POST",
url: "/MainViewController/SomeAction",
data: JSON.stringify({ dataObj: dataArray }),
contentType: "application/json; charset=utf-8",
dataType: "json",
async: true,
success: function (msg) {
ServiceSucceeded(msg);
},
error: function () {
return "error";
}
});
SomeAction Code :
public void SomeAction(List<ModelClass> dataObj)
{
if(dataObj != null)
{
}
}
My doubt is that, since the controls in this partial view are already bound to the MainViewModel properties, do I still need to pass it using json like this? Or can the data be directly accessed from the MainViewModel during a post method? I tried to pass the model to the post method, but its data remains as null.
My MainViewModel class :
private EnvironmentVariableTarget m_Markers;
private List<SelectListItem> startLocation = new List<SelectListItem>();
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public string JobId { get; set; }
public string TaskId { get; set; }
public string TrajName { get; set; }
public int UserId { get; set; }
public DateTime StartPeriod { get; set; }
public DateTime EndPeriod { get; set; }
public int Aggr { get; set; }
public string MailId { get; set; }
public string StartLocation { get; set; }
public string EndLocation { get; set; }
public string lblGridHeaderTask { get; set; }
public string lblGridHeaderTraj { get; set; }
public string lblGridAggr { get; set; }
public string lblGridStartDate { get; set; }
public string lblGridEndDate { get; set; }
public int StartLocId { get; set; }
public int EndLocaId { get; set; }
public MySqlConnection databaseConnectionObj;
private MySqlCommand sqlCommandObj;
private Logger m_Logger;
These are the bound properties which I need :
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public string TrajName { get; set; }
When user clicks on add to list, I am adding to javascript array like this :
var obj = { TaskId: ccount, TrajName: $('#drpTraj').find(":selected").text(), StartTime: $('#txtStartTime').val(), EndTime: $('#txtEndTime').val(), Aggr: $('#drpAggrInterval').find(":selected").text() }
dataArray.push(obj)
I am keeping this array in js and when user clicks submit I am passing the entire array back to the controller. My question is at this point, I am getting the control's value. I am asking whether I can get the bound value at this time.
ie the controls drpTraj, txtStartTime and drpAggrInterval are already bound to viewmodel properties.
My questions are :
Is there any other way to tackle this scenario?
If I want to pass one more data which is not bound to the viewmodel, then how to pass that?
If databinding is not used, then is this the way to pass data ie using JSON?
Check Below Code for passing model data through JSON :
//Your Master Model Properties
public partial class YourMasterModel
{
public List<YourModel> YourMasterModelList{ get; set; }
public YourModel YourModel{ get; set; }
}
//Your Model Properties
public partial class YourModel
{
public int Id { get; set; }
public string Param1 { get; set; }
public string Param2 { get; set; }
public int[] SelectedListOptions { get; set; }
}
//Your Ajax Call along with Your Model
$("#Addbtn").click(function () {
var YourModel = {
"Id": $("#hdnId").val(),
"Param1": $("#Param1").val(),
"Param2": $("#Param2").val()
};
var YourMasterModel = {
"YourMasterModelList": //You have to create a list of YourModel through for loop and stored into a list variable and pass this to here
"YourModel": YourModel
};
$.ajax(
{
url: '/MainViewController/SomeAction/',
type: "Post",
async: false,
dataType: "html",
data: JSON.stringify(YourMasterModel),
contentType: "application/json;charset=utf-8",
success: function (result) {
$("#YourResultDiv").html("");
}
});
});
//Your Action with your model
/// <summary>
/// Add Data
/// </summary>
/// <param name="YourModel"></param>
/// <returns></returns>
[HttpPost]
public ActionResult AddDataWithModel(YourMasterModel objYourMasterModel)
{
//Here you will get the list of yourmodel data
var listofdata=objYourMasterModel.YourMasterModelList;
return PartialView("_YourPartialView");
}
Hope this will help you !!
If you want to pass parameter into post method use below technique:
#using (Ajax.BeginForm("action", "controller", null, new AjaxOptions() { OnSuccess = "" }, new { #class = "form-horizontal", role = "form", id = "id" }))
{
//put partial view code into the these brackets
}
If you want to do ajax, then you need to pass data into data:
// all columnname same name as data model of action
data: {
"columnname1": "John",
"columnname2": "Smith",
"columnname2": "man",
"columnname3": 32
}

Pass custom model *with List<CustClass>* through ajax call

I am having a bit of trouble passing my json string to the jsonResult within my controller. All the first-level variables come in fine except for the List<CustClass> which always returns a default empty list when it should be filled with the list of objects (List<>) I passed in.
The ajax call that looks along the lines of:
var model = {
Id: id,
Name: name,
Items: [{
Name: itemName[0],
Color: itemColor[0]
},{
Name: itemName[1],
Color: itemColor[2]
}]
};
$.ajax({
url: "/#path",
type: "POST",
data: JSON.stringify(model),
dataType: "json",
contentType: "application/json; charset=utf-8",
cache: false,
traditional: true
});
With my C# model looking along the lines of
public class MyModel
{
public int Id { get; set; }
public string Name { get; set; }
public class Item {
public string Name { get; set; }
public string Color { get; set; }
}
public List<Item> Items = new List<Item>();
}
And the result:
[HttpPost]
public JsonResult MyResult(MyModel model)
{
// Do Stuff
}
What am I doing wrong here? Is this even possible to do?
Dont instantiate your list to map it properly. Since binding of model takes place after instantiation of the class.
public class MyModel
{
public int Id { get; set; }
public string Name { get; set; }
public class Item {
public string Name { get; set; }
public string Color { get; set; }
}
public List<Item> Items {get; set;}
}

Server not receiving JSON

I have the following viewModel:
public class ProfileLocalizationViewModel
{
public ProfileViewModel Profile { get; set; }
public virtual string LanguageCode { get; set; }
public string Description { get; set; }
}
with the Profile object looking like:
public class ProfileViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsOutlet { get; set; }
public bool IsWholesaler { get; set; }
public bool IsProducer { get; set; }
public List<ProfileLocalizationViewModel> Localizations { get; set; }
}
From the client, I'm sending the following JSON:
{"Profile":{"Id":-1,"Name":"New Profiledsa","IsOutlet":false,"IsWholesaler":false,"IsProducer":false,"Localizations":null},"LanguageCode":"en","Description":"Description for selected language","__ko_mapping__":{"ignore":[],"include":["_destroy"],"copy":[],"observe":[],"mappedProperties":{"Profile.Id":true,"Profile.Name":true,"Profile.IsOutlet":true,"Profile.IsWholesaler":true,"Profile.IsProducer":true,"Profile.Localizations":true,"Profile":true,"LanguageCode":true,"Description":true},"copiedProperties":{}}}
Which gets parsed by Chrome like:
And on the server, when I try to receive a ProfileLocalizationViewModel, the values received are all null:
Any idea why this happens? Any advice greatly appreciated.
Client ajax call:
self.saveProfile = function (model, event) {
model.ItemForEditing.LanguageCode = self.SelectedLanguage.Code().toLowerCase();
var preview = ko.toJSON(model.ItemForEditing);
if (validateForm()) {
$.ajax({
type: "POST",
url: urlSaveProfile,
data: ko.toJSON(model.ItemForEditing),
contentType: 'application/json',
async: true,
beforeSend: function ()
success: function (result) {
// Handle the response here.
self.pushProfile(ko.mapping.fromJS(result.Data));
addContainer.modal('hide');
}
});
}
};
And inside preview, right before the call, there's the JSON...

ASP.NET MVC Project: RESTful API method with complex input parameters

I am new to designing API's, and I have a situation in ASP.NET MVC.
In my domain system, I have different concepts, such as an Invoice. I want to create a REST API, where it is possible to:
Create
Update
Delete
Select (based on different elements)
But, for instance, when creating a new object, I need a big set of parameters (see an example viewmodel below).
If I expect a path such as this:
POST - /api/invoice/create
How would I go around and accept form data?
My best guess is to make an APIController, and then accept the InvoiceViewModel as the only parameter. As it is an API Controller, I assume it accepts JSON by default.
Then I have the following question(s):
In jQuery, how would I build a JSON object to "satisfy" this InvoiceViewModel?
Is this the best way to handle more complex products?
InvoiceViewModel:
public class InvoiceViewModel
{
public int Id { get; set; }
public string Comment { get; set; }
public InvoiceAddressViewModel CompanyInfo { get; set; }
public InvoiceAddressViewModel ReceiverInfo { get; set; }
public DateTime DateCreated { get; set; }
public List<InvoiceLineViewModel> Lines { get; set; }
public decimal Total { get; set; }
public decimal VatTotal { get; set; }
public decimal VatPercentage { get; set; }
public decimal TotalExVat { get; set; }
public InvoiceViewModel()
{
this.Lines = new List<InvoiceLineViewModel>();
}
}
public class InvoiceAddressViewModel
{
public string Name { get; set; }
public string Address { get; set; }
public string Company { get; set; }
public string VatNumber { get; set; }
public string Country { get; set; }
public string ZipCode { get; set; }
public string City { get; set; }
}
public class InvoiceLineViewModel
{
public string Title { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
}
There is a default JsonValueProviderFactory for the Asp.net-mvc 3 framework, as long as your JSON data posted to the Action matches the Model it should bind the data correctly.
So something like this:
var requestData = {
Id: "1",
Comment: "The quick brown fox",
CompanyInfo: {
Name: "etc."
}
};
$.ajax({
url: '/api/invoice/create',
type: 'POST',
data: JSON.stringify(requestData),
dataType: 'json',
contentType: 'application/json; charset=utf-8',
error: function (xhr) {
alert('Error: ' + xhr.statusText);
},
success: function (result) {
alert('success');
}
});
Should work just fine, all the data should be bound correctly, just match the JSON property names with the Model names.(they must match)
The best way to get your model to match is to simply serialize your Model in your view to JSON, then you know it is correct, and manipulate it to your hearts content.
var data = set(#Html.Raw(new JavaScriptSerializer().Serialize(Model)));
As for complexity, the sky is the limit you may (very unlikely) run into some scenarios where the default JsonValueProviderFactory for .net is not good enough, but if you do I would be suprised.
Just as a side note, this whole use-case works wonderfully with http://knockoutjs.com/.
Have fun.

Categories

Resources