I apologize if this is a duplicated question somewhere but I could not find an answer that works.
I have an .aspx page that is calling a webservice which populates basic employee information. It works great when I call the service outside of a custom object. As soon as I move the ajax functionality into the custom object, I lose scope and cannot populate the object properties. I can see that the service is returning data in the json via Firebug but the object's properties do not get populated. Any help on this is greatly appreciated. The custom object JavaScript is below.
/* Begin Employee JavaScript object */
//Define the Employee object
function Employee() {}
//Define the Employee object's properties on the prototype
Employee.prototype = {
//Properties
EmployeeNumber: '',
FirstName: '',
LastName: '',
ErrorMessage: '',
IsFound: false
}
//Define the Search function
Employee.prototype.employeeSearch = function (pEmplNo, callback) {
$.ajax({
context: this,
type: "POST",
url: "webservice URL",
data: '{"pEmployeeNumber":"' + pEmplNo + '"}',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
var me = this;
me.EmployeeNumber = msg.d.EmployeeNumber;
me.FirstName = msg.d.FirstName;
me.LastName = msg.d.LastName;
me.ErrorMessage = '';
me.IsFound = true;
callback(me);
},
error: function () {
var me = this;
me.ErrorMessage = 'Error retrieving employee';
me.IsFound = false;
}
});
}
/* End Employee JavaScript object */
function SetEmployeeFields(pEmployee) {
$('#<%= txtEmployeeNumber.ClientID %>').val(pEmployee.EmployeeNumber);
$('#<%= txtFirstName.ClientID %>').val(pEmployee.FirstName);
$('#<%= txtLastName.ClientID %>').val(pEmployee.LastName);
}
function FindEmployee(emplNo) {
$("#mdlGetEmployeeDialog").dialog('open');
if (emplNo.length < 6) {
while (emplNo.length < 6) {
emplNo = "0" + emplNo;
}
$('#<%= txtEmployeeNumber.ClientID %>').val(emplNo);
}
var _employee = new Employee();
_employee.employeeSearch(emplNo, function () {
if (_employee.IsFound) {
SetEmployeeFields(_employee);
$('#<%= txtNature.ClientID %>').focus();
$("#mdlGetEmployeeDialog").dialog('close');
}
else {
$('#<%= lblMessage.ClientID %>').text('Could not find employee' + _employee.ErrorMessage);
$('#<%= upErrors.ClientID %>').addClass("ui-state-error").css({ "padding": "4px", "margin-top": "4px" }).show();
$("#mdlGetEmployeeDialog").dialog('close');
}
});
}
//Sets up the Employee Search modal and button
function SetupGetEmployeeModal() {
$("#mdlGetEmployeeDialog").dialog({
autoOpen: false,
modal: true,
width: 500
});
$("#btnEmployeeSearch").button({
text: false,
icons: {
primary: "ui-icon-search"
}
}).css({
'padding': '4px 0px 4px 0px',
'font-size': '9px',
'margin-left': '3px'
});
}
$(function () {
$('#btnEmployeeSearch').click(function (e) {
e.preventDefault();
var emplNo = $('#<%= txtEmployeeNumber.ClientID %>').val();
if (emplNo !== '' && emplNo !== '######') {
$('#<%= lblMessage.ClientID %>').text('');
$('#<%= upErrors.ClientID %>').removeClass('ui-state-error').removeAttr('style').hide();
FindEmployee(emplNo);
}
else {
$('#<%= lblMessage.ClientID %>').text('Employee Number required');
$('#<%= upErrors.ClientID %>').addClass("ui-state-error").css({ "padding": "4px", "margin-top": "4px" }).show();
$("#mdlGetEmployeeDialog").dialog('close');
}
});
});
/* End Page Scripts */
4 Answers 4
Ajax is asynchronous. You need to add a callback to your employeeSearch method so that you can act upon it's success.
Employee.prototype.employeeSearch = function (pEmplNo,callback) {
...
success: function (msg) {
this.EmployeeNumber = msg.d.EmployeeNumber;
this.FirstName = msg.d.FirstName;
this.LastName = msg.d.LastName;
this.ErrorMessage = '';
this.IsFound = true;
callback(this);
},
...
}
Now, use the callback later:
var _employee = new Employee();
_employee.employeeSearch(emplNo, function () {
if (_employee.IsFound) {
SetEmployeeFields(_employee);
$("#mdlGetEmployeeDialog").dialog('close');
}
else {
$('#<%= lblMessage.ClientID %>').text('Could not find employee'+ _employee.ErrorMessage);
$('#<%= upErrors.ClientID %>').addClass("ui-state-error").css({ "padding": "4px", "margin-top": "4px" }).show();
$("#mdlGetEmployeeDialog").dialog('close');
}
});
1 Comment
You need to scope your variables inside your callback functions:
success: function (msg) {
this.EmployeeNumber = msg.d.EmployeeNumber;
this.FirstName = msg.d.FirstName;
this.LastName = msg.d.LastName;
this.ErrorMessage = '';
this.IsFound = true;
},
error: function () {
this.ErrorMessage = 'Error retrieving employee';
this.IsFound = false;
}
1 Comment
EDIT:
So it looks like your properties are getting set, but since it's asynchronous, it is not populated yet, you should move this to the ajax callback:
if (_employee.IsFound) {
SetEmployeeFields(_employee);
$("#mdlGetEmployeeDialog").dialog('close');
}
else {
$('#<%= lblMessage.ClientID %>').text('Could not find employee'+ _employee.ErrorMessage);
$('#<%= upErrors.ClientID %>').addClass("ui-state-error").css({ "padding": "4px", "margin-top": "4px" }).show();
$("#mdlGetEmployeeDialog").dialog('close');
}
3 Comments
Aside from scoping your properties, as Kevin-B pointed out, you have to execute the code that comes after the call to employeeSearch, in the success method.
Javascript is asynchronous so after the ajax call is made, the rest of the code is executed.
Another thing you can do is use a library that help you make synchronous calls. Using such a library you can make your code to execute when the ajax call has returned.
Take a look here.
Another quick fix is to add a flag variable that you set only when the success or error functions were called, and add a while loop with that flag variable as condition right after the function call.
Employee.prototype.employeeSearch = function (pEmplNo) {
$.ajax({
context: this,
type: "POST",
url: "webservice URL",
data: '{"pEmployeeNumber":"' + pEmplNo + '"}',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
var me = this;
me.EmployeeNumber = msg.d.EmployeeNumber;
me.FirstName = msg.d.FirstName;
me.LastName = msg.d.LastName;
me.ErrorMessage = '';
me.IsFound = true;
me.searchEnded = true;
},
error: function () {
var me = this;
me.ErrorMessage = 'Error retrieving employee';
me.IsFound = false;
me.searchEnded = true;
}
});
while(!this.searchEnded)
{
}
}
Also, if you ever need to call a function with a different scope, take a look at apply and call.
if (_employee.IsFound) {will always happen before the ajax request completes. You need to use callbacks.