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!
Related
I want to update values in my database. to make sure my script was working and to send the values I created a POST method to check and the values are coming.
My question now is with the values coming to the method, how to update or save my values in the database?
Controller:
[HttpPost]
public JsonResult EditPost(Programa_Cor_Info_Status statusData)
{
Programa_Cor_Info_Status status = new Programa_Cor_Info_Status
{
ID_Info = statusData.ID_Info,
Status = statusData.Status,
Obs = statusData.Obs,
};
return Json(status, JsonRequestBehavior.AllowGet);
}
I tried using db.savechanges on my controller but to no avail.
Could someone help me with an example?
Thanks
------------Update-----------------------------------------
[HttpPost]
public ActionResult EditPost(Programa_Cor_Info_Status statusData, int ID_Status)
{
Programa_Cor_Info_Status status = new Programa_Cor_Info_Status
{
ID_Info = statusData.ID_Info,
Status = statusData.Status,
Obs = statusData.Obs,
};
var q = db.Programa_Cor_Info_Status.Where(m => m.ID_Info == ID_Status).FirstOrDefault();
q.ID_Info = ID_Status;
db.Entry(q).State = EntityState.Modified;
db.SaveChanges();
return Json(status, JsonRequestBehavior.AllowGet);
}
namespace Balu0._1.Models
{
using System;
using System.Collections.Generic;
public partial class Programa_Cor_Info_Status
{
public int ID_Info { get; set; }
public int ID_Programa { get; set; }
public int ID_Linha_Cor { get; set; }
public string Status { get; set; }
public string Obs { get; set; }
}
}
If you stll don't have, in your view add hidden model field with ID_Info value.
Change your action to this:
public ActionResult EditPost(Programa_Cor_Info_Status statusData)
{
var existItem = db.Programa_Cor_Info_Status.Find(statusData.ID_Info);
// or if you dont have a proper primary key you can try
var existItem = db.Programa_Cor_Info_Status
.Where( i=> i.ID_Info== statusData.ID_Info).FirstOrDefault();
if (existItem != null)
{
db.Entry(existItem).CurrentValues.SetValues(statusData);
var result = db.SaveChanges(); // if result==0 then error
} else ...error
return Json(statusData, JsonRequestBehavior.AllowGet);
}
thanks for the help i already got !!!
db.Entry(status).State = EntityState.Modified;
db.SaveChanges();
return Json(status, JsonRequestBehavior.AllowGet);
I'm developing an ASP.NET MVC 5 application, with C# and .NET Framework 4.6.1.
I have this View:
#model MyProject.Web.API.Models.AggregationLevelConfViewModel
[...]
#Html.DropDownListFor(m => m.Configurations[0].HelperCodeType, (SelectList)Model.HelperCodeTypeItems, new { id = "Configurations[0].HelperCodeType" })
The ViewModel is:
public class AggregationLevelConfViewModel
{
private readonly List<GenericIdNameType> codeTypes;
private readonly List<GenericIdNameType> helperCodeTypes;
public IEnumerable<SelectListItem> CodeTypeItems
{
get { return new SelectList(codeTypes, "Id", "Name"); }
}
public IEnumerable<SelectListItem> HelperCodeTypeItems
{
get { return new SelectList(helperCodeTypes, "Id", "Name"); }
}
public int ProductionOrderId { get; set; }
public string ProductionOrderName { get; set; }
public IList<Models.AggregationLevelConfiguration> Configurations { get; set; }
public AggregationLevelConfViewModel()
{
// Load CodeTypes to show it as a DropDownList
byte[] values = (byte[])Enum.GetValues(typeof(CodeTypes));
codeTypes = new List<GenericIdNameType>();
helperCodeTypes = new List<GenericIdNameType>();
for (int i = 0; i < values.Length; i++)
{
GenericIdNameType cType = new GenericIdNameType()
{
Id = values[i].ToString(),
Name = EnumHelper.GetDescription((CodeTypes)values[i])
};
if (((CodeTypes)values[i]) != CodeTypes.NotUsed)
codeTypes.Add(cType);
helperCodeTypes.Add(cType);
}
}
}
And Models.AggregationLevelConfiguration is:
public class AggregationLevelConfiguration
{
public byte AggregationLevelConfigurationId { get; set; }
public int ProductionOrderId { get; set; }
public string Name { get; set; }
public byte CodeType { get; set; }
public byte HelperCodeType { get; set; }
public int PkgRatio { get; set; }
public int RemainingCodes { get; set; }
}
I need to set selected value in these properties:
public IEnumerable<SelectListItem> CodeTypeItems
{
get { return new SelectList(codeTypes, "Id", "Name"); }
}
public IEnumerable<SelectListItem> HelperCodeTypeItems
{
get { return new SelectList(helperCodeTypes, "Id", "Name"); }
}
But I can't set it in new SelectList(codeTypes, "Id", "Name"); or new SelectList(helperCodeTypes, "Id", "Name"); because the selected value are in Configurations array: fields AggregationLevelConfiguration.CodeType and AggregationLevelConfiguration.HelperCodeType.
I think I have to set selected value in the View, but I don't know how to do it.
How can I set the selected values?
Unfortunately #Html.DropDownListFor() behaves a little differently than other helpers when rendering controls in a loop. This has been previously reported as an issue on CodePlex (not sure if its a bug or just a limitation)
The are 2 option to solve this to ensure the correct option is selected based on the model property
Option 1 (using an EditorTemplate)
Create a custom EditorTemplate for the type in the collection. Create a partial in /Views/Shared/EditorTemplates/AggregationLevelConfiguration.cshtml (note the name must match the name of the type
#model yourAssembly.AggregationLevelConfiguration
#Html.DropDownListFor(m => m.HelperCodeType, (SelectList)ViewData["CodeTypeItems"])
.... // other properties of AggregationLevelConfiguration
and then in the main view, pass the SelectList to the EditorTemplate as additionalViewData
#using (Html.BeginForm())
{
...
#Html.EditorFor(m => m.Configurations , new { CodeTypeItems = Model.CodeTypeItems })
...
Option 2 (generate a new SelectList in each iteration and set the selectedValue)
In this option your property CodeTypeItems should to be IEnumerable<GenericIdNameType>, not a SelectList (or just make codeTypes a public property). Then in the main view
#Html.DropDownListFor(m => m.Configurations[0].HelperCodeType, new SelectList(Model.CodeTypeItems, "Id", "Name", Model.Configurations[0].HelperCodeType)
Side note: there is no need to use new { id = "Configurations[0].HelperCodeType" - the DropDownListFor() method already generated that id attribute
I wrote this class to overcome an issue I was having with selecting an option in an html select list. I hope it helps someone.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
namespace Login_page.Models
{
public class HTMLSelect
{
public string id { get; set; }
public IEnumerable<string> #class { get; set; }
public string name { get; set; }
public Boolean required { get; set; }
public string size { get; set; }
public IEnumerable<SelectOption> SelectOptions { get; set; }
public HTMLSelect(IEnumerable<SelectOption> options)
{
}
public HTMLSelect(string id, string name)
{
this.id = id;
this.name = name;
}
public HTMLSelect(string id, string name, bool required, IEnumerable<SelectOption> options)
{
this.id = id;
this.name = name;
this.required = required;
}
private string BuildOpeningTag()
{
StringBuilder text = new StringBuilder();
text.Append("<select");
text.Append(this.id != null ? " id=" + '"' + this.id + '"' : "");
text.Append(this.name != null ? " name=" + '"' + this.name + '"' : "");
text.Append(">");
return text.ToString();
}
public string GenerateSelect(IEnumerable<SelectOption> options)
{
StringBuilder selectElement = new StringBuilder();
selectElement.Append(this.BuildOpeningTag());
foreach (SelectOption option in options)
{
StringBuilder text = new StringBuilder();
text.Append("\t");
text.Append("<option value=" + '"' + option.Value + '"');
text.Append(option.Selected != false ? " selected=" + '"' + "selected" + '"' + ">" : ">");
text.Append(option.Text);
text.Append("</option>");
selectElement.Append(text.ToString());
}
selectElement.Append("</select");
return selectElement.ToString();
}
}
public class SelectOption
{
public string Text { get; set; }
public Boolean Selected { get; set; }
public string Value { get; set; }
}
}
And
public IEnumerable<SelectOption> getOrderTypes()
{
List<SelectOption> orderTypes = new List<SelectOption>();
if (this.orderType == "OptionText")
{
orderTypes.Add(new SelectOption() { Value = "1", Text = "OptionText", Selected = true });
} else
{
orderTypes.Add(new SelectOption() { Value = "2", Text = "OptionText2" });
}
}
And to use it:
#{
Login_page.Models.HTMLSelect selectElement = new Login_page.Models.HTMLSelect("order-types", "order-types");
}
#Html.Raw(selectElement.GenerateSelect(Model.getOrderTypes()));
I leave this in case it helps someone else. I had a very similar problem and none of the answers helped.
We had in a view this line at the top:
IEnumerable<SelectListItem> exitFromTrustDeed = (ViewData["ExitFromTrustDeed"] as IEnumerable<string>).Select(e => new SelectListItem() {
Value = e,
Text = e,
Selected = Model.ExitFromTrustDeed == e
});
and then below in the view:
#Html.DropDownListFor(m => m.ExitFromTrustDeed, exitFromTrustDeed, new { #class = "form-control" })
We had a property in my ViewData with the same name as the selector for the lambda expression and for some reason that makes the dropdown to be rendered without any option selected.
We changed the name in ViewData to ViewData["ExitFromTrustDeed2"] and that made it work as expected.
Weird though.
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 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
});
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