I am making a ajax calls that returns me some data from the server. I work on string function on the data that come from ajax call. From my knowledge i can see the string operation begins before the ajax call gets over. Often giving me undefined error. Here is my ajax call
$.ajax({
type: "POST",
url: "/add_director",
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
data: formData,
cache: false,
contentType: false,
processData: false,
success: function(data) {
$('#addDirModal').modal('hide');
insertDirector(data);
},
error : function(xhr ,status ,error)
{
console.log(xhr);
alert(xhr);
}
});
Here is my insertDirector function
function insertDirector(data){
console.log(data);
if (data.msg == "1") {
$.each(data,function(key,value){
var dir_name = value.dir_name;
var dir_pan = value.dir_pan;
var dir_din = value.dir_din;
var dir_addr = value.dir_addr;
var dir_id = value.id;
var dir_img = value.dir_img;
if (dir_name.val().length > 15) {
var dir_r_name = dir_name.substr(0,15);
}
else{
var dir_r_name = dir_name;
}
});
}
}
Here when i work on substr() it throws the error Cannot read property 'val' of undefined. I can see this is because the substr() is executed before the ajax request is completed. how do i fix this ?
EDITED
Here is the response
{"msg":"1","director":{"dir_name":"Naveen","dir_pan":"AAAAA1111B","dir_din":"123456","dir_addr":"dsadasdasdasdsadasdas","dir_img":"1490852438.jpg","user_id":3,"updated_at":"2017-03-30 05:40:38","created_at":"2017-03-30 05:40:38","id":15}}
Its not clear why you use the $.each here (you can omit it and use data.director instead of value), but if it is possible that your data contain several 'director' objects and you want to iterate through all of them, then you should change the insertDirector code to skip the 'msg' key as it doesn't have dir_name, dir_plan, ... properties:
function insertDirector(data) {
console.log(data);
if (data.msg == "1") {
$.each(data, function (key, value) {
if (key == "director") { //or if (key != "msg")
var dir_name = value.dir_name;
var dir_pan = value.dir_pan;
var dir_din = value.dir_din;
var dir_addr = value.dir_addr;
var dir_id = value.id;
var dir_img = value.dir_img;
var dir_r_name = (dir_name.length > 15 ? dir_name.substr(0, 15) : dir_name);
//if (dir_name.length > 15) {
// var dir_r_name = dir_name.substr(0, 15);
//}
//else {
// var dir_r_name = dir_name;
//}
}
});
}
}
also, note that dir_name.val().length is wrong as dir_name is a string (.val() is not required)
change
if (dir_name.val().length > 15) {
var dir_r_name = dir_name.substr(0,15);
}
to
if (dir_name.length > 15) {
var dir_r_name = dir_name.substr(0,15);
}
try this way :
function insertDirector(data) {
console.log(data);
if (data.msg == "1") {
var dir_name = data.director.dir_name;
var dir_pan = data.director.dir_pan;
var dir_din = data.director.dir_din;
var dir_addr = data.director.dir_addr;
var dir_id = data.director.id;
var dir_img = data.director.dir_img;
if (dir_name.length > 15) {
var dir_r_name = dir_name.substr(0, 15);
}
else {
var dir_r_name = dir_name;
}
}
}
After seeing the data you posted, it is easy to find issue.
Here, the issue is:
Your function:
function insertDirector(data){
console.log(data);
if (data.msg == "1") {
$.each(data,function(key,value){
var dir_name = value.dir_name;
var dir_pan = value.dir_pan;
var dir_din = value.dir_din;
var dir_addr = value.dir_addr;
var dir_id = value.id;
var dir_img = value.dir_img;
if (dir_name.val().length > 15) {
var dir_r_name = dir_name.substr(0,15);
}
else{
var dir_r_name = dir_name;
}
});
}
}
Here, when you do $.each, every object inside data will be traversed. Now, your first value inside data is msg:1. This is not a object. As a result, on first iteration, key is 'msg' but value is '1'. Now this value can't have dir_name so undefined is returned. As a result dir_name.val() generates error.
Try it like this:
function insertDirector(data){
console.log(data);
if (data.msg == "1") {
$.each(data,function(key,value){
if(key==="director"){
var dir_name = value.dir_name;
var dir_pan = value.dir_pan;
var dir_din = value.dir_din;
var dir_addr = value.dir_addr;
var dir_id = value.id;
var dir_img = value.dir_img;
if (dir_name.val().length > 15) {
var dir_r_name = dir_name.substr(0,15);
}
else{
var dir_r_name = dir_name;
}
}
});
}
}
Related
This is my JS code
getItemData:function(e){
var id = e.target.getAttribute('data-id');
var uom = e.target.options[e.target.options.selectedIndex].dataset.uom;
var uomId = e.target.options[e.target.options.selectedIndex].dataset.uomid;
if(uomId == null || uom == null){
$('#uom_item'+id).html('<option value="" selected></option>');
}
this.GetItemTotalAmount(id);
this.getItemGroupUOM(id);
this.getVatStructure(id);
},
getVatStructure:function (id)
{
var trans_sub_type = $('#trans_sub_type').val();
var prod_type = $('#product_type').val();
var hsCode = $('#hs_code'+id).val()
var defaultVatRate = $('#default_vat_rate_id'+id).val()
$.ajax({
url:'get-vat-structure-by/item',
method:'get',
data:{'tranSubType':trans_sub_type,'prod_type':prod_type,'hs_code':hsCode,'defaultVatRate':defaultVatRate},
success:function(res){
// console.log(res);
$('#vat_structure_rate'+id).html(res.result);
if (!res.isTrue)
{
$('#vat_item'+id).val(null);
$('#vat_amount_item'+id).val(null);
}
$('#vat_structure_rate'+id).trigger("change");
console.log('trg');
},
error:function(err){
console.log(err);
}
});
},
getVatData:function (e)
{
console.log('inside');
var id = e.target.getAttribute('data-id');
var vat = e.target.options[e.target.options.selectedIndex].dataset.vat;
$('#vat_item'+id).val(vat);
this.GetItemTotalAmount(id);
}
I want to trigger getVatData() which is an on change function declared in HTML as #change="getVatData" function from getVatStructure function.
How can I do that. I have tried the following but now working.
I have this code fragment:
if(!encryption_state){
if(cKey=="" || cKey==null){
cKey=getKey(aid); //here we trying to obtain key
if(cKey!="" && cKey!=null && cKey!=undefined){
if(isJSON(jKey) && encryption_state){
var tjKey = JSON.parse(jKey);
tjKey[aid] = cKey;
jKey = JSON.stringify(tjKey);
}else{
jKey = json.stringify({aid: cKey});
}
encryption_state=true;
}
}
if(!encryption_state){
if(cKey=="" || cKey==null){
cKey=rndstr(32); //generate string
}
var arr = {};
if(isJSON(jKey)) arr = JSON.parse(jKey);
arr[aid] = cKey;
jKey = JSON.stringify(arr);
encryption_state = true;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
But when i call getKey(kaid) function:
function getKey(kaid){
$.ajax({
method: "POST",
url: "/?mod=key&fnc=syncKey",
data: {
aid: kaid
},
done: function(data) {
var tret = (JSON.parse(data)['msg']);
return tret;
}
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Browsers don't continue do function getKey(), they do next commands in parent function, i don't know why they ignore web server answer and don't let function return server response :(
in general, an ajax call is asynchronous. That means, a sequence like
var a = 0;
a = getAwithAjaxFromServer(...);
console.log(a);
will immediately print "0" while the ajax is still runnng.
Your entire logic with cleyand encryption_state has to be put into the done function:
if(!encryption_state){
if(cKey=="" || cKey==null){
cKey=getKey(aid);
}
}
and in your ajax:
function getKey(kaid){
$.ajax({
method: "POST",
url: "/?mod=key&fnc=syncKey",
data: {
aid: kaid
},
done: function(data) {
var tret = (JSON.parse(data)['msg']);
.... PUT ALL THE LOGIC HERE .....
}
});
}
You must understand asynchronous mechanism in javascript to continue calling ajax. There are a lot of resources and stackoverflow questions. For example: https://www.pluralsight.com/guides/front-end-javascript/introduction-to-asynchronous-javascript
So, you can convert the code so:
if(!encryption_state){
var serverKeyCallback = function(cKey) {
if(cKey!="" && cKey!=null && cKey!=undefined){
if(isJSON(jKey) && encryption_state){
var tjKey = JSON.parse(jKey);
tjKey[aid] = cKey;
jKey = JSON.stringify(tjKey);
}else{
jKey = json.stringify({aid: cKey});
}
encryption_state=true;
}
};
var localKeyCallback = function(cKey) {
if(!encryption_state){
if(cKey=="" || cKey==null){
cKey=rndstr(32); //generate string
}
var arr = {};
if(isJSON(jKey)) arr = JSON.parse(jKey);
arr[aid] = cKey;
jKey = JSON.stringify(arr);
encryption_state = true;
}
}
manageKey(cKey, aid, serverKeyCallback, localKeyCallback);
}
function manageKey(cKey, kaid, serverKeyCallback, localKeyCallback) {
if(cKey=="" || cKey==null) {
$.ajax({
method: "POST",
url: "/?mod=key&fnc=syncKey",
data: {
aid: kaid
},
done: function(data) {
var tret = (JSON.parse(data)['msg']);
serverKeyCallback(tret);
localKeyCallback(tret);
}
});
}
else {
localKeyCallback(cKey);
}
}
Defining two encapsulated pieces of code, one to execute after serverResponse, and the other to execute after the serverResponse or when you have the cKey locally stored. I haven't tested the code, but it must work as you expect.
I am making a validation function, submitForm function is to check other function return value true or false, but I have this error, I don't know why.
Uncaught TypeError: Cannot read property 'length' of undefined
var ClassSignUpValidation = function (){};
ClassSignUpValidation.prototype.CheckName = function (_target)
{
return false;
}
ClassSignUpValidation.prototype.CheckPassword = function (_target)
{
return false;
}
//SUBMIT FORM VALIDATION
ClassSignUpValidation.prototype.SubmitForm = function (event)
{
var sumbit_errorspan = $("#submit-errorResult");
//array validation function
var validators = [this.CheckName, this.CheckPassword];
// bypass all function
var valid = validators.reduce(function(valid, validator){
return validator() && valid;
}, true);
if(valid){
sumbit_errorspan.html('');
}else{
sumbit_errorspan.css('color', 'red');
sumbit_errorspan.html('sumbit not requirements.');
}
return valid;
}
error point
ClassSignUpValidation.prototype.CheckName = function (_target)
{
//set target id to jquery
_target = "#" + _target;
//set variable
var username_target = $(_target);
var username_value = username_target.val();
var username_errorspan = $("#user-errorResult");
****//here is the error****
if (username_value.length >= 4){
$.ajax({
type:"POST",
url:"/main/class/classvalidation.php",
async:false,
data:{
"username": username_value
},
success: function(data)
{
var usernameAvailable = JSON.parse(data);
var color = usernameAvailable.exists ? "#dfe0e6" : "red";
username_errorspan.html(usernameAvailable.message);
username_errorspan.css("color", color);
username_target.css("border-color", color);
if(usernameAvailable.exists === true){
return true;
}
}
});
};
return false;
}
error here is the error point in
if (username_value.length >= 4){
Your IF statement should look like this:
username_value && username_value.length >= 4
That way you'll be sure that there is a value (and so an element as well) and that it's length is greater than 4.
Hello everybody. I have a problem with my code. I use the jquery framework. When I want to call $.ajax(requestOptions), function xmlParser(xml) don't working.
I try to find a resolve this problem, but I can't nothing find.
$(document).ready(function () {
var requestOptions = {
type: "GET", //The method
url: "Course_Valute_02-07-2014.xml", //It is reference on xml file
dataType: "xml", //The type of data
crossDomain: true, //Allow to do the cross-domain request
success: xmlParser //Calling function
};
function xmlParser(xml) {
$("#load").fadeOut();
$(xml).find("Valute").each(function() {
$("#outputListValutes").append(
"<option value=" + $(this).find("CharCode").text() + ">" + $(this).find("CharCode").text() + "</option>");
});
};
$.ajax(requestOptions);
$("#clear").click(function() {
var sumValue = document.getElementById("sum").value = "";
var resValue = document.getElementById("result").value = "";
});
$("#convert").click(function(xml) {
//var selectCurrency = $("#inputListCurrency").val();
//findData(xml);
}(requestOptions));
function findData(xml) {
var decimalOnly = /^\s*-?[1-9]\d*(\.\d{1,2})?\s*$/;
try{
var shortName = $("#outputListCurrency").val();
var value = $("#sum").val();
if(value == "") throw new Error("Empty value");
else if(!decimalOnly.test(value)) throw new Error("value must be of decimal digits");
else if(value < 0) throw new Error("Value isn't to be below zero");
else if(isNaN(parseFloat(value))) throw new Error("Value isn't to be as symbols");
$(xml).find("Valute").each(function() {
if(shortName == $(this).find("CharCode").text()) {
var nominal = $(this).find("Nominal").text();
var course = $(this).find("Value").text();
var result = parseFloat(value) * parseFloat(nominal) / parseFloat(course);
document.getElementById("result").value = Number(result).toFixed(2);
}
});
}
catch(e) {
alert(e);
}
}
});
change the success parameter of the request to use the xmlParser function (forgot () ):
var requestOptions = {
type: "GET", //The method
url: "Course_Valute_02-07-2014.xml", //It is reference on xml file
dataType: "xml", //The type of data
crossDomain: true, //Allow to do the cross-domain request
success: xmlParser(data) //Calling function
};
I found the solution this promlem. I am happy.
var courseFilePath = "xml/Course_Currency_02-07-2014.xml";
var listCurrency = [];
function insertOptions(){
for (var i = 0; i < listCurrency.length; ++i){
$("#outputListCurrency").append(
"<option value=" + listCurrency[i] + ">" + listCurrency[i] + "</option>");
}
}
function xmlParser(xml){
$("#load").fadeOut();
$(xml).find("Valute").each(function(){
var value = $(this).find("CharCode").text();
listCurrency.push(value);
});
listCurrency.sort();
};
function findData(xml){
var decimalOnly = /^\s*-?[0-9]\d*(\.\d{1,2})?\s*$/;
try {
var shortName = $("#outputListCurrency").val();
var value = $("#sum").val();
if (value == "") throw new Error("Empty value");
else if (!decimalOnly.test(value)) throw new Error("value must be of decimal digits");
else if (value < 0) throw new Error("Value isn't to be below zero");
else if (isNaN(parseFloat(value))) throw new Error("Value isn't to be as symbols");
$(xml).find("Valute").each(function(){
if (shortName == $(this).find("CharCode").text()){
var nominal = $(this).find("Nominal").text();
var course = $(this).find("Value").text();
var result = parseFloat(value) * parseFloat(nominal) / parseFloat(course);
document.getElementById("result").value = Number(result).toFixed(2);
}
});
}
catch (e){
alert(e);
}
}
$(document).ready(function(){
$.ajax({
type: "GET", //The method of sending for data
url: courseFilePath, //It is reference on xml file
dataType: "xml", //The type of data
success: function(xml){
xmlParser(xml);
insertOptions();
}
});
//insertOptions();
$("#clear").click(function() {
document.getElementById("sum").value = "";
document.getElementById("result").value = "";
});
$("#convert").click(function() {
var selectCurrency = $("#inputListCurrency").val();
$.get(courseFilePath, findData, "xml");
});
});
I have the following javascript and JsonResult. The issue I am having is the ajax post doesn't allow enough time for JsonResult to return the appropriate data. I probably don't completely understand javascript processing and I'm sure this is by design but I'm wondering how I can make this a synchronous request. In short, wait for the JsonResult action to complete before the javascript continues processing.
<script type="text/javascript">
$(document).ready(function () {
var table = document.getElementById("updateTable");
var tasks = new Array("shutdown", "prep", "boot", "ready");
var tasksLength = tasks.length;
for (var i in tasks) {
for (var loop = 1, max = table.rows.length; loop < max; loop++) {
id = table.rows[loop].cells[0].innerHTML;
task = tasks[i];
ImageUpdateStatus = {
ImageId: parseInt(id),
Task: task,
Status: "pending"
}
$.ajax({
type: "POST",
url: "UpdateStatus",
data: $.postify(ImageUpdateStatus),
success: function (data) {
var status = data.status;
}
});
ImageUpdateStatus.Status = status;
if (ImageUpdateStatus.Status == "success") {
task = task.concat(" ");
document.getElementById(task.concat(id)).src = "/PVSUtil_ver2/Assets/Images/Image.Success.png";
j = parseInt(i) + 1;
if (j < tasksLength) {
nextTask = tasks[j];
nextTask = nextTask.concat(" ");
document.getElementById(nextTask.concat(id)).src = "/PVSUtil_ver2/Assets/Images/Image.Load.gif";
}
}
}
}
document.getElementById('nextButton').className = "navigation";
document.getElementById('nextButton').disabled = false;
});
//
// GET: /Build/UpdateStatus
public JsonResult UpdateStatus(ImageUpdateStatus imageUpdateStatus, SessionStateItemCollection sessionItems = null)
{
var data = new object();
string status = null;
ImageInfo imageInfo = new ImageInfo();
IImageInfoServices svcImageInfo = new ImageInfoServicesRepository();
imageInfo = svcImageInfo.GetImageByImageId(imageUpdateStatus.ImageId);
IDeviceControlServices svcDevice = new DeviceControlServicesRespository();
IPVSCommandServices svcPVSCmds = new PVSCommandServicesRespository();
if (imageUpdateStatus.Task == "shutdown")
{
status = svcDevice.Shutdown(imageInfo.ImageId);
//status = "success";
data = new
{
status
};
}
if (imageUpdateStatus.Task == "prep")
{
List<UpdateReasonForm> updateReasonForms;
if (sessionItems.Keys.Count > 0)
{
updateReasonForms = sessionItems["UpdateReasonForms"] as List<UpdateReasonForm>;
}
else
{
updateReasonForms = Session["UpdateReasonForms"] as List<UpdateReasonForm>;
}
foreach (var item in updateReasonForms)
{
if (item.ImageId == imageInfo.ImageId)
{
status = svcPVSCmds.PrepImage(imageInfo, item.NewVersion);
}
}
data = new
{
status
};
}
if (imageUpdateStatus.Task == "boot")
{
status = svcDevice.Boot(imageInfo.ImageId);
data = new
{
status
};
}
if (imageUpdateStatus.Task == "ready")
{
status = "success";
data = new
{
status
};
}
return this.Json(data, JsonRequestBehavior.AllowGet);
}
Just move the code that relies on the result from the ajax request into the success callback function:
$.ajax({
type: "POST",
url: "UpdateStatus",
data: $.postify(ImageUpdateStatus),
success: function (data) {
ImageUpdateStatus.Status = data.status;
if (ImageUpdateStatus.Status == "success") {
task = task.concat(" ");
document.getElementById(task.concat(id)).src = "/PVSUtil_ver2/Assets/Images/Image.Success.png";
j = parseInt(i) + 1;
if (j < tasksLength) {
nextTask = tasks[j];
nextTask = nextTask.concat(" ");
document.getElementById(nextTask.concat(id)).src = "/PVSUtil_ver2/Assets/Images/Image.Load.gif";
}
}
}
});
You don't want to make the request synchronous; you want to put all code that depends on the result into your callback:
$.ajax({
type: "POST",
url: "UpdateStatus",
data: $.postify(ImageUpdateStatus),
success: function (data) {
var status = data.status;
ImageUpdateStatus.Status = status;
if (ImageUpdateStatus.Status == "success") {
task = task.concat(" ");
document.getElementById(task.concat(id)).src = "/PVSUtil_ver2/Assets/Images/Image.Success.png";
j = parseInt(i) + 1;
if (j < tasksLength) {
nextTask = tasks[j];
nextTask = nextTask.concat(" ");
document.getElementById(nextTask.concat(id)).src = "/PVSUtil_ver2/Assets/Images/Image.Load.gif";
}
}
}
});
$.ajax({
type: "POST",
async: false,
url: "UpdateStatus",
data: $.postify(ImageUpdateStatus),
success: function (data) {
var status = data.status;
}
});
but you really should avoid this, you should really look into making your application work with that wait for the ajax request
I really feel that you should aggregate any data you need to render your view for the first time on the server side and then push it down to the page. You could use JavaScript to do the rendering once the data is in the page (could be stored in JSON format in a hidden field) but I don't think it's optimal to have the page making an Ajax call when it's rendering for the first time.