Chris Chris - 4 months ago 60
jQuery Question

Why do I get periodic Uncaught TypeError: Cannot read property 'value' of undefined when setting the value of multiple dropdownlists?

I posted a question the other day about this type of error and have been looking for solutions and causes for this error and am not finding a suitable solution or cause for the issue I am running into, one of the causes and solutions I came across is this one


Uncaught TypeError: Cannot set property ‘foo’ of null, Uncaught TypeError: Cannot set property ‘foo’ of undefined
Related errors: TypeError: someVal is undefined, Unable to set property ‘foo’ of undefined or null reference

Attempting to write null or undefined as if it was an object. For example:

var someVal = null;
someVal.foo = 1;
How to fix this error: This too is usually caused by typos. Check the variable names near the line the error points to.


I have been over my html and variables that I have and I have no typos.

I then added a try catch in my function that populates my dropdownlists and here it is


TypeError: Cannot read property 'value' of undefined
at MaterialUpdateData (eval at (http://localhost:23289/Scripts/jquery-1.10.2.min.js:21:4994), :254:45)
at Object.success (eval at (http://localhost:23289/Scripts/jquery-1.10.2.min.js:21:4994), :290:13)
at c (http://localhost:23289/Scripts/jquery-1.10.2.min.js:21:26036)
at Object.fireWith [as resolveWith] (http://localhost:23289/Scripts/jquery-1.10.2.min.js:21:26840)
at k (http://localhost:23289/Scripts/jquery-1.10.2.min.js:23:14258)
at XMLHttpRequest.r (http://localhost:23289/Scripts/jquery-1.10.2.min.js:23:18646)


Here is the function for at MaterialUpdateData (eval at (http://localhost:23289/Scripts/jquery-1.10.2.min.js:21:4994), :254:45)

$("#Type").data('kendoDropDownList').value(parseInt(Material[0].MaterialTypeID));


Here is the function for Object.success (eval at (http://localhost:23289/Scripts/jquery-1.10.2.min.js:21:4994), :290:13)

function GetMaterialDataByID(id) {
$.ajax({
type: "GET",
url: URLParam.GetMaterialForUpdate + "?id=" + id,
contentType: "application/json; charset=utf-8",
success: function (data, textStatus, jqXHR) {
MaterialUpdateData(data);
}
})
}


Now the odd thing is that the error never happens at the exact same place, sometimes it points to this

$("#Category").data('kendoDropDownList').value(parseInt(Material[0].MaterialCategoryID));


or this

$("#ddBuyUOM").data('kendoDropDownList').value(parseInt(Material[0].PurchaseUOMID));


or this

$("#ddSellUOM").data('kendoDropDownList').value(Material[0].SellUOMID);


I have no idea what is happening with this and I been looking for solutions and or causes since yesterday and since this morning but am not getting any closer to a fixing my issue.

EDIT

So upon further investigation, I have noticed that my returned data sometimes is an array or sometimes its an object and have added my controls to a var and a typeof to each of my control vars and sometimes they come back as undefined.

To me this isn't making sense to me, sometimes I have to reselect the record multiple times before everything works right. Its safe to say my code is broken.

MaterialJS file
This is the file that is pertaining to all my issues, my apologies if its a little messy

$(document).ready(function () {
// Validation
MaterialValidation();

// Loading of dropdownlists
LoadCategoryDropdownlist();
LoadTypeDropdownlist();
//LoadSubTypeDropdownlist(1);
LoadActiveVendorDropdownlist();

GlobalScript.GetAllUOM("BuyUOM");
GlobalScript.GetAllUOM("SellUOM");

if (HomeStorage.Keys.AddOrEdit == "Add") {
console.log("Add");
}
else {
GetMaterialDataByID(HomeStorage.Keys.CurrentID);
}
});


function NewMaterialForVendor() {

}

// #region DropdownLists

// Category
function LoadCategoryDropdownlist() {
$.ajax({
type: "GET",
url: URLParam.GetMaterialCategory,
contentType: "application/json; charset=utf-8",
success: function (data, textStatus, jqXHR) {
ShowCategoryDropdownlist(data);
}
});

}
function ShowCategoryDropdownlist(catData) {
$("#Category").kendoDropDownList({
dataTextField: "MaterialCategory1",
dataValueField: "MaterialCategoryID",
dataSource: catData,
index: 0,
optionLabel: "Select Category"
});
}

// Type
function LoadTypeDropdownlist() {
$.ajax({
type: "GET",
url: URLParam.GetMaterialType,
contentType: "application/json; charset=utf-8",
success: function (data, textStatus, jqXHR) {
ShowTypeDropdownlist(data);
}
});
}
function ShowTypeDropdownlist(typeData) {
$("#Type").kendoDropDownList({
dataTextField: "MaterialType1",
dataValueField: "MaterialTypeID",
dataSource: typeData,
index: 0,
optionLabel: "Select Type",
change: function (e) {
//var dd = $("#SubType").data("kendoDropDownList");
//dd.enable(true);
//console.log(this.value());
LoadSubTypeDropdownlist(this.value());
}
});
}

// SubType
function LoadSubTypeDropdownlist(id) {
$.ajax({
type: "GET",
url: URLParam.GetMaterialSubType + "?id=" + id,
contentType: "application/json; charset=utf-8",
success: function (data, textStatus, jqXHR) {
ShowSubTypeDropdownlist(data);
}
});
//ShowSubTypeDropdownlist(data);
}
function ShowSubTypeDropdownlist(subData) {
$("#SubType").kendoDropDownList({
dataTextField: "MaterialSubType1",
dataValueField: "MaterialSubTypeID",
dataSource: subData,
index: 0,
optionLabel: "Select SubType",
change: function (e) {
//console.log(this.value());
}
});
}

// Active Vendors
function LoadActiveVendorDropdownlist() {
$.ajax({
type: "GET",
url: URLParam.GetActiveVendors,
contentType: "application/json; charset=utf-8",
success: function (data, textStatus, jqXHR) {
ShowActiveVendorDropdownlist(data);
}
});
}
function ShowActiveVendorDropdownlist(typeData) {
$("#DefaultVendor").kendoDropDownList({
dataTextField: "VendorName",
dataValueField: "VendorID",
dataSource: typeData,
index: 0,
optionLabel: "Select Vendor"
});
}


// #endregion

// #region New Material Data

function NewMaterialToSubmit() {
var mv = {
MaterialCategoryID: $("#Category").val(),
MaterialTypeID: $("#Type").val(),
MaterialSubTypeID: $("#SubType").val(),
DLength: $("#txtLength").val(),
DWidth: $("#txtWidth").val(),
DHeight: $("#txtSize").val(),
PurchaseUOMID: $("#ddBuyUOM").val(),
SellUOMID: $("#ddSellUOM").val(),
VendorID: $("#DefaultVendor").val(),
MaterialDetail: null,
Description: $("#txtDescription").val(),
PurchaseItemQuantity: $("#txtPurchaseQuantity").val(),
SellItemQuantity: $("#txtSellQuantity").val(),
NewPrice: null,
RemodelPrice: $("#txtRemodel").val(),
ServicePrice: $("#txtRemodel2").val()
};
console.log(mv);
return mv;
}

// #endregion

// #region Save Material

function SubmitNewMaterial() {
var newMaterial = NewMaterialToSubmit();
$.ajax({
type: "POST",
url: URLParam.AddNewMaterial,
dataType: "json",
contentType: "application/json; charset=utf-8",
data: JSON.stringify(newMaterial),
success: function (data, textStatus, jqXHR) { },
complete: function (e) {
ClearMaterialFields();
GetMaterialGridData();
//CloseTheWindow();
}
})
}

// #endregion

// #region Update Material By ID

function UpdateMaterial(id) {
var updatedMaterial = NewMaterialToSubmit();
$.ajax({
type: "POST",
url: URLParam.UpdateMaterial + "?id=" + id,
dataType: "json",
contentType: "application/json; charset=utf-8",
data: JSON.stringify(updatedMaterial),
success: function (data, textStatus, jqXHR) { },
complete: function (e) {
ClearMaterialFields();
GetMaterialGridData();
//CloseTheWindow();
}
})
}

// #endregion

// #region Get Material UpdateData

function MaterialUpdateData(Material) {

try{
//var categoryDropdown = $("#Category").data('kendoDropDownList');
//console.log(typeof (categoryDropdown));
//console.log(categoryDropdown);
$("#Category").data('kendoDropDownList').value(parseInt(Material[0].MaterialCategoryID));

$("#Type").data('kendoDropDownList').value(parseInt(Material[0].MaterialTypeID));

$("#ddBuyUOM").data('kendoDropDownList').value(parseInt(Material[0].PurchaseUOMID));
bu.text(Material[0].UnitOfMeasure);

$("#ddSellUOM").data('kendoDropDownList').value(Material[0].SellUOMID);
su.text(Material[0].UnitOfMeasure2);

var dv = $("#DefaultVendor").data('kendoDropDownList');//.value(Material[0].VendorID);
dv.text(Material[0].VendorName);


$("#txtDescription").val(Material[0].Description);
$("#txtWidth").val(Material[0].DWidth);
$("#txtLength").val(Material[0].DLength);
$("#txtSize").val(Material[0].DHeight);

$("#txtRemodel").val(Material[0].RemodelPrice);
$("#txtRemodel2").val(Material[0].ServicePrice);

$("#txtPurchaseQuantity").val(Material[0].PurchaseItemQuantity);
$("#txtSellQuantity").val(Material[0].SellItemQuantity);
}
catch (e) {
//alert(e);
console.log(e);
}

}

function GetMaterialDataByID(id) {
$.ajax({
type: "GET",
url: URLParam.GetMaterialForUpdate + "?id=" + id,
contentType: "application/json; charset=utf-8",
success: function (data, textStatus, jqXHR) {
MaterialUpdateData(data);
}
})
}

// #endregion

// #region Clear Material

function ClearMaterialFields() {
// Dropdowns

//$("#ddState").val(-1);

// End Dropdowns

$("#txtDescription").val("");
$("#txtDetail").val("");
$("#txtWidth").val("");
$("#txtLength").val("");
$("#txtSize").val("");

$("#txtPurchaseQuantity").val("");
$("#txtSellQuantity").val("");


}

// #endregion

// #region Validation

function ResetMaterialForm() {
$("#MaterialData").data("bootstrapValidator").resetForm();
}

function MaterialValidation() {
var validator = $("#MaterialData").bootstrapValidator({
//excluded: ':disabled',
//container: 'tooltip',
//feedbackIcons: {
// valid: "glyphicon glyphicon-ok",
// invalid: "glyphicon glyphicon-remove",
// validating: "glyphicon glyphicon-refresh"
//},
fields: {
description: {
message: "Description is required",
validators: {
notEmpty: {
message: "Please add Description"
}
}
},
detail: {
message: "Detail is required",
validators: {
notEmpty: {
message: "Please add Detail"
}
}
},
width: {
message: "Width is required",
validators: {
notEmpty: {
message: "Please add Width"
}
}
},
length: {
message: "Length is required",
validators: {
notEmpty: {
message: "Please add Length"
}
}
},
size: {
message: "Size is required",
validators: {
notEmpty: {
message: "Please add Size"
}
}
},
new1: {
message: "New is required",
validators: {
notEmpty: {
message: "Please add New"
}
}
},
new2: {
message: "New is required",
validators: {
notEmpty: {
message: "Please add New"
}
}
},
remodel: {
message: "Remodel is required",
validators: {
notEmpty: {
message: "Please add Remodel"
}
}
},
remodel2: {
message: "Remodel is required",
validators: {
notEmpty: {
message: "Please add Remodel"
}
}
},
quantity: {
message: "Quantity is required",
validators: {
notEmpty: {
message: "Please add Quantity"
}
}
},
quantity2: {
message: "Quantity2 is required",
validators: {
notEmpty: {
message: "Please add Quantity2"
}
}
},
uom: {
message: "UOM is required",
validators: {
notEmpty: {
message: "Please add UOM"
}
}
},
uom2: {
message: "UOM2 is required",
validators: {
notEmpty: {
message: "Please add UOM2"
}
}
}
}
});
}

// #endregion

function CloseTheWindow() {
$("#window").data("kendoWindow").destroy();
localStorage.clear();
}

$("#btnCloseMaterialEditor").click(function () {
ClearMaterialFields();
CloseTheWindow();
GetMaterialGridData();
});

$("#btnSaveMaterial").click(function () {

var validator = $("#MaterialData").data("bootstrapValidator");
validator.validate();
if (validator.isValid()) {

if (HomeStorage.Keys.AddOrEdit == "Add") {
SubmitNewMaterial();
ResetMaterialForm();
CloseTheWindow();
}
else if (HomeStorage.Keys.AddOrEdit == "Edit") {
UpdateMaterial(HomeStorage.Keys.CurrentID);
ResetMaterialForm();
CloseTheWindow();
}
}
});


My GlobalMethods script
This is a just in case anyone wanted to see where my populating of the BuyUOM and SellUOM is coming from

// #region Get IDS from Grid

var GlobalScript = {
GetAllStates: function () {
var self = this;
$.ajax({
type: "GET",
url: URLParam.GetStatesForDropdown,
contentType: "application/json; charset=utf-8",
success: function (data, textStatus, jqXHR) {
self.ShowStates(data);
// or this way
// GlobalScript.ShowStates(data);
}
})

},
ShowStates: function (stateData) {
$("#acVendorState").kendoDropDownList({
dataSource: stateData,
dataTextField: "StateName",
dataValueField: "StateID",
animation: false,
optionLabel: {
StateName: "-- Select State --"
}
});
},

GetAllUOM: function (whichDropdown) {
var self = this;
$.ajax({
type: "GET",
url: URLParam.GetUOMForDropdown,
contentType: "application/json; charset=utf-8",
success: function (data, textStatus, jqXHR) {
self.ShowUOM(data, whichDropdown);
// or this way
// GlobalScript.ShowStates(data);
}
});
},
ShowUOM: function (uomData, whichDropdown) {
$("#dd"+whichDropdown).kendoDropDownList({
dataSource: uomData,
dataTextField: "UnitOfMeasure1",
dataValueField: "UnitOfMeasureID",
animation: false,
index: 0,
optionLabel: {
UnitOfMeasure1: "Select"
}
//change: function (e) {
// var value = this.value();
// alert(value);
//}
});
},
GetGridCheckboxIDs: function (gridName, idToGet) {
var idsToSend = [];
var grid = $("#" + gridName).data("kendoGrid")
var ds = grid.dataSource.view();

for (var i = 0; i < ds.length; i++) {
var row = grid.table.find("tr[data-uid='" + ds[i].uid + "']");
var checkbox = $(row).find(".checkbox");
if (checkbox.is(":checked")) {
idsToSend.push(ds[i].idToGet);
}
}
HomeStorage.KeysAssignmentIDString = idsToSend;
}
}


Html
here is all my html for this script

@{
Layout = null;
}

<!DOCTYPE html>

<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>MaterialEditor</title>
<style>
.max-size {
max-width: 100%;
}

.nav-tabs > li.active > a,
.nav-tabs > li.active > a:hover,
.nav-tabs > li.active > a:focus {
color: white;
background-color: #347AB6;
}

.panel-heading {
border-top-left-radius: 0px;
border-top-right-radius: 0px;
}

.panel {
border-radius: 0px;
}

.k-window div.k-window-content {
overflow: hidden;
}
</style>
<script src="~/Scripts/Customjs/GlobalMethods/GlobalMethodsJS.js"></script>
</head>
<body>
<div class="form-horizontal">
<ul class="nav nav-tabs">
<li class="active"><a href="#MaterialData" data-toggle="tab">Material Data</a></li>
<li><a href="#MaterialColorAssignment" data-toggle="tab">Material Color Assignment</a></li>
</ul>

<div class="tab-content">

<div class="tab-pane active" id="MaterialData">
<div class="panel panel-primary">
<div class="panel panel-heading"><strong>Add/Edit Material</strong></div>
<div class="panel-body">
<div class="col-md-12">
<fieldset class="Myfieldset">
<div class="form-group">
<div class="col-md-4">
@*<select class="form-control max-size" name="categories" id="Category"></select>*@
<input id="Category" class="form-control max-size" />
</div>
<div class="col-md-4">
@*<select class="form-control" name="type" id="Type"></select>*@
<input id="Type" class="form-control max-size" />
</div>
<div class="col-md-4" id="myDropdown">
<select class="form-control" name="subtype" id="SubType"></select>
</div>
</div>

<div class="form-group">
<label for="txtDescription" class="control-label col-md-2" id="lblDetail"><b>Description</b></label>
<div class="col-md-9">
<input id="txtDescription" type="text" class="form-control max-size" name="description" />
</div>
@*<label for="txtDetail" class="control-label col-md-1" id="lblDetail"><b>Detail</b></label>
<div class="col-md-3">
<input id="txtDetail" type="text" class="form-control" name="detail" />
</div>*@
</div>
</fieldset>
</div>
</div>
<div class="panel panel-heading"><strong>Material Information</strong></div>
<div class="form-group">
<label for="txtWidth" class="control-label col-md-1 col-md-offset-1" id="lblWidth"><b>Width</b></label>
<div class="col-md-2">
<input id="txtWidth" type="text" class="form-control" name="width" />
</div>

<label for="txtLength" class="control-label col-md-1" id="lblLength"><b>Length</b></label>
<div class="col-md-2">
<input id="txtLength" type="text" class="form-control" name="length" />
</div>

<label for="txtSize" class="control-label col-md-1" id="lblSize"><b>Size</b></label>
<div class="col-md-2">
<input id="txtSize" type="text" class="form-control" name="size" />
</div>
</div>
<br />
<fieldset class="Myfieldset">

<div class="panel panel-primary col-md-6">
<div class="panel-heading">Pricing and Labor Cost</div>
<div class="panel-body">
<div class="row">
<label for="txtDescription" class="control-label col-md-offset-5" id="lblDetail"><b>Sell&nbsp;Price</b></label>
<label for="txtDescription" class="control-label col-md-offset-2" id="lblDetail"><b>Labor&nbsp;Cost</b></label>
</div><!-- end row -->

@*<div class="row">
<label for="txtNew" class="control-label col-md-2" id="lblNew">New</label>
<div class="col-md-4 col-md-offset-2">
<input id="txtNew" type="text" class="form-control" name="new1" />
</div>

<div class="col-md-4">
<input id="txtNew2" type="text" class="form-control" name="new2" />
</div>
</div>*@ <!-- end row -->

<br />

<div class="row">
<label for="txtRemodel" class="control-label col-md-2" id="lblRemodel">Remodel</label>
<div class="col-md-4 col-md-offset-2">
<input id="txtRemodel" type="text" class="form-control" name="remodel" />
</div>

<div class="col-md-4">
<input id="txtRemodel2" type="text" class="form-control" name="remodel2" />
</div>
</div> <!-- end row -->
<div class="row">
<br />
<br />
</div>

</div>

</div>

<div class="panel panel-primary col-md-6">
<div class="panel-heading">Purchasing and Sales</div>
<div class="panel-body">
<div class="row">
<div class="row">
<label for="txtDescription" class="control-label col-md-offset-5" id="lblDetail"><b>Purchase</b></label>
<label for="txtDescription" class="control-label col-md-offset-2" id="lblDetail"><b>Sell</b></label>
</div><!-- end row -->

<div class="row">
<label for="txtQuantity" class="control-label col-md-2" id="lblQuantity">Quantity</label>
<div class="col-md-4 col-md-offset-2">
<input id="txtPurchaseQuantity" type="text" class="form-control" name="purchasequantity" />
</div>

<div class="col-md-4">
<input id="txtSellQuantity" type="text" class="form-control" name="sellquantity" />
</div>
</div> <!-- end row -->

<br />

<div class="row">
<label for="txtUOM" class="control-label col-md-2" id="lblUOM">U.O.M</label>
<div class="col-md-1 col-md-offset-2">
<select class="form-control" name="buyuom" id="ddBuyUOM" style="width:100px;"></select>
</div>

<div class="col-md-1 col-md-offset-3">
<select class="form-control" name="selluom" id="ddSellUOM" style="width:100px;"></select>
</div>
</div> <!-- end row -->
</div>
</div>
</div>

<div class="form-group">
<label for="ddDefaultVendor" class="control-label col-md-2" id="lblDefaultVendor">Default Vendor</label>
<div class="col-md-9">
<select class="form-control" name="defaultvendor" id="DefaultVendor"></select>
</div>
</div>
</fieldset>
</div>
</div><!--End Material Data-->
<div class="tab-pane" id="MaterialColorAssignment">
<div class="panel panel-primary">
<div class="panel panel-heading"><strong>Add/Edit Material Color Assignment</strong></div>
<div class="panel-body">
<div id="MaterialColorAssignmentGrid">

</div>
</div>
</div>
</div><!--End Material Assignment-->
</div>

<div class="form-group col-md-12">
<button id="btnCloseMaterialEditor" type="button" class="btn btn-primary pull-right">Close</button> &nbsp;
<button id="btnSaveMaterial" type="button" class="btn btn-primary pull-right">Save</button>
@*<button id="btnTest" type="button" class="btn btn-danger pull-right">Test</button>*@
</div>

</div>
<script src="~/Scripts/Customjs/Material/MaterialEditorJS.js"></script>
</body>
</html>

Answer

You have a race condition.

Your KendoDropDownLists are only bound after the ajax calls to populate them (async), and your GetMaterialDataByID is calling MaterialUpdateData before they are all bound. This is why the error condition changes to different lines.

You could delay this call until all your kendoDropDownLists are available

function MaterialUpdateData(Material) {
    var category = $("#Category").data('kendoDropDownList');
    var type = $("#Type").data('kendoDropDownList');

    if (category == null || type == null)
       return setTimeout(function(){ MaterialUpdateData(Material); }, 20); // kendoDropLists not bound/populated yet