Knockout children of children loading/options in MVC - javascript

I have problem loading children to my option list.
I create an order but I cannot Edit. It will not load the dropdownlists.
My goal is when I press Edit on an order.
It will have selected the current product in the dropdownlist on the orderitem.
And I want to put the price from Product Model to the view(when choosing an item from dropdownlist)
Is there any other way to populate the dropdownlist?
I will upload pictures.
Here is my code javascript code.
var Products = [];
//fetch categories from database
function LoadProducts(element) {
if (Products.length == 0) {
//ajax function for fetch data
$.ajax({
type: "GET",
url: '/Sales/GetProducts',
success: function (data) {
Products = data;
//render catagory
renderProducts(element);
}
})
}
else {
alert("else");
//render catagory to the element
renderProducts(element);
}
}
function renderProducts(element) {
var $ele = $(element);
$ele.empty();
$ele.append($('<option/>').val('0').text('Select'));
$.each(Products, function (i, val) {
$ele.append($('<option/>').val(val.ProductId).text(val.ProductName));
})
}
var Seats = [];
//fetch categories from database
function LoadSeats(element) {
if (Seats.length == 0) {
//ajax function for fetch data
$.ajax({
type: "GET",
url: '/Sales/GetSeats',
success: function (data) {
Seats = data;
//render catagory
renderSeats(element);
}
})
}
else {
//render catagory to the element
renderSeats(element);
}
}
function renderSeats(element) {
var $ele = $(element);
$ele.empty();
$ele.append($('<option/>').val('0').text('Select'));
$.each(Seats, function (i, val) {
$ele.append($('<option/>').val(val.SeatId).text(val.SeatPlace));
})
}
var Employees = [];
//fetch categories from database
function LoadEmployees(element) {
if (Employees.length == 0) {
//ajax function for fetch data
$.ajax({
type: "GET",
url: '/Sales/GetEmployees',
success: function (data) {
Employees = data;
//render catagory
renderEmployees(element);
}
})
}
else {
//render catagory to the element
renderEmployees(element);
}
}
function renderEmployees(element) {
var $ele = $(element);
$ele.empty();
$ele.append($('<option/>').val('0').text('Select'));
$.each(Employees, function (i, val) {
$ele.append($('<option/>').val(val.EmployeeId).text(val.EmployeeName));
})
}
var PaymentMethods = [];
//fetch categories from database
function LoadPaymentMethods(element) {
if (PaymentMethods.length == 0) {
//ajax function for fetch data
$.ajax({
type: "GET",
url: '/Sales/GetPaymentMethods',
success: function (data) {
PaymentMethods = data;
//render catagory
renderPaymentMethods(element);
}
})
}
else {
//render catagory to the element
renderPaymentMethods(element);
}
}
function renderPaymentMethods(element) {
var $ele = $(element);
$ele.empty();
$ele.append($('<option/>').val('0').text('Select'));
$.each
(PaymentMethods, function (i, val) {
$ele.append
($('<option/>')
.val(val.PaymentMethodId)
.text(val.PaymentMethodType));
})
}
var ObjectState = {
Unchanged: 0,
Added: 1,
Modified: 2,
Deleted: 3
};
LoadProducts($('#productCategory'));
var salesOrderItemMapping = {
'SalesOrderItems': {
key: function (salesOrderItem) {
// alert("Salesorderitem mapping key");
return ko.utils.unwrapObservable(salesOrderItem.SalesOrderItemId);
},
create: function (options) {
console.log(options);
return new SalesOrderItemViewModel(options.data);
}
}
};
//var productItemMapping = {
// 'Products': {
// key: function(product) {
// return ko.utils.unwrapObservable(product.ProductId);
// },
// create: function(options) {
// return new SalesOrderViewModel(options.data);
// }
// }
//};
// ko.mapping.fromJS(data, productItemMapping, SalesOrderViewModel);
SalesOrderItemViewModel = function (data) {
//alert("salesorder item view"); // funkade
var self = this;
ko.mapping.fromJS(data, salesOrderItemMapping, self);
//dd: ko.observableArray(Products);
self.itemss = ko.observableArray(Products);
self.selectedItem = ko.observable(Products.ProductId);
//self.product1 = ko.observableArray(Products());
//self.dd = ko.observableArray(function() {
// //data.ProductId = data.Products.ProductId;
// return self.Products();
//});
self.flagSalesOrderAsEdited = function() {
if (self.ObjectState() !== ObjectState.Added) {
self.ObjectState(ObjectState.Modified);
}
// alert("salesorder item view if");
return true;
};
};
SalesOrderViewModel = function (data) {
var self = this;
ko.mapping.fromJS(data, salesOrderItemMapping, self);
//alert("salesorder view model"); // funkade
self.save = function () {
$.ajax({
url: "/Sales/Save/",
type: "POST",
data: ko.toJSON(self),
contentType: "application/json",
success: function (data) {
if (data.salesOrderViewModel !== null)
ko.mapping.fromJS(data.salesOrderViewModel, {}, self);
if (data.newLocation !== null)
window.location = data.newLocation;
}
});
},
self.flagSalesOrderAsEdited = function () {
if (self.ObjectState() !== ObjectState.Added) {
self.ObjectState(ObjectState.Modified);
}
return true;
},
self.deleteSalesOrderItem = function(salesOrderItem) {
self.SalesOrderItems.remove(this);
if (salesOrderItem.SalesOrderItemId() > 0 &&
self.SalesOrderItemsToDelete.indexOf
(salesOrderItem.SalesOrderItemId()) === -1)
self.SalesOrderItemToDelete.push(SalesOrderItemId());
}
self.addSalesOrderItem = function () {
// alert(" add salesorder item"); // funkade
var salesOrderItem = new SalesOrderItemViewModel(
{ SalesOrderItemId: 0, ProductId: 1, Quantity: 1,
ObjectState: ObjectState.Added });
self.SalesOrderItems.push(salesOrderItem);
};
};
//UnitPrice: 1
LoadSeats($('#SeatId'));
LoadEmployees($('#EmployeeId'));
LoadPaymentMethods($('#PaymentMethodId'));
Here is my Edit Partial view.
<table class="table table-striped">
<tr>
<th>Product Name</th>
<th>Quantity</th>
#*<th>Unit Price</th>*#
<th><button class="btn btn-info btn-xs"
data-bind="click: addSalesOrderItem">Add</button></th>
</tr>
<tbody data-bind="foreach: SalesOrderItems">
<tr>
<td>
#*<select id="productCategory" class="pc form-control"
data-bind="value: ProductId">
<option>Select</option>
</select>*#
#*<select data-bind="options: $parent.product1,
optionsText: 'ProductName', optionsValue: 'ProductId',
value: ProductId"></select>*#
<select data-bind=
"options: itemss, optionsText: 'ProductName',
value: ProductId, optionsValue: 'ProductId',
selectedOption: selectedOption"> </select>
</td>
#*<td class="form-group">
<input class="form-control input-sm" data-bind="value: ProductId" /></td>*#
<td class="form-group">
<input class="form-control input-sm" data-bind="value: Quantity"/></td>
#*<td class="form-group">
<input class="form-control input-sm" data- bind="text: UnitPrice"/></td>*#
<td class="form-group">Delete</td>
</tr>
</tbody>
</table>
Here it is when I create
Here it is when I Edit an order
And I get this problem when I save
I have problem loading children to my option list.
I create an order but I cannot Edit. It will not load the dropdownlists.
My goal is when I press Edit on an order.
It will have selected the current product in the dropdownlist on the orderitem.
And I want to put the price from Product Model to the view(when choosing an item from dropdownlist)
I will upload pictures.
I would like a road to follow. I am new to knockout/mvc and I cant find examples on mapping. I would appriatiate any feedpack or steps I can use.
If you need more from me, just write.
Thank you!!!
This is my Create View btw(how it is linked to knockout)
#model TheSolution.Domain.viewModels.SalesOrderViewModel
#using System.Web.Script.Serialization
#{
ViewBag.Title = "Create Sales Order";
}
#{
string data = new JavaScriptSerializer().Serialize(Model);
}
#section scripts
{
<script src="~/Scripts/knockout-3.4.0.js"></script>
<script src="~/Scripts/knockout.mapping-latest.js"></script>
<script src="~/Scripts/salesorderviewmodel.js"></script>
<script type="text/javascript">
var salesOrderViewModel = new SalesOrderViewModel(#Html.Raw(data));
ko.applyBindings(salesOrderViewModel);
</script>
}
#Html.Partial("_EditSalesOrder");

Since Ajax is loading asyc. It didnt had the time to load.
To fix the Edit problem with loading my Dropdown list. I used an ajaxStop in the Views(Create and Edit) It waits until ajax have loaded before GET the view
Here is the code
$(document).ajaxStop(function (event, request, settings) {
var salesOrderViewModel = new SalesOrderViewModel(#Html.Raw(data));
ko.applyBindings(salesOrderViewModel);
});
And with the price I had to do an ko ArrayFirst to match the ProductId observable with the ProductId in the Products Array(the one I loaded with Ajax)
And it would return the UnitPrice value from that row in the model.
This is how it looks like.
self.findItem = function () {
console.log(self.itemss().length);
var thePrice = ko.utils.arrayFirst(self.itemss(), function (item) {
return item.ProductId === self.ProductId();
}).UnitPrice;
console.log(thePrice);
return thePrice * self.Quantity();
}

Related

DataTable replicating rows

I have a panel where I take data from a view in database, and show them. The data are being showed but it is being replicated 3 times, I mean, each row apears 3 times in my table (panel).
When I use my filters, the data apears only one time though, as it should be.
I thought that I was calling my function "criarDataTables()" 3 times, but this is not the case.
This is in my Index.cshtml:
#section Scripts{
#Scripts.Render("~/bundles/typeahead")
#Scripts.Render("~/bundles/datatables")
#Scripts.Render("~/Scripts/js/bootstrap-datapicker.js")
#Scripts.Render("~/Scripts/js/bootstrap-datepicker.pt-BR.js")
#Scripts.Render("~/Scripts/jQuery-Mask/jquery.mask.min.js")
<script type="text/javascript">
var tbPainelTriagem;
var reload = false;
function criarDataTables() {
tbPainelTriagem = $("#tb-triagem").DataTable({
searching: false,
processing: true,
serverSide: true,
ajax: {
url: "/PainelTriagem/ListaPainelTriagem",
type: "POST",
data: {
customSearch: {
[...]
}
}
},
columns: [
{ data: "ID_VIEW" },
{ data: "TIPO" },
[...]
],
columnDefs: [
],
drawCallback: function (settings, json) {
$("#frm-filtro :input").prop("disabled", false);
}
});
}
$(document).ready(function () {
var listaDs;
$('#dsUnidIntField').attr("autocomplete", "off");
$('#dsUnidIntField').typeahead({
name: 'resultDs',
limit: 200,
minLength: 0,
source: function (query, process) {
itens = [];
listaDs = {};
$.post('/PainelTriagem/DsAutocomplete', { query: query }, function (data) {
$.each(data, function (i, item) {
listaDs[item.Nome] = item;
itens.push(item.Nome);
});
process(itens);
});
},
updater: function (item) {
var ds = listaDs[item];
$('#ID_VIEW', '#frm-filtro').val(ds);
return ds.Nome;
}
});
criarDataTables();
})
</script>
}
[...]
<table id="tb-triagem" class="table table-striped table-bordered dataTableLayout">
<thead>
<tr>
<th>ID View</th>
<th>Tipo</th>
[...]
</tr>
</thead>
</table>
This is in my PainelTriagemController.cs
using [...]
namespace PainelMV.Controllers
{
public class PainelTriagemController : Controller
{
[...]
[HttpPost]
public ActionResult ListaPainelTriagem(HCDataTableRequest<PainelTriagem> dataTableRequest)
{
try
{
HCDataTableResponse<PainelTriagemViewModel> dataTable = MyPainelTriagemManager
.ToList(dataTableRequest).CastViewModel(x => new PainelTriagemViewModel
{
ID_VIEW = x.ID_VIEW,
TIPO = x.TIPO == null ? " - " : x.TIPO.ToString(),
[...]
});
return Json(dataTable);
}
catch(Exception ex)
{
return Json(new { success = false, message = ex.Message });
}
}
}
}
And this is in my PainelTriagemStore.cs
using [...]
namespace PainelMV.Data.Store
{
public class PainelTriagemStore : BaseStore<PainelTriagem, AppContext>
{
public PainelTriagemStore(AppContext context): base(context) { }
public HCDataTableResponse<PainelTriagem> ToList(HCDataTableRequest<PainelTriagem> dataTableRequest)
{
try
{
HCDataTableResponse<PainelTriagem> response = new HCDataTableResponse<PainelTriagem>();
var qr = _context.PainelTriagem.AsQueryable();
response.recordsTotal = qr.Count();
int? tipo = dataTableRequest.GetCustomSearchInt("tipo");
string nmPaciente = dataTableRequest.GetCustomSearchString("nmPaciente");
[...]
if (tipo != null)
{
qr = qr.Where(x => x.TIPO == tipo);
}
[...]
response.recordsFiltered = qr.Count();
qr = qr.OrderAndPaging(dataTableRequest);
response.data = qr.ToList();
return response;
}
catch(Exception ex)
{
throw ex;
}
}
}
}

Knock out Array doesn't seem to be correct in UI

I have a drop down that's dynamically created, when it first get's created it has 9 objects with different properties. When you click on an option it goes out and grabs more info and in this case gets 3 new objects. But when it updates it goes from this:
Initial drop down Selection
to This:
Updated List after click
The objects are updated and when console logged they both look good. However, it appears to be updating by how many items are in the array
view:
#if (Model.SubMenu.Count > 8)
{
<li style="display:inline;" id="MenuSearch">
<input id="MenuSearchInput" class="form-control" type="text" style="margin:9px; width:90%" placeholder="Search" data-bind="value: query, valueUpdate: 'keyup'">
</li>
<li class="divider"></li>
<li id="MenuSearchItem" role="menuitem" data-bind="foreach: FilteredItems">
<a data-bind="text: name, click: Inventory.GetDomainFacilities"></a>
</li>
}
ViewModel:
(function (i) {
"use strict";
var vm = i.ViewModels || (i.ViewModels = {});
vm.DomainSwitchViewModel = function (menuItem) {
var self = this;
var data = menuItem;
self.query = ko.observable('');
self.AllMenuItems = ko.observableArray([]);
self.Update = function (data) {
var mappedItems = _.map(data, function (item) {
if (item.FacilityID) {
return {
id: item.FacilityID,
name: item.FacilityName,
type: 'Facility',
href: '/Home/SwitchDomain?' + 'domainID=' + item.DomainID + 'facilityID=' + item.FacilityID
}
}
else {
return {
id: item.DomainID,
name: item.Name,
type: 'Domain',
href: ''
}
}
})
self.AllMenuItems(mappedItems);
};
self.FilteredItems = ko.computed(function () {
var allItems = self.AllMenuItems();
var search = self.query().toLowerCase();
return ko.utils.arrayFilter(allItems, function (item) {
return item.name.toLowerCase().indexOf(search) >= 0;
});
});
self.Update(menuItem);
}
window.Inventory = i;
})(window.Inventory || {});
GetDomainFacilities:
i.GetDomainFacilities = function (menuItem) {
$.ajax({
type: 'GET',
url: '/InventoryBase/GetDomainFacilities',
data: { domainID: menuItem.id },
contentType: 'application/json',
dataType: 'json',
success: function (data) {
var updatedMenuItem = JSON.parse(data);
vm.Update(updatedMenuItem);
ko.cleanNode(document.getElementById("DropDownNavMenus"))
ko.applyBindings(vm, document.getElementById("DropDownNavMenus"));
}
});
}

Windows Azure + DevExrpess (PhoneJs) getting ToDoList (Standart Sample)

I'm starting to learn and azure phonejs.
Todo list get through a standard example:
$(function() {
var client = new WindowsAzure.MobileServiceClient('https://zaburrito.azure-mobile.net/', 'key');
var todoItemTable = client.getTable('todoitem');
// Read current data and rebuild UI.
// If you plan to generate complex UIs like this, consider using a JavaScript templating library.
function refreshTodoItems() {
var query = todoItemTable.where({ complete: false });
query.read().then(function(todoItems) {
var listItems = $.map(todoItems, function(item) {
return $('<li>')
.attr('data-todoitem-id', item.id)
.append($('<button class="item-delete">Delete</button>'))
.append($('<input type="checkbox" class="item-complete">').prop('checked', item.complete))
.append($('<div>').append($('<input class="item-text">').val(item.text)));
});
$('#todo-items').empty().append(listItems).toggle(listItems.length > 0);
$('#summary').html('<strong>' + todoItems.length + '</strong> item(s)');
}, handleError);
}
function handleError(error) {
var text = error + (error.request ? ' - ' + error.request.status : '');
$('#errorlog').append($('<li>').text(text));
}
function getTodoItemId(formElement) {
return $(formElement).closest('li').attr('data-todoitem-id');
}
// Handle insert
$('#add-item').submit(function(evt) {
var textbox = $('#new-item-text'),
itemText = textbox.val();
if (itemText !== '') {
todoItemTable.insert({ text: itemText, complete: false }).then(refreshTodoItems, handleError);
}
textbox.val('').focus();
evt.preventDefault();
});
// Handle update
$(document.body).on('change', '.item-text', function() {
var newText = $(this).val();
todoItemTable.update({ id: getTodoItemId(this), text: newText }).then(null, handleError);
});
$(document.body).on('change', '.item-complete', function() {
var isComplete = $(this).prop('checked');
todoItemTable.update({ id: getTodoItemId(this), complete: isComplete }).then(refreshTodoItems, handleError);
});
// Handle delete
$(document.body).on('click', '.item-delete', function () {
todoItemTable.del({ id: getTodoItemId(this) }).then(refreshTodoItems, handleError);
});
// On initial load, start by fetching the current data
refreshTodoItems();
});
and it works!
Changed for the use of phonejs and the program stops working, even mistakes does not issue!
This my View:
<div data-options="dxView : { name: 'home', title: 'Home' } " >
<div class="home-view" data-options="dxContent : { targetPlaceholder: 'content' } " >
<button data-bind="click: incrementClickCounter">Click me</button>
<span data-bind="text: listData"></span>
<div data-bind="dxList:{
dataSource: listData,
itemTemplate:'toDoItemTemplate'}">
<div data-options="dxTemplate:{ name:'toDoItemTemplate' }">
<div style="float:left; width:100%;">
<h1 data-bind="text: name"></h1>
</div>
</div>
</div>
</div>
This my ViewModel:
Application1.home = function (params) {
var client = new WindowsAzure.MobileServiceClient('https://zaburrito.azure-mobile.net/', 'key');
var todoItemTable = client.getTable('todoitem');
var toDoArray = ko.observableArray([
{ name: "111", type: "111" },
{ name: "222", type: "222" }]);
var query = todoItemTable.where({ complete: false });
query.read().then(function (todoItems) {
for (var i = 0; i < todoItems.length; i++) {
toDoArray.push({ name: todoItems[i].text, type: "NEW!" });
}
});
var viewModel = {
listData: toDoArray,
incrementClickCounter: function () {
todoItemTable = client.getTable('todoitem');
toDoArray.push({ name: "Zippy", type: "Unknown" });
}
};
return viewModel;
};
I can easily add items to the list of programs, but from the server list does not come:-(
I am driven to exhaustion and can not solve the problem for 3 days, which is critical for me!
Specify where my mistake! Thank U!
I suggest you use a DevExpress.data.DataSource and a DevExpress.data.CustomStore instead of ko.observableArray.
Application1.home = function (params) {
var client = new WindowsAzure.MobileServiceClient('https://zaburrito.azure-mobile.net/', 'key');
var todoItemTable = client.getTable('todoitem');
var toDoArray = [];
var store = new DevExpress.data.CustomStore({
load: function(loadOptions) {
var d = $.Deferred();
if(toDoArray.length) {
d.resolve(toDoArray);
} else {
todoItemTable
.where({ complete: false })
.read()
.then(function(todoItems) {
for (var i = 0; i < todoItems.length; i++) {
toDoArray.push({ name: todoItems[i].text, type: "NEW!" });
}
d.resolve(toDoArray);
});
}
return d.promise();
},
insert: function(values) {
return toDoArray.push(values) - 1;
},
remove: function(key) {
if (!(key in toDoArray))
throw Error("Unknown key");
toDoArray.splice(key, 1);
},
update: function(key, values) {
if (!(key in toDoArray))
throw Error("Unknown key");
toDoArray[key] = $.extend(true, toDoArray[key], values);
}
});
var source = new DevExpress.data.DataSource(store);
// older version
store.modified.add(function() { source.load(); });
// starting from 14.2:
// store.on("modified", function() { source.load(); });
var viewModel = {
listData: source,
incrementClickCounter: function () {
store.insert({ name: "Zippy", type: "Unknown" });
}
};
return viewModel;
}
You can read more about it here and here.

KnockoutJS - ViewModel (Grandparent - Parent - Child) Accessing a Parent Function within Child element

I have a Grandparent, Parent, Child ViewModel relationship setup in knockout and knockout mapping, CustomerViewModel, WorkOrderViewModel, and RepairViewModel.
For each level I flag if the record has been Modified. Then I have a save button that saves the entire Model. The function that Saves the Model is within the Grandparent ViewModel (CustomerViewModel)
Example of a Child level element
<input class="form-control input-sm text-right" name="RepairCost" id="RepairCost" data-bind="value: RepairCost, event: {change: flagRepairAsEdited}" />
Is there a way within the flagRepairAsEdited function I can call the SAVE function within the parent/grandparent?
Thanks so much!
Here is the JS code I'm using (simplified):
var ObjectState = {
Unchanged: 0,
Added: 1,
Modified: 2,
Deleted: 3
};
var workOrderMapping = {
'WorkOrders': {
key: function (workOrders) {
return ko.utils.unwrapObservable(workOrders.WorkOrderId);
},
create: function (options) {
return new WorkOrderViewModel(options.data);
}
},
'Repairs': {
key: function (repairs) {
return ko.utils.unwrapObservable(repairs.RepairId);
},
create: function (options) {
return new RepairViewModel(options.data);
}
}
};
RepairViewModel = function (data) {
var self = this;
ko.mapping.fromJS(data, workOrderMapping, self);
self.flagRepairAsEdited = function () {
if (self.ObjectState() != ObjectState.Added) {
self.ObjectState(ObjectState.Modified);
}
//WOULD LOVE TO CALL SAVE FUNCTION HERE
return true;
}
;
}
WorkOrderViewModel = function (data) {
var self = this;
ko.mapping.fromJS(data, workOrderMapping, self);
self.flagWorkOrderAsEdited = function () {
if (self.ObjectState() != ObjectState.Added) {
self.ObjectState(ObjectState.Modified);
}
//WOULD LOVE TO CALL SAVE FUNCTION HERE
return true;
}
;
}
CustomerViewModel = function (data) {
var self = this;
ko.mapping.fromJS(data, workOrderMapping, self);
self.save = function () {
$.ajax({
url: "/Customers/Save/",
type: "POST",
data: ko.toJSON(self),
contentType: "application/json",
success: function (data) {
ko.mapping.fromJS(data.customerViewModel, workOrderMapping, self);
if (data.newLocation != null)
window.location = data.newLocation;
},
});
},
self.flagCustomerAsEdited = function () {
if (self.ObjectState() != ObjectState.Added) {
self.ObjectState(ObjectState.Modified);
}
return true;
}
;
}
There are 2 ways to do this
a) Pass viewModels as parameters of the child flagRepairAsEdited function:
data-bind="value: RepairCost, event: {change: flagRepairAsEdited.bind($data, $parent, $root)}"
b) Save the link of the parent viewModel inside child viewModel
WorkOrderViewModel = function (data, parent) {
this.parent = parent;
...
}
And use parent.flagWorkOrderAsEdited and parent.parent.flagWorkOrderAsEdited to save parent and grandparent viewmodels

JQuery - Callback Dropdownlist load

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 !

Categories