Related
I am building a Point of Sale system in ASP.NET MVC and I wish to save the content of the HTML table containing all the orders to the database.
I have tried sending it through JSON to the controller but it saves only the first row of the table and ignores the rest rows.
Also, asides the HTML table contents, I also have some data in textboxes that I want to save into the database though it will have to be manipulated first in the controller. Below is the code I have tried but it saves only the first row on the table and ignores others.
the below is the Controller side code
public JsonResult InsertOrders(List<OrderDetail> orderDetails)
{
using (POSContext entities = new POSContext())
{
//Check for NULL.
if (orderDetails == null)
{
orderDetails = new List<OrderDetail>();
}
//Loop and insert records.
foreach (OrderDetail orderDetail in orderDetails)
{
orderDetail.Order_Date = WATTime;
orderDetail.Cashier= User.Identity.Name;
entities.OrderDetails.Add(orderDetail);
}
int insertedRecords = entities.SaveChanges();
return Json(insertedRecords);
}
}
Below is the frontend where I am passing the JSON to backend
///////Save Transactions To Database// Still testing this line of codes
$('#btnsavetransaction').click(function () {
//Loop through the Table rows and build a JSON array.
var orders = new Array();
$("#tblCart tbody tr").each(function () {
var row = $(this);
var order = {};
order.Item_ID = row.find("TD").eq(1).html();
order.Item_Name = row.find("TD").eq(2).html();
order.salesPrice = row.find("TD").eq(3).html();
order.Qty = row.find("TD").eq(4).html();
order.Amount = row.find("TD").eq(5).html();
orders.push(order);
});
//Send the JSON array to Controller using AJAX.
$.ajax({
type: "POST",
url: "/Transactions/Transactions/InsertOrders",
data: JSON.stringify(orders),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (r) {
alert(r + " record(s) inserted.");
}
});
});
It actually saves the first row but ignores other rows.
Then, I also have some data in textbox that I want to pass to the controller as well, since I have passed table as JSON, how can I pass the values of the textboxes as well?
Thank you.
EDIT : The below is the full View
#model POS_Web.Models.POSModel.Cartdummy
#{
ViewBag.Title = "Point Of Sales";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="w3-container" style="padding-left:10px">
<div class="col-sm-1"></div>
<div class="col-sm-9 w3-card-4" style="padding-left:40px; padding-right:20px">
<h2 class="w3-center"><strong>Point Of Sales </strong></h2>
<div class="w3-row">
#using (Html.BeginForm("PointOfSales", "Transactions", new { area = "Transactions" }, FormMethod.Post, new { id = "form" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#*#Html.HiddenFor(model => model.Id)*#
#*#Html.HiddenFor(model => model.New_Quantity)*#
<div class="w3-responsive w3-row">
#*<h2 class="w3-center"><strong>All Items in Stock </strong></h2>*#
<table id="tblItems" class="table w3-table-all w3-hoverable">
<thead>
<tr>
<th>Item ID</th>
<th>Item Category</th>
<th>Item Name</th>
<th>Cost Price</th>
<th>Sales Price</th>
<th>Quantity</th>
<th>Reorder Level</th>
<th>Item Discontinued?</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<div class="w3-row">
<div class="w3-col w3-third">
<div class="form-group">
#Html.LabelFor(model => model.Item_ID, htmlAttributes: new { #class = "control-label" })
#Html.EditorFor(model => model.Item_ID, new { htmlAttributes = new { placeholder = "Item ID", #class = "form-control", #readonly = "true" } })
#Html.ValidationMessageFor(model => model.Item_ID, "", new { #class = "text-danger" })
</div>
</div>
<div class="w3-col w3-third">
<div class="form-group">
#Html.LabelFor(model => model.Item_Name, htmlAttributes: new { #class = "control-label" })
#Html.EditorFor(model => model.Item_Name, new { htmlAttributes = new { placeholder = "Item Name", #class = "form-control", #readonly = "true" } })
#Html.ValidationMessageFor(model => model.Item_Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="w3-col w3-third">
<div class="form-group">
#Html.LabelFor(model => model.Sales_Price, htmlAttributes: new { #class = "control-label" })
#Html.EditorFor(model => model.Sales_Price, new { htmlAttributes = new { placeholder = "Price", #class = "form-control", #readonly = "true" } })
#Html.ValidationMessageFor(model => model.Sales_Price, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="w3-row">
<div class="w3-col w3-third">
<div class="form-group">
#Html.LabelFor(model => model.Qty, htmlAttributes: new { #class = "control-label" })
#Html.EditorFor(model => model.Qty, new { htmlAttributes = new { placeholder = "Qty", #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Qty, "", new { #class = "text-danger" })
</div>
</div>
<div class="w3-col w3-third">
<div class="form-group">
#Html.LabelFor(model => model.Amount, htmlAttributes: new { #class = "control-label" })
#Html.EditorFor(model => model.Amount, new { htmlAttributes = new { placeholder = "Amount", #class = "form-control", #readonly = "true" } })
#Html.ValidationMessageFor(model => model.Amount, "", new { #class = "text-danger" })
</div>
</div>
<div class="w3-col w3-third">
<div class="form-group">
<input type="button" id="btnAddToCart" value="Add To Cart" class="btn btn-primary btn-block" />
</div>
</div>
</div>
<div class="w3-row">
<h3 class="w3-center"><strong>Shopping Cart </strong></h3>
</div>
<div class="w3-responsive w3-row">
<table id="tblCart" class="table w3-table-all">
<thead>
<tr>
<th>Remove From Cart</th>
<th>Item ID</th>
<th>Item Name</th>
<th>Sales Price</th>
<th>Qty</th>
<th>Amount</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<div class="w3-col w3-third">
</div>
<div class="w3-col w3-third">
<div class="form-group">
#Html.LabelFor(model => model.Total_Amount, htmlAttributes: new { #class = "control-label" })
#Html.EditorFor(model => model.Total_Amount, new { htmlAttributes = new { placeholder = "Total Amount", #class = "form-control", #readonly = "True" } })
#Html.ValidationMessageFor(model => model.Total_Amount, "", new { #class = "text-danger" })
</div>
<div class="form-group">
#Html.LabelFor(model => model.Amount_Tendered, htmlAttributes: new { #class = "control-label" })
#Html.EditorFor(model => model.Amount_Tendered, new { htmlAttributes = new { placeholder = "Amount Tendered", #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Amount_Tendered, "", new { #class = "text-danger" })
</div>
<div class="form-group">
#Html.LabelFor(model => model.Change_Received, htmlAttributes: new { #class = "control-label" })
#Html.EditorFor(model => model.Change_Received, new { htmlAttributes = new { placeholder = "Change Received", #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Change_Received, "", new { #class = "text-danger" })
</div>
</div>
<div class="w3-col w3-third">
<div class="form-group">
#Html.LabelFor(model => model.Payment_Method, htmlAttributes: new { #class = "control-label" })
#Html.DropDownList("Payment_Method", new List<SelectListItem>{
new SelectListItem{ Text="Cash", Value="Cash"},
new SelectListItem{ Text="Bank Transfer", Value="Bank Transfer"},
new SelectListItem{ Text="POS", Value="POS"}
}, "--- Select Payment Method ---", new { #class = "form-control" }
)
#Html.ValidationMessageFor(model => model.Payment_Method, "", new { #class = "text-danger" })
</div>
<div class="form-group">
#Html.LabelFor(model => model.Customer_ID, htmlAttributes: new { #class = "control-label" })
#Html.EditorFor(model => model.Customer_ID, new { htmlAttributes = new { placeholder = "Customer ID", #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Customer_ID, "", new { #class = "text-danger" })
</div>
<br />
<div class="form-group">
<input type="submit" value="Save" class="btn btn-success btn-block" id="submitbtn" />
</div>
<div class="form-group">
<input type="button" id="btnsavetransaction" value="Save Transaction" class="btn btn-primary btn-block" />
</div>
</div>
<hr />
</div>
}
</div>
</div>
</div>
#section Scripts {
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/jqueryui")
#Styles.Render("~/Content/cssjqryUi")
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/Scripts/jquery.validate.js")
#Scripts.Render("~/Scripts/jquery.validate.date.js")
#Scripts.Render("~/Scripts/jquery.validate.unobtrusive.min.js")
#Scripts.Render("~/Scripts/jquery.unobtrusive-ajax.min.js")
#*<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>*#
<script type="text/javascript" src="https://cdn.datatables.net/1.10.20/js/jquery.dataTables.min.js"></script>
<link href="https://cdn.datatables.net/1.10.20/css/jquery.dataTables.css" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" />
<script type="text/javascript">
//Declaring the Total Amount First
var totalAmount = 0;
var itemDiscontinued = null;
var stock = 0;
$(document).ready(function () {
$('#submitbtn').click(function (e) {
$('#errorWithdraw').css('display', 'none');
if (!$('#form').valid()) {
alert('Some Input Fields has Not Been Filled Correctly');
return false;
} else if ($('#form').valid()) {
var x = confirm("Are you sure to Save this Transaction?"); //confirm text
if (x == true) { //checking whether user clicked ok or cancel
$('.spinner').css('display', 'block'); //if clicked ok spinner shown)
} else { //else if clicked cancel spinner is hidden
$('.spinner').css('display', 'none');
return false //stops further process
}
}
});
//Table listing all categories and allows filtering
$(function () {
var oTable;
$.ajax({
type: "POST",
url: "/StockManagement/StockManagement/Items",
data: '{}',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response) {
var customers = eval(response);
oTable = $("#tblItems").DataTable({
bLengthChange: true,
lengthMenu: [[5], [5]],
bFilter: true,
bSort: true,
bPaginate: true,
data: customers,
columns: [
{ 'data': 'Item_ID' },
{ 'data': 'Item_category' },
{ 'data': 'Item_Name' },
{ 'data': 'Cost_Price' },
{ 'data': 'Sales_Price' },
{ 'data': 'Quantity' },
{ 'data': 'Reorder_Level' },
{ 'data': 'Item_Discontinued' },
]
});
},
failure: function (response) {
alert(response.responseText);
},
error: function (response) {
alert(response.responseText);
}
});
$('#Item_Name').keyup(function () {
oTable.search($(this).val()).draw();
})
});
//Making the Table clickable
$(function () {
$('#tblItems').on('click', 'tr', function () {
var currentRow = $(this).closest("tr");
var itemID = currentRow.find("td:eq(0)").text(); // get current row 1st TD value
var itemName = currentRow.find("td:eq(2)").text(); // get current row 2nd TD
// var oldQty = currentRow.find("td:eq(5)").text(); // get current row 5th TD
var salesprice = currentRow.find("td:eq(4)").text(); // get current row 5th TD
itemDiscontinued = currentRow.find("td:eq(7)").text(); // getting the Discontinued status of the item selected
stock = currentRow.find("td:eq(5)").text(); // getting the Stock of the Item selected
$('#Item_ID').val(itemID);
$('#Item_Name').val(itemName);
// $('#Old_Quantity').val(oldQty);
$('#Sales_Price').val(salesprice);
});
});
//The Cart table Jquery
$(function () {
//calculating the Amount when Qty is entered
$('#Qty').keyup(function () {
var Qty = $('#Qty').val();
if ($('#Item_ID').val() == '' || $('#Item_ID').val() == undefined) {
alert('Please Select an Item First');
$('#Qty').val('');
return false;
}
var salesPrice = parseFloat($('#Sales_Price').val());
var amount = Qty * salesPrice;
$('#Amount').val(amount);
})
});
//Jquery for the AddToCart Button
$('#btnAddToCart').click(function () {
var itemID = $('#Item_ID').val();
var itemName = $('#Item_Name').val();
var salesprice = parseFloat($('#Sales_Price').val());
var Qty = $('#Qty').val();
var amount = $('#Amount').val();
var newstock = stock - Qty;
if ($('#Item_ID').val() == '' || $('#Item_ID').val() == undefined) {
alert('Please Select an Item to Add to Cart');
return false;
}
if ($('#Qty').val() == '' || $('#Qty').val() == undefined || $('#Qty').val() == 0) {
alert('Please Enter the Qty of The Item Been Purchased');
return false;
}
if ($('#Sales_Price').val() == '' || $('#Sales_Price').val() == undefined || $('#Sales_Price').val() == 0) {
alert('Please Enter the Qty of The Item Been Purchased');
return false;
}
if (itemDiscontinued == 'Yes' ) {
alert('The Item Selected has been Discontinued and cannot be sold');
$('#Item_ID').val('');
$('#Item_Name').val('');
$('#Sales_Price').val('');
$('#Qty').val('');
$('#Amount').val('');
return false;
}
if (newstock < 0) {
alert('The Qty of ' + $('#Item_Name').val() + ' Selected to be purchased is more than what is in store, Please replenish item');
$('#Item_ID').val('');
$('#Item_Name').val('');
$('#Sales_Price').val('');
$('#Qty').val('');
$('#Amount').val('');
return false;
}
//Check if the Item is already in Cart////////////////////////////
var $tds = $('#tblCart tr > td:nth-child(2)').filter(function () {
return $.trim($(this).text()) == itemID;
});
if ($tds.length != 0) {
alert("Item already in Cart");
$('#Item_ID').val('');
$('#Item_Name').val('');
$('#Sales_Price').val('');
$('#Qty').val('');
$('#Amount').val('');
return false;
}
/////////////////////////////////////////////////////////////////////
//Bild up the table row
var table =
"<tr>" +
"<td><button type='button' name='record' class='btn btn-danger' onclick='deleterow(this)'> Remove </td>" +
"<td>" + itemID + "</td>" +
"<td>" + itemName + "</td>" +
"<td>" + salesprice + "</td>" +
"<td>" + Qty + "</td>" +
"<td>" + amount + "</td>" +
"<tr>";
totalAmount += Number(amount);
$('#Total_Amount').val(totalAmount);
$('#tblCart tbody').append(table);
//Empty the Textboxes to allow for new item
$('#Item_ID').val('');
$('#Item_Name').val('');
$('#Sales_Price').val('');
$('#Qty').val('');
$('#Amount').val('');
});
///////Save Transactions To Database// Still testing this line of codes
$('#btnsavetransaction').click(function () {
//Loop through the Table rows and build a JSON array.
var orders = new Array();
$("#tblCart tbody tr").each(function () {
var row = $(this);
var order = {};
order.Item_ID = row.find("TD").eq(1).html();
order.Item_Name = row.find("TD").eq(2).html();
order.salesPrice = row.find("TD").eq(3).html();
order.Qty = row.find("TD").eq(4).html();
order.Amount = row.find("TD").eq(5).html();
orders.push(order);
});
//Send the JSON array to Controller using AJAX.
$.ajax({
type: "POST",
url: "/Transactions/Transactions/InsertOrders",
//data: JSON.stringify(orders),
data: JSON.stringify({ orderDetails: orders }),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (r) {
alert(r + " record(s) inserted.");
}
});
});
});
////Function to Delete Row from Cart
function deleterow(e) {
var amount = parseFloat($(e).parent().parent().find('td:last').text(), 10);
totalAmount -= amount;
$('#Total_Amount').val(totalAmount);
$(e).parent().parent().remove();
}
function showSpinner() {
$('.spinner').css('display', 'block'); //if clicked ok spinner shown
}
</script>
}
// jQuery for the AddToCart Button
$('#btnAddToCart').click(function () {
var itemID = $('#Item_ID').val();
var itemName = $('#Item_Name').val();
var salesprice = parseFloat($('#salesPrice').val()).toFixed(2);
var Qty = $('#Qty').val();
var amount = $('#Amount').val();
var newstock = stock - Qty;
if ($('#Item_ID').val() == '' || $('#Item_ID').val() == undefined) {
alert('Please Select an Item to Add to Cart');
return false;
}
if ($('#Qty').val() == '' || $('#Qty').val() == undefined || $('#Qty').val() == 0) {
alert('Please Enter the Qty of The Item Been Purchased');
return false;
}
if ($('#salesPrice').val() == '' || $('#salesPrice').val() == undefined || $('#salesPrice').val() == 0) {
alert('Please Enter the Qty of The Item Been Purchased');
return false;
}
if (itemDiscontinued == 'Yes') {
alert('The Item Selected has been Discontinued and cannot be sold');
$('#Item_ID').val('');
$('#Item_Name').val('');
$('#salesPrice').val('');
$('#Qty').val('');
$('#Amount').val('');
return false;
}
if (newstock < 0) {
alert('The Qty of ' + $('#Item_Name').val() + ' Selected to be purchased is more than what is in store, Please replenish item');
$('#Item_ID').val('');
$('#Item_Name').val('');
$('#salesPrice').val('');
$('#Qty').val('');
$('#Amount').val('');
return false;
}
// Check if the Item is already in Cart
var $tds = $('#tblCart tr > td:nth-child(2)').filter(function () {
return $.trim($(this).text()) == itemID;
});
if ($tds.length != 0) {
alert("Item already in Cart");
$('#Item_ID').val('');
$('#Item_Name').val('');
$('#salesPrice').val('');
$('#Qty').val('');
$('#Amount').val('');
return false;
}
// Build up the table row
var tbody = $('#tblCart tbody');
var tr = $('<tr></tr>');
tr.append("'<td><button type='button' name='record' class='btn btn-danger' onclick='deleterow(this)'> Remove </td>'")
tr.append('<td>' + itemID + '</td>');
tr.append('<td>' + itemName + '</td>');
tr.append('<td>' + salesprice + '</td>');
tr.append('<td>' + Qty + '</td>');
tr.append('<td>' + amount + '</td>');
tbody.append(tr);
totalAmount += Number(amount);
$('#Total_Amount').val(parseFloat(totalAmount).toFixed(2));
// Empty the Textboxes to allow for new item
$('#Item_ID').val('');
$('#Item_Name').val('');
$('#salesPrice').val('');
$('#Qty').val('');
$('#Amount').val('');
});
// Checkout and Save Transactions To Database
$('#btnCheckOut').click(function() {
// First check if the TableCart is not empty
if ($('#tblCart tr').length <= 1) {
alert('The Cart is Empty, Please add Items to Cart');
return false;
}
if ($('#Amount_Tendered').val() == '' || $('#Amount_Tendered').val() == undefined || $('#Amount_Tendered').val() <= 0) {
alert('Please Enter the Amount Tendered by Customer');
return false;
}
if ($('#Payment_Method').val() == '' || $('#Payment_Method').val() == undefined) {
alert('Please Select the Payment Method');
return false;
}
var totalAmount = parseFloat($('#Total_Amount').val());
var changeReceived = parseFloat($('#Change_Received').val());
if (changeReceived < 0 ) {
alert('The Amount Tendered Cannot be Less than Total Amount');
return false;
}
finalPayment(); //Call the finalpayment method
EmptyControls(); //Calling the Empty control mehod
loaddata(); //Items to be reloaded
});
// Function to Delete Row from Cart
function deleterow(e) {
var amount = parseFloat($(e).parent().parent().find('td:last').text(), 10);
totalAmount -= amount;
$('#Total_Amount').val(totalAmount);
$(e).parent().parent().remove();
}
//Function to send cart table to controller
function finalPayment() {
var totalAmount = $('#Total_Amount').val();
var paymentMethod = $('#Payment_Method').val();
var amountTendered = $('#Amount_Tendered').val();
var changeReceived = $('#Change_Received').val();
var customerID = $('#Customer_ID').val();
var orderdetails = new Array();
$('#tblCart tr:not(:first)').each(function() {
var row = $(this);
var orderdetail = {};
orderdetail.Item_ID = row.find("TD").eq(1).html();
orderdetail.Item_Name = row.find("TD").eq(2).html();
orderdetail.salesPrice = row.find("TD").eq(3).html();
orderdetail.Qty = row.find("TD").eq(4).html();
orderdetail.Amount = row.find("TD").eq(5).html();
orderdetails.push(orderdetail);
});
$.ajax({
async: true,
type: "POST",
url: "/Transactions/Transactions/InsertOrders",
//data: JSON.stringify(orderdetails),
data: JSON.stringify({
orderdetails: orderdetails,
totalAmount: totalAmount,
paymentMethod: paymentMethod,
amountTendered: amountTendered,
changeReceived: changeReceived,
customerID: customerID
}),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
alert(data);
},
error: function () {
alert("Something went wrong, processing not completed");
}
});
}
I have JsonResult list of Articles and it looked like this:
[
{
"tbl_dobavuvaci": null,
"tbl_fakDet": null,
"tbl_fakMas": null,
"tbl_kompanii": null,
"tbl_useri": null,
"artID": 1,
"artKompID": 1,
"artUserID": 1,
"artCode": 25456658845646540,
"artIme": "Artikal 1 Ime",
"artCenaNab": 10,
"artCenaProd": 15,
"artDDV": 18,
"artDobavuvac": 1
},
{
"tbl_dobavuvaci": null,
"tbl_fakDet": null,
"tbl_fakMas": null,
"tbl_kompanii": null,
"tbl_useri": null,
"artID": 2,
"artKompID": 1,
"artUserID": 1,
"artCode": 8606010872303,
"artIme": "TestName",
"artCenaNab": 25,
"artCenaProd": 30,
"artDDV": 18,
"artDobavuvac": 1
}
]
Now in HTML View i have javascript:
$(document).ready(function () {
$.getJSON("/fakturi/getArticles", function (data) {
$.each(data, function (i, data) {
$('<option>',
{
value: data.artID,
text: data.artCode
}).html;
});
})
$(function () {
$("[name='bar']").on("change", function () {
$("#artikal").val($(this).val());
});
});
});
Now When i change artCod named dropdown with artCode values from Json, corectly updated second field with artIme name.
HTML CODE:
#Html.DropDownList("bar", null, string.Empty, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.tbl_artikli, "", new { #class = "text-danger",})
#Html.DropDownList("artikal", null, string.Empty, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.tbl_artikli, "", new { #class = "text-danger", })
#Html.TextBox("artCenaProd", "", new { #class = "form-control", #id = "artCenaProd", style = "width:60pt" })
My Question is how to update third field named artCenaProd when I will change dropdown?
You need to store the json array you receive from your ajax call to a local variable in your script. When the dropdown change event is fired, read the selected option and get the option value (artID). Now filter the local array for items with this id and get the subset (If the artID's are unique, you will get a sub array with one it.
$(document).ready(function () {
var localData = [];
var $bar = $("[name='bar']");
$.getJSON("#Url.Action("/fakturi/getArticles")",
function(data) {
localData = data;
$bar.empty();
$.each(data,
function(i, data) {
var t = $('<option>', { value: data.artID, text: data.artCode });
$bar.append(t);
});
});
$bar.change(function() {
var v = $(this).val();
var filteredData = localData.filter(function(item) {
return item.artID == v;
});
if (filteredData.length) {
$("#artCenaProd").val(filteredData[0].artCenaProd);
}
});
});
Also if you are populating the Dropdown's options using the ajax call, no need to use the DropDownList helper method! Simply write HTML markup for a SELECT element
<SELECT name='bar'>
</SELECT>
I am trying to fill a textbox from jquery after selecting an option from the dropdownlist. I include some snippets of the code.
This is the markup of the view.
<div class="form-group">
#Html.LabelFor(model => model.DependantID, "DependantID", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("DependantID", null, htmlAttributes: new { #class = "form-control", #onchange = "GetRegNo()" })
#Html.ValidationMessageFor(model => model.DependantID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.RegNo, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#*#Html.EditorFor(model => model.RegNo, new { htmlAttributes = new { #class = "form-control" } })*#
<span id="loading_progress1" style="display: none;">Please wait...</span>
#Html.TextBoxFor(model => model.RegNo, new { #Value = #ViewBag.Regno, #readonly = "readonly", #class = "form-control" })
#*#Html.TextBoxFor(model => model.RegNo, new { #Value = Regno, #readonly = "readonly", #class = "form-control" })*#
#Html.ValidationMessageFor(model => model.RegNo, "", new { #class = "text-danger" })
</div>
</div>
This is the jquery code i am hoping to achieve
function GetRegNo() {
var dependid = $('#DependantID').val();
var dprogress = $('#loading_progress1');
dprogress.show();
//alert(schoolid);
$.ajax({
cache: false,
//url: '#Url.Action("/Patients/FillClass")',
url: '/Patients/FillClass',
type: "GET",
datatype: "json",
data: { DependID: dependid },
success: function (stud) {
$("#RegNo").html(""); ///clear entry before appending
$("#RegNo").html() = stud.regno;
alert("I reach here");
alert("data.regno " + stud.regno);
//$.each(studi, function (i, stude) {
//$("#SClassID").append(
//$('<option></option>').val(stude.SClassID).html(stude.Class));
// });
dprogress.hide();
},
error: function (response) {
alert("Error: " + response.responseText);
dprogress.hide();
}
});
Then this is from the controller
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult FillClass(int? dependid)
{
if (dependid == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
string regno="";
var N = db.Patients.Max(f => (int?)f.PatientID).GetValueOrDefault(0);
N++;
string Nt = Convert.ToString(N);
if (dependid == 1)
{
regno = "M" + Convert.ToString((DateTime.Now).ToString("yy")) + BizLogic.Right("00000" + Nt, 5);
}
else
{
regno = "D" + Convert.ToString((DateTime.Now).ToString("yy")) + BizLogic.Right("00000" + Nt, 5);
}
return Json(regno, JsonRequestBehavior.AllowGet);
}
So from my code snippets above, when there is a change in the dropdownlist, the java is called which in turn call the method in the controller and fills the textbox. If there is a better way, I am all open. Thank you.
I found the issue with the jquery script. I will post the change and point to the change. It had to do with my assignment. the line I marked here is posted the value into the textbox.
function GetRegNo() {
var dependid = $('#DependantID').val();
var dprogress = $('#loading_progress1');
dprogress.show();
//alert(schoolid);
$.ajax({
cache: false,
//url: '#Url.Action("/Patients/FillClass")',
url: '/Patients/FillClass',
type: "GET",
datatype: "json",
data: { DependID: dependid },
success: function (stud) {
$("#RegNo").html(""); ///clear entry before appending
here: $('input#RegNo').val(stud); //i missed it here, changing to this changed solved the problem, compare with with script in the question
dprogress.hide();
},
error: function (response) {
alert("Error: " + response.responseText);
dprogress.hide();
}
});
}
I have web app for testing.
My very simple class:
public class MyClass
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Value { get; set; }
}
I changed my default controller this way:
// GET: MyClasses/Create
public ActionResult Create()
{
MyClass myClass = new MyClass()
{
Name = "First",
Value = 1
};
var Names = new[]{
new SelectListItem{ Value="First", Text="First" },
new SelectListItem{ Value="Second", Text="Second" },
new SelectListItem{ Value="Third", Text="Third" },
};
ViewBag.Names = new SelectList(Names, "Value", "Text");
return View(myClass);
}
// POST: MyClasses/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create([Bind(Include = "Id,Name,Value")] MyClass myClass, string Action)
{
if (Action == "Change name")
{
myClass.Value = myClass.Name == "First" ? 1 :
myClass.Name == "Second" ? 2 :
myClass.Name == "Third" ? 3 :
0;
ModelState.Clear();
}
else
if (ModelState.IsValid)
{
db.MyClasses.Add(myClass);
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
var Names = new[]{
new SelectListItem{ Value="First", Text="First" },
new SelectListItem{ Value="Second", Text="Second" },
new SelectListItem{ Value="Third", Text="Third" },
};
ViewBag.Names = new SelectList(Names, "Value", "Text");
return View(myClass);
}
I changed "Create" view this way:
#using (Html.BeginForm(null, null, FormMethod.Post, new { #id = "MainForm" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>MyClass</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#*#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })*#
#Html.DropDownListFor(model => model.Name, (IEnumerable<SelectListItem>)new SelectList(ViewBag.Names, "Value", "Text", Model.Name), htmlAttributes: new { #class = "form-control", #onchange = "changeName()" })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Value, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Value, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Value, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script>
function changeName() {
var input = $("<input>")
.attr("type", "hidden")
.attr("name", "Action").val("Change name");
$('#MainForm').append($(input));
$('#MainForm').submit();
}
</script>
}
I want make this app multilingual (change culture). I added some code to Global.asax.cs for it:
protected void Application_BeginRequest(object sender, EventArgs e)
{
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("someculture");
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("someculture");
}
This app works well when I use "en" or other culture/language ("someculture" in Global.asax.cs), DropDownListFor changes the Value, controller (async Task Create) works as it should.
My browser default culture/language is English. So when I use "fr" or other culture/language I get an error in "Create" view "The field Value must be a number.".
To fix this error user can change "," to "." in "Value", but it is not the solution.
To number validation I added the scripts I use in my other apps. I added its to "Create" view scripts section:
$.validator.methods.number = function (value, element) {
return this.optional(element) ||
!isNaN(Globalize.parseFloat(value));
}
$(document).ready(function () {
Globalize.culture('#(System.Threading.Thread.CurrentThread.CurrentCulture.Name)');
});
jQuery.extend(jQuery.validator.methods, {
range: function (value, element, param) {
var val = Globalize.parseFloat(value);
return this.optional(element) || (val >= param[0] && val <= param[1]);
}
});
But after adding this scripts DropDownListFor stopped working. Number validation is works, DropDownListFor - no.
My question is some way to do to work validation and DropDownListFor one time in one View? Or my approach is wrong and I should implement this functionality otherwise.
UPDATE
I found solution.
Added new input in view:
<input type="hidden" value="no" id="submitform" />
And modified scripts this way:
<script>
function changeName() {
var input = $("<input>")
.attr("type", "hidden")
.attr("name", "Action").val("Change name");
$('#MainForm').append($(input));
document.getElementById("submitform").value = "yes";
$('#MainForm').submit();
}
jQuery.extend(jQuery.validator.methods, {
range: function (value, element, param) {
var val = Globalize.parseFloat(value);
return this.optional(element) || (val >= param[0] && val <= param[1]);
}
});
$.validator.methods.number = function (value, element) {
if (document.getElementById("submitform").value == "yes") {
document.getElementById("submitform").value = "no";
document.getElementById("MainForm").submit();
}
return this.optional(element) || !isNaN(Globalize.parseFloat(value));
}
$(document).ready(function () {
Globalize.culture('#(System.Threading.Thread.CurrentThread.CurrentCulture.Name)');
});
</script>
I need to select a value from a Dropdownlist after it has been loaded:
EDIT: In the script associated with the View I have:
//Dropdown cascade call when trigger is called and fill councilDropdown:
$("#districtDropdown").cascade({
url: "/Address/ListCouncilByDistrict",
paramName: "districtId",
firstOption: 'Selecione o Concelho...',
childSelect: $("#councilDropdown")
});
$("#PostalCode").keyup(function () {
loadPTPostalCode();
});
$("#PostalCodeExtension").keyup(function () {
loadPTPostalCode();
});
function loadPTPostalCode()
{
if ($("#PostalCode").val() >= 1000) {
$.ajax({
url: '/Address/GetPTPostalCode',
type: "POST",
dataType: "json",
data: { postalCode: $("#PostalCode").val(), postalCodeExtension: $("#PostalCodeExtension").val() },
success: function (data) {
if (data != null) {
$("#districtDropdown").val(data.PTDistrict_Id); // Set the Dropdown value
$('#districtDropdown').trigger('change'); // Trigger (force the dropdown to load
// *** This is done to soon, the dropdownlist of the Councils is not all loaded yet ***
$("#councilDropdown").val(data.PTCouncil_Id);
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert(textStatus)
}
});
}
}
EDIT: The View
#model Heelp.ViewModels.AddressPTViewModel
<h2>Create</h2>
#using (Ajax.BeginForm(MVC.Address.CreateAddressPT(), new AjaxOptions { OnSuccess = "showLoginConfirmationResultMessage" }, new { #id = "AddressForm" }))
{
#Html.AntiForgeryToken()
<div class="address1">
#Html.LabelFor(model => model.Address1)
#Html.TextBoxFor(model => model.Address1)
#Html.ValidationMessageFor(model => model.Address1)
</div>
<div class="address2">
#Html.TextBoxFor(model => model.Address2)
#Html.ValidationMessageFor(model => model.Address2)
</div>
<div class="city">
#Html.LabelFor(model => model.City)
#Html.TextBoxFor(model => model.City)
#Html.ValidationMessageFor(model => model.City)
</div>
<div class="postalCode">
#Html.DisplayNameFor(m => m.PostalCode)
#Html.TextBoxFor(m => m.PostalCode, new { #Value = "" })
#Html.ValidationMessageFor(m => m.PostalCode)
</div>
<div class="postalCodeExtension">
#Html.LabelFor(model => model.PostalCodeExtension)
#Html.TextBoxFor(model => model.PostalCodeExtension)
#Html.ValidationMessageFor(m => m.PostalCodeExtension)
</div>
<div class="postalCodeCity">
#Html.LabelFor(model => model.PostalCodeCity)
#Html.TextBoxFor(model => model.PostalCodeCity)
#Html.ValidationMessageFor(m => m.PostalCodeCity)
</div>
<div id="district">
#Html.DisplayNameFor(m => m.PTDistrict_Id)
#Html.DropDownListFor(m => m.PTDistrict_Id, Model.PTDistrictList, HeelpResources.PTDistrictViewDropDownListFirstRecord, new { id = "districtDropdown" })
#Html.ValidationMessageFor(m => m.PTDistrict_Id)
</div>
<div id="council">
#Html.DisplayNameFor(m => m.PTCouncil_Id)
#Html.DropDownListFor(m => m.PTCouncil_Id, Model.PTCouncilList, HeelpResources.PTCouncilViewDropDownListFirstRecord, new { id = "councilDropdown" })
#Html.ValidationMessageFor(m => m.PTCouncil_Id)
</div>
<p>
<input type="submit" value="Create" />
</p>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
EDIT:
Cascade Function:
// Cascade function
(function ($) {
$.fn.cascade = function (options) {
var defaults = {};
var opts = $.extend(defaults, options);
return this.each(function () {
$(this).change(function () {
var selectedValue = $(this).val();
if (selectedValue == '') {
opts.childSelect.empty();
return;
}
var params = {};
params[opts.paramName] = selectedValue;
$.post(opts.url, params, function (items) {
//$.getJSON(opts.url, params, function (items) {
opts.childSelect.empty();
if (opts.firstOption != "")
opts.childSelect.append(
$('<option/>')
.attr('value', '')
.text(opts.firstOption));
$.each(items, function (index, item) {
// alert(opts.firstOption);
opts.childSelect.append(
$('<option/>')
.attr('value', item.Id)
.text(item.Name)
);
});
});
});
});
};
})(jQuery);
But when I do that, as the Dropdownlist is not still loaded, the val() is not there yet.
For example, if I put an alert message before, it works fine because it as time to load the dropdown.
How can I set the value of the council dropdown only after the dropdown is loaded?
As your requirement "set the value of the council dropdown only after the dropdown is loaded".
You need perform synchronous Ajax request. You can specify the async option to be false to get a synchronous Ajax request.
$.ajax({
url: '/Address/GetPTPostalCode',
type: "POST",
dataType: "json",
data: { postalCode: $("#PostalCode").val(), postalCodeExtension: $("#PostalCodeExtension").val() },
success: function (data) {
if (data != null) {
$("#districtDropdown").val(data.PTDistrict_Id);
$('#districtDropdown').trigger('change');
// *** This is done to soon, the dropdownlist of the Councils is not all loaded yet ***
$("#councilDropdown").val(data.PTCouncil_Id);
}
},
async: false
});
I would update the cascade plugin to trigger an event when the ddl is updated.
(function ($) {
$.fn.cascade = function (options) {
var defaults = {};
var opts = $.extend(defaults, options);
return this.each(function () {
$(this).change(function () {
// #### store reference to changed element for later ####
var self = this,
selectedValue = $(this).val();
if (selectedValue == '') {
opts.childSelect.empty();
return;
}
var params = {};
params[opts.paramName] = selectedValue;
$.post(opts.url, params, function (items) {
//$.getJSON(opts.url, params, function (items) {
opts.childSelect.empty();
if (opts.firstOption != "")
opts.childSelect.append(
$('<option/>')
.attr('value', '')
.text(opts.firstOption));
$.each(items, function (index, item) {
// alert(opts.firstOption);
opts.childSelect.append(
$('<option/>')
.attr('value', item.Id)
.text(item.Name)
);
});
// #### Trigger event ####
self.trigger("update");
});
});
});
};
})(jQuery);
now you can bind to that:
...
// *** #### fixed #### This is done to soon, the dropdownlist of the Councils is not all loaded yet ***
$("#councilDropdown").on("updated",function(){
$(this).val(data.PTCouncil_Id);
});
}
I would say there are two approaches here.
1
The best practice would just be to add a callback functionality to your cascade. It could be done like this:
...
$.post(opts.url, params, function (items) {
//$.getJSON(opts.url, params, function (items) {
opts.childSelect.empty();
if (opts.firstOption != ""){
opts.childSelect.append(
$('<option/>')
.attr('value', '')
.text(opts.firstOption));
$.each(items, function (index, item) {
// alert(opts.firstOption);
opts.childSelect.append(
$('<option/>')
.attr('value', item.Id)
.text(item.Name)
);
});
if( typeof(opts.callback) == "function" )opts.callback();//issue callback
}
});
...
It would be used by setting up cascade here:
$("#districtDropdown").cascade({
url: "/Address/ListCouncilByDistrict",
paramName: "districtId",
firstOption: 'Selecione o Concelho...',
childSelect: $("#councilDropdown"),
callback: function(){ districtCallback(); }
});
and defined in whatever manner you wanted like this:
function districtCallback(){
$("#councilDropdown").val($("#districtDropdown").val());
}
2
Quick and dirty.. jsFiddle demo
success: function (data) {
if (data != null) {
$("#districtDropdown").val(data.PTDistrict_Id); // Set the Dropdown value
$('#districtDropdown').trigger('change'); // Trigger (force the dropdown to load
(function councilVal(){
if( typeof($("#councilDropdown").val()) != "undefined" ){
$("#councilDropdown").val(data.PTCouncil_Id);
}else{
setTimeout(councilVal,50);
}
})()
}
}
Try creating two events on dropdown 1. custom event and 2. change event
When user manually changes then dropdown value then change event will be fired.
$('#dictrctDropdown').change(function (event){
$('#dictrctDropdown').trigger('custom');
});
$('#dictrctDropdown').on('custom', function (event, param1){
// Load council dropdown
if(param1){
$("#councilDropdown").val(param1);
}
});
from "/Address/GetPTPostalCode" success call back raise custom event for "dictrctDropdown"
function loadPTPostalCode()
{
if ($("#PostalCode").val() >= 1000) {
$.ajax({
url: '/Address/GetPTPostalCode',
type: "POST",
dataType: "json",
data: { postalCode: $("#PostalCode").val(), postalCodeExtension: $("#PostalCodeExtension").val() },
success: function (data) {
if (data != null) {
$.getJSON('disctrictURL','data to post (if any)',function(response){
//Load district dropdown
/*
$.each(items, function (index, item) {
// alert(opts.firstOption);
opts.childSelect.append(
$('<option/>')
.attr('value', item.Id)
.text(item.Name)
);
});
*/
$("#districtDropdown").val(data.PTDistrict_Id); // Set the Dropdown value
});
//Now use district id load council dropdown and set value
$.getJSON('councilURL','data to post (if any)',function(response){
//Council dropdown
$("#districtDropdown").val('council id'); // Set the Dropdown value
});
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert(textStatus)
}
});
}
Hope this will help !