I am trying to create a function in an Angular controller which passes an array of TestExpense objects to a C# API which will then handle inserting them into a database. Currently, the API is only configured to do one at a time.
The objects of the array, $scope.TestExpenses, I wish to pass are represented by the following constructor :
function TestExpense(employeeId, expenseDate, taskId, expenseTypeId,
billingCategory, notes, amount, lastUpdatedDate, lastUpdatedBy, dateSubmitted) {
this.employeeId = employeeId;
this.expenseDate = expenseDate;
this.taskId = taskId;
this.expenseTypeId = expenseTypeId;
this.billingCategory = billingCategory;
this.notes = notes;
this.amount = amount;
this.lastUpdatedDate = lastUpdatedDate;
this.lastUpdatedBy = lastUpdatedBy;
this.dateSubmitted = dateSubmitted;
this.location = location;
}
$scope.TestExpenses = [];
The current state of the relevant Angular function submitEntriesToDatabase:
$scope.submitEntriesToDatabase = function () {
$http.post('/expense/submitExpense', $scope.TestExpenses)
.success(function (data, status, headers, config) {
})
.error(function (data, status, headers, config) {
});
};
In C#, I have the following model to correspond to my TestExpense object:
public class Expense
{
public int employeeId { get; set; }
public string expenseDate { get; set; }
public int taskId { get; set; }
public int expenseTypeId { get; set; }
public int billingCategory { get; set; }
public string notes { get; set; }
public float amount { get; set; }
public string LastUpdatedDate { get; set; }
public int LastUpdatedBy { get; set; }
public string dateSubmitted { get; set; }
public string location { get; set; }
}
And the method to handle the POST in the API:
public void SubmitExpenses(List<Expense> expenses)
{
//using(cnxn)
//{
// using(SqlCommand sqlQuery = new SqlCommand("INSERT INTO Expenses " +
// "(Employee_ID, Task_ID, Expense_Date, Expense_Type_ID, Billing_Category_ID, " +
// "Amount, Notes, Last_Updated_By, Last_Update_Datetime, Date_Submitted, Location) " +
// "Values (#employeeId, #taskId, #expenseDate, #expenseTypeId, #billingCategory, #amount, #notes, " +
// "#lastUpdatedBy, #lastUpdatedDate, #dateSubmitted, #locationId)", cnxn))
// {
// sqlQuery.Parameters.Add(new SqlParameter("#employeeId", SqlDbType.Int) { Value = employeeId });
// sqlQuery.Parameters.Add(new SqlParameter("#expenseDate", SqlDbType.DateTime) { Value = expenseDate });
// sqlQuery.Parameters.Add(new SqlParameter("#taskId", SqlDbType.Int) { Value = taskId });
// sqlQuery.Parameters.Add(new SqlParameter("#expenseTypeId", SqlDbType.Int) { Value = expenseTypeId });
// sqlQuery.Parameters.Add(new SqlParameter("#billingCategory", SqlDbType.Int) { Value = billingCategory });
// sqlQuery.Parameters.Add(new SqlParameter("#notes", SqlDbType.Text) { Value = notes });
// sqlQuery.Parameters.Add(new SqlParameter("#amount", SqlDbType.Money) { Value = amount });
// sqlQuery.Parameters.Add(new SqlParameter("#lastUpdatedDate", SqlDbType.DateTime) { Value = lastUpdatedDate });
// sqlQuery.Parameters.Add(new SqlParameter("#lastUpdatedBy", SqlDbType.Int) { Value = lastUpdatedBy });
// sqlQuery.Parameters.Add(new SqlParameter("#dateSubmitted", SqlDbType.DateTime) { Value = dateSubmitted });
// sqlQuery.Parameters.Add(new SqlParameter("#locationId", SqlDbType.VarChar) { Value = "Radnor" });
// cnxn.Open();
// sqlQuery.ExecuteNonQuery();
// }
//}
}
The lines that are commented out in my SubmitExpenses work to insert a single entry (with the appropriate method signature, not what is there now). It is also that functionality which I wish to imitate with the List<Expenses> expenses argument being passed to it. From what I gather, I need to deserialize the JSON string that will represent my $scope.TestExpenses array, but I am unsure of how to start to parse out individual Expense objects from it.
The relevant route in RouteConfig.cs:
routes.MapRoute(
name:"SubmitExpense",
url:"expense/submitExpense",
defaults: new
{
controller = "Expense",
action = "SubmitExpenses"
}
);
Any guidance would be much appreciated!
From what I gather, I need to deserialize the JSON string that will represent my $scope.TestExpenses array, but I am unsure of how to start to parse out individual Expense objects from it.
Simple. Use the [FromBody] decorator in your method signature. Your default JSON serializer settings setup for all the controllers will try parse the string into the Expense list - if you're using Json.NET, it can handle this automatically.
public void SubmitExpenses([FromBody] List<Expense> expenses)
From what I gather, I need to deserialize the JSON string that will
represent my $scope.TestExpenses array, but I am unsure of how to
start to parse out individual Expense objects from it.
No. You don't need to do a thing to de-serialize. It will be auto-deserialized.
A better implementation of the POST request will be this.
$scope.submitEntriesToDatabase = function() {
var config = {
method: "POST",
url: '/expense/submitExpense',
data: $scope.TestExpenses
};
$http(config).then(function(response) {
//success
}, function(response) {
//error
});
};
If the property names in the array are same as that of the the object in your generic list, the web api will automatically convert the javascript array to List<T>.
P.S: Do not use .success and .error callbacks as they are obsolete. Use .then
The correct way to do a post in angular 1.x, using $http is:
$http.post('/my/url',{foo:bar}).then(function(result) {
console.log(result.data); // data property on result contains your data
});
Related
I want to pass all data to controller after clicking button.
var data = new FormData();
Here is my javascript object
var info = {};
info.CorporateName = $("input[name*='CorporateName']").val();
info.CorporatePhone1 = $("input[name*='CorporatePhone1']").val();
info.CorporatePhone2 = $("input[name*='CorporatePhone2']").val();
info.CorporateEmail = $("input[name*='CorporateEmail']").val();
I can reach these datas from the controller with code below
$.each(info, function (key, input) {
data.append(key, input);
});
Here is my file list. I can reach these files from the controller with code below
var allfiles = $(".required-files");
for (var i = 0; i < allfiles.length; i++)
{
var files = allfiles[i].files;
data.append('files', files[0]);
}
Here is my packages cookie. I can't reach package list from the controller
var packageList = $.parseJSON($.cookie("packageList"));
data.append('packageList',JSON.stringify(packageList));
I can post files, my info object but I can't post cookie list
Here is my controller
[HttpPost]
public async Task<IActionResult> create(IEnumerable<IFormFile> files, List<PostServiceDto> packageList, ModelDto Model)
{
// files = not null, Model not null, but packageList = null
var model = Request.Form;
return View();
}
My package model
public class PostServiceDto
{
public string Type { get; set; }
public string Name { get; set; }
public string Price { get; set; }
public string Id { get; set; }
public string Count { get; set; }
}
I couln't take the list it with parameter but I solved it getting json object form request body.
the value returned from request ={\"Type\":\"3\",\"Name\":\"dfsfsdfs\",\"Price\":\"44,00\",\"Id\":\"2\",\"Count\":1},{\"Type\":\"3\",\"Name\":\"Yeni Paket\",\"Price\":\"49,90\",\"Id\":\"1\",\"Count\":1}
Solution
foreach (var item in Request.Form.Keys)
{
if(item == "packageList")
{
clearObject(Request.Form[item]);
}
}
public List<PostServiceDto> clearObject(string value)
{
List<PostServiceDto> postServices = new List<PostServiceDto>();
List<PostServiceDto> myDeserializedObjList =
(List<PostServiceDto>)Newtonsoft.Json.JsonConvert.DeserializeObject(value, typeof(List<PostServiceDto>));
return myDeserializedObjList;
}
code source : [https://www.codeproject.com/Tips/79435/Deserialize-JSON-with-C]
We have a ASP:NET MVC application with controller. We HTTP GET to one method in controller.
Inside of it, we want to create Event objects and send the list with all its properties back to the client (in JS).
It doesn't work because in JS we receive a list of empty objects. See attached screenshot. What are we missing?
Thanks in advance for any help.
ASP.NET MVC Controller:
public class KalenderController : Controller
{
public class Event
{
public Event(int _id, string _title)
{
id = _id;
title = _title;
}
public int id;
public string title;
}
[HttpGet]
public JsonResult GetEvents()
{
StringValues start = "";
Request.Query.TryGetValue("start", out start);
StringValues end = "";
Request.Query.TryGetValue("end", out end);
DateTime dtStart = DateTime.Parse(start.ToString().Replace(" ", "+"));
DateTime dtEnd = DateTime.Parse(end.ToString().Replace(" ", "+"));
List<Event> events = new List<Event>();
DateTime dt = dtStart;
while(dt <= dtEnd)
{
events.Add(new Event(1, "title"));
dt = dt.AddDays(1);
}
return Json(events);
}
}
JS Code:
$.ajax({
url: "Kalender/GetEvents?start=" + fetchInfo.startStr + "&end=" + fetchInfo.endStr,
type: 'GET',
success: function (data) {
console.dir(data);
console.log(data.d);
},
error: function (jqXHR, textStatus, errorThrown) {
alert("Fehler beim Abrufen des Skripts: " + textStatus + " - " + errorThrown);
},
failure: function (bool) {
alert("Fehler beim Abrufen des Skripts");
}
});
Result of sending data back to client:
Empty objects in JS array: https://i.stack.imgur.com/Zi7v7.png
You should change the public fields into public properties on the Event object
public class Event
{
public Event(int _id, string _title)
{
Id = _id;
Title = _title;
}
public int Id { get; set; }
public string Title { get; set; }
}
I try to save fields by action controller action method which return different view. But failed to do this: My Jquery code is:
$("#btnAdd").click(function () {
var Product = {
name: $("#txtProductName").val(),
color: $("#ddlColor option:selected").val(),
gage: $("#ddlGage option:selected").val(),
rate: $("#txtrate").val()
};
$.ajax({
});
$.post("ProductTable", { Pro: JSON.stringify(Product) }, function (data) {
$("#RightDiv").html(data);
alert(data);
});
});
and my controller action method on the same controller which return different view:
public ActionResult ProductTable()
{
Product product = new Product();
JavaScriptSerializer serializer = new JavaScriptSerializer();
product = serializer.Deserialize<Product>(Request.Form["Pro"]);
productDB.addProduct(product);
productManager.productTable = productDB.getAllProducts();
return View(productManager);
}
Browser give me error:
HTTP500: SERVER ERROR - The server encountered an unexpected condition that prevented it from fulfilling the request.
(XHR)POST - http://localhost:59008/Product/ProductTable
If you're using MVC, it should handle the serialization/deserialization for you. You just need to make sure the object sent over matches the object you declare in MVC controller action parameter.
Client-side
// Suggestions:
// * use camelCase for javascript variables and functions
// * jQuery .val() on selects should give you the selected value
// * always use fully qualified Url generated by Html.Helper
$("#btnAdd").click(function () {
var product = {
name: $("#txtProductName").val(),
color: $("#ddlColor").val(),
gage: $("#ddlGage").val(),
rate: $("#txtrate").val()
};
var createUrl = '#Url.Action("create", "product", new { area = "" })';
$.post(createUrl, product, function (response) {
$("#RightDiv").html(response);
alert(response);
});
});
Server-side
// Suggestions:
// * NEVER send your domain model back to the page! You should create
// a ViewModel to just include what you want to show the users
[HttpPost]
public ActionResult Create(CreateProductViewModel model)
{
...
productDB.addProduct(new Product {
Name = model.Name,
Color = model.Color,
Gage = model.Gage,
Rate = model.Rate,
// And other stuff like
// CreatedBy = User.Identity.Name
});
// This looks weird to me too!
productManager.productTable = productDB.getAllProducts();
return View(productManager);
}
The ViewModel
public class CreateProductViewModel
{
public string Name { get; set; }
public int Color { get; set; }
public int Gage { get; set; }
public double Rate { get; set; }
}
I have an "Add Employee" modal with a multiselect selectize "Department" dropdown. On button click, an ajax call will run to call respective controller and pass values to database. I can pass everything aside from the "Department" dropdown.
I have tried:
$.ajax({
...
data: { ..., Department: $("#cmbAddDepartment").val(), .... }
})
$.ajax({
...
data: { ...., Department: $("#cmbAddDepartment").getValue(), ... }
})
and
var selectize = $('#cmbAddDepartment').get(0).selectize;
var cmbAddDepartment=selectize.getValue();
$.ajax({
...
data: { ... , Department: cmbAddDepartment, ... }
})
Funny thing is, all those work inside an alert() but not inside an ajax data.
I am using:
Bootstrap 4 alpha 6,
JQuery 3.2.1,
Standalone Selectize 0.12.4
EDIT:
Just an fyi, all my other comboboxes are single-select (still selectize), and $("#cmbAddSomething").val()` works for them.
EDIT 2: Here is the controller and (view)model
Viewmodel - vmEmpCreate.cs
public class vmEmpCreate
{
public vmEmpCreate()
{
//constructor
}
//combo
public string Company { get; set; }
public string Site { get; set; }
public string[] Department { get; set; } //can be multiple
public string ProductionLine { get; set; }
public IEnumerable<SelectListItem> AddCompany { get; set; }
public IEnumerable<SelectListItem> AddSite { get; set; }
public IEnumerable<SelectListItem> AddDepartment { get; set; }
public IEnumerable<SelectListItem> AddProductionLine { get; set; }
}
public class MyListSelectForAdd
{
public string Key { get; set; }
public string Display { get; set; }
}
Controller - Controller.cs
[HttpPost]
public ActionResult AddEmployee(vmEmpCreate vmc)
{
if (ModelState.IsValid)
{
modEmployee addemp = new modEmployee();
addemp.Company = vmc.Company;
addemp.Site = vmc.Site;
addemp.Department = vmc.Department;
...
addemp.Remarks = vmc.Remarks;
conn = new SqlConnection(someConnectionString);
conn.Open();
comm = new SqlCommand("insert into someTable (company, site, department, ..., remarks) values ('"
+ addemp.Company + "' , '"
+ addemp.Site + "' , '"
+ addemp.Department + "' , '"
...
+ addemp.Remarks + "')", conn);
comm.ExecuteNonQuery();
conn.Close();
}
return PartialView();
}
EDIT 3: as per suggestions, i checked my program with chrome inspector to see any errors, but none came up.
I am not very familiar with selectize, but in order to send the set of information you need to store it in an object (aka. associative array):
var selectize = $('#cmbAddDepartment').get(0).selectize;
var cmbAddDepartment=selectize.getValue();
$.ajax({
...
data: {
... ,
Department: cmbAddDepartment,
...
}
});
You can pass as much data as you need into that. So if all of your methods work, then use the one that is best for you, making sure that the data is enclosed in the brackets.
More on JavaScript Objects
I was able to create a workaround for this problem by storing the multiselect dropdown selected values to a HiddenFor, and then passing that value to my "Department" property in the ajax call. I also changed my viewmodel "Department" property from an array to a string.
(View)Model:
public string Department;
View:
#Html.HiddenFor(m => m.Department, new { #id = "hdnDepartment" })
$('#btnAddEmployee').click(function (e) {
e.preventDefault();
var selectize = $('#cmbAddDepartment').get(0).selectize;
var cmbAddDepartment = selectize.getValue();
$("#hdnDepartment").val(cmbAddDepartment);
$.ajax({
..
data: { ..., Department: $("#hdnDepartment").val(), ... }, // optional data
...
});
});
Pretty cheap solution, but it gets the job done.
Thanks to everyone with their help!
I always get a little lost whenever I am doing something more than basic javascript. I have a knockout viewmodel like so:
function UserSettingsViewModel(apiBaseUrl, userId) {
var self = this;
self.firstName = ko.observable();
self.lastName = ko.observable();
self.fullName = ko.computed(function () {
return self.firstName() + " " + self.lastName();
}, this);
var vmData = $.getJSON(apiBaseUrl + "?userId=" + userId, function (data) {
alert(JSON.stringify(data));
});
self.firstName(vmData.FirstName);
}
I am following along on the tutorial on knockouts site. This will expand into something that will hold first and last name, two email addresses, an address model, and more. I guess asking how to properly do that is another question. Baby steps.
I am getting the right result from the getJSON call, something like this:
{
"FirstName":"Test Data",
"LastName":"Test Data",
...more stuff...
}
How can I put all this data into my knockout observables when the data comes in so it updates my page automagically?
I know there is a plugin for mapping. If I ought to go that route, can you possibly show me an example or point me to a good tutorial? The end product of this page is going to be a object like this (C# Model Class):
public class UserSettingsViewModel
{
public string UserGuid { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string PrimaryEmail { get; set; }
public string SecondaryEmail { get; set; }
public string City { get; set; }
public string County { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
}
This is the object getting passed back from the webapi get method.
I don't know about ko, but I hope one of these 2 options works for you:
Option 1:
$.getJSON(apiBaseUrl + "?userId=" + userId, function (data) {
self.firstName(data.FirstName);
});
Option 2: Synchronous (not recommended, use as last resource):
$.ajaxSetup({async: false});
$.getJSON(apiBaseUrl + "?userId=" + userId, function (data) {
self.firstName(data.FirstName);
});
$.ajaxSetup({async: true});
The second one is not recommended because as the call is async, execution will stop until the ajax call finishes.
Cheers