Unexpected undefined return value from a function - javascript

I'm getting an unexpected undefined return value from a function.
function createselbox(arr) {
console.log('In createselbox');
var startstr = `Something`;
mytemp = '';
for (var i = 0; i < arr.length; i++) {
mytemp = mytemp + '<option>' + arr[i] + '</option>';
}
var ret = startstr + mytemp + `Something else `;
IsStaff = CheckifStaff();
console.log('Checkifstaff is ' + IsStaff);
if (IsStaff) {
console.log('Got true createselbox');
console.log('In sel loop');
ret = startstr + mytemp + `Something more`;
} else {
console.log('Got false createselbox');
}
return ret;
}
function CheckifStaff() {
var data = {
"isstaff": 'check'
};
data = $(this).serialize() + "&" + $.param(data);
$.ajax({
type: "POST",
dataType: "html",
url: "/functions/checkifstaff",
data: data,
success: function (data) {
var recdata = data;
if (recdata.indexOf('Has add permissions') != -1) {
console.log('Returning true');
return 1;
} else {
console.log('Returning false');
return 0;
}
},
error: function (xhr, textStatus, errorThrown) {
console.log('An error occured in CheckifStaff');
return 0;
}
});
}
The console shows:
In createselbox
appointment.js ? dev = 96168005 : 292 Checkifstaff is undefined
appointment.js ? dev = 96168005 : 305 Got false createselbox
appointment.js ? dev = 96168005 : 158 Returning true
createselbox is called first. But the value from the function is being returned as false, apparently even before the function execution.
Why is this happening?

CheckifStaff() has no explicit return statement, so it returns what all functions return by default, which is undefined.

To make this work, CheckiStaff needs to return something, here, for example CheckiStaff will return a Promise which's value is either 1 or 0. createselbox will now await CheckiStaff and then use the value it returns afterwards
async function createselbox(arr) {
console.log('In createselbox');
var startstr = `Something`;
mytemp = '';
for (var i = 0; i < arr.length; i++) {
mytemp = mytemp + '<option>' + arr[i] + '</option>';
}
var ret = startstr + mytemp + `Something else `;
let IsStaff = await CheckiStaff();
console.log('Checkifstaff is ' + IsStaff);
if (IsStaff) {
console.log('Got true createselbox');
console.log('In sel loop');
ret = startstr + mytemp + `Something more`;
} else {
console.log('Got false createselbox');
}
return ret;
}
function CheckifStaff() {
var data = {
"isstaff": 'check'
};
data = $(this).serialize() + "&" + $.param(data);
return new Promise((resolve, reject) => {
$.ajax({
type: "POST",
dataType: "html",
url: "/functions/checkifstaff",
data: data,
success: function (data) {
var recdata = data;
if (recdata.indexOf('Has add permissions') != -1) {
console.log('Returning true');
resolve(1);
} else {
console.log('Returning false');
resolve(0);
}
},
error: function (xhr, textStatus, errorThrown) {
console.log('An error occured in CheckifStaff');
resolve(0);
}
});
});
}

you can also do change your ajax to be like this
$.ajax({
type: "POST",
dataType: "html",
url: "/functions/checkifstaff",
data: data,
success: function (data) {
var recdata = data;
if (recdata.indexOf('Has add permissions') != -1) {
console.log('Returning true');
return 1;
} else {
console.log('Returning false');
return 0;
}
},
error: function (xhr, textStatus, errorThrown) {
console.log('An error occured in CheckifStaff');
return 0;
}
}).then(function(data){
return data
});

i'm not an expert, but i think when you use ajax you should wait for the response - use promise, or async/await func

Related

How to deal with asynchronous problems in javascript

I want to display data stored in ch ! But my problem is that ch is displayed before the data is stored !
I think this is an Asynchronous Problems! How can I solve this problem.
When I try to get length of ch, I get always 0. Even if I store data statically in ch, I get the length 0.
I think this is an Asynchronous Problems! How can I solve this problem.
function RechercheFiltrée() {
var nom = document.getElementById('nompre').value;
var matricule = document.getElementById('matcle').value;
$.ajax({
url: "myWebServiceURL",
type: "GET",
dataType: "xml",
success: function(xml) {
var stock = [];
$(xml).find('Population').each(function() {
var table = document.getElementById("myTable");
$(this).find("directories").each(function()
{
dossier = $(this).attr('dossier');
stock.push(dossier);
});
});
var ch = [];
for (var i = 0; i < stock.length; i++) {
$.ajax({
url: "/mySecondWebServiceURL" + stock[i],
type: "GET",
dataType: "xml",
success: function(xml) {
var NMPRES = "";
var jsonObj = JSON.parse(xml2json(xml, ""));
var nom = jsonObj.SubmitResponse.occurrences.occurrence.filter(x => x["#datasection"] === "TS")[0].data.filter(x => x.item === "NMPRES")[0].value;
var matcle = jsonObj.SubmitResponse.occurrences.occurrence.filter(function(x) {
return x["#datasection"] === "LM"
})[0].data.filter(x => x.item === "MATCLE")[0].value;
var dossier = jsonObj.SubmitResponse.occurrences.occurrence.filter(function(x) {
return x["#datasection"] === "LM"
})[0]["#dossier"];
ch.push({
"nom": nom,
"matcle": matcle,
"dossier": dossier
});
if ($('#population').val() != null && firstIter == false) {
}
},
error: function(request, error) {
console.log('error Connexion : ' + error + ' request Connexion : ' + request);
}
});
}
var txt = "";
var firstIter = true;
for (var key in ch) {
if (ch[key].matcle === matricule) {
txt += "<option value='" + ch[key].dossier + "'" + firstSelect(firstIter) + ">" + ch[key].nom + "</option>";
firstIter = false;
}
}
$('#population').html(txt)
},
error: function(request, error) {
console.log('error Connexion : ' + error + ' request Connexion : ' + request);
}
});
}
The problem is that you are not waiting for the second service to respond.
It should be something like this:
const deferreds = stock.map((stockItem) => {
//... your logic with ch.push here
return $.ajax({
// your call to the second service
});
});
$.when(...deferreds).then(() => {
// your code
// for (var key in ch) {
});
The approach I'd rather take is to break the code down and use Promises. You really should take your time to learn Promises. It's a JavaScript standard and what jQuery uses under the hood.
function RechercheFiltrée() {
var nom = document.getElementById('nompre').value;
var matricule = document.getElementById('matcle').value;
return $.ajax({
url: "myWebServiceURL",
type: "GET",
dataType: "xml"
});
}
function getStockArray(xml) {
var stocks = [];
$(xml).find('Population').each(function() {
var table = document.getElementById("myTable");
$(this).find("directories").each(function() {
{
dossier = $(this).attr('dossier');
stocks.push(dossier);
});
});
});
return stocks;
}
function getStocks(stocks) {
return Promise.all(stocks.map(fetchStock));
}
function fetchStock (stock) {
return $.ajax({
url: "/mySecondWebServiceURL" + stock,
type: "GET",
dataType: "xml"
})
.then(formatStockInfo)
}
function formatStockInfo (xml) {
var NMPRES = "";
var jsonObj = JSON.parse(xml2json(xml, ""));
var nom = jsonObj.SubmitResponse.occurrences.occurrence.filter(x => x["#datasection"] === "TS")[0].data.filter(x => x.item === "NMPRES")[0].value;
var matcle = jsonObj.SubmitResponse.occurrences.occurrence.filter(function(x) {
return x["#datasection"] === "LM"
})[0].data.filter(x => x.item === "MATCLE")[0].value;
var dossier = jsonObj.SubmitResponse.occurrences.occurrence.filter(function(x) {
return x["#datasection"] === "LM"
})[0]["#dossier"];
if ($('#population').val() != null && firstIter == false) {
}
return {
"nom": nom,
"matcle": matcle,
"dossier": dossier
};
}
function updateSelectMenu (ch) {
var txt = "";
var firstIter = true;
for (var key in ch) {
if (ch[key].matcle === matricule) {
txt += "<option value='" + ch[key].dossier + "'" + firstSelect(firstIter) + ">" + ch[key].nom + "</option>";
firstIter = false;
}
}
$('#population').html(txt)
}
RechercheFiltrée()
.then(getStockArray)
.then(getStocks)
.done(updateSelectMenu);

dropdownlistfor cannot change to selected value from controller with jquery

I have read through this question ASP.NET MVC DropDownListFor not selecting value from model and answer but I don't know the solution to my problem.
This is part of my controller, here is first time when I call the ddl for the view, but not yet select any value.
private void bindDDLRefund(FormModel mod){
// refundCodes = _uow.ParameterRefund.GetAll().Where(e => e.IsDeleted.Value == false).Select(e => e.RefundCode).FirstOrDefault();
mod.DdlRefundPercentage = _uow.ParameterRefund.GetAll().Where(e => e.IsDeleted.Value == false).ToList().Select(e => new SelectListItem { Text = e.CfPercentage.ToString(), Value = e.RefundCode.ToString() }).OrderBy(e => e.Value);
//mod.DdlRefundPercentage = _uow.ParameterRefund.GetAll().Where(e => e.IsDeleted == false).ToList().Select(e => new SelectListItem() { Text = e.CfPercentage.ToString(), Value = e.RefundCode.ToString(), Selected = (e.RefundCode == mod.RefundCode) }).ToList();
}
public ActionResult Add(){
var mod = new FormModel();
//var percentage = GetAllPercentage();
//mod.ddlRefundPercentage = GetSelectListItems(percentage);
bindDDLRefund(mod);
mod.isCreate = true;
return View("Form",mod);
}
Then here is the selected value is being selected from controller,
public JsonResult GetTicketData(string ticketnumber){
bool isSuccess = false;
var result = new spRefTicketRefundRetrieve();
int isError = 0;
string errorDesc = "";
var mod = new FormModel();
try{
spRefTicketRefundRetrieveHeader obj = _uow.StoreProc.spRefTicketRefundRetrieve(ticketnumber);
isError = obj.IsError;
errorDesc = obj.ErrorDesc;
if (obj.IsError == 0){
result = obj.detailData;
}
isSuccess = true;
}
catch (Exception ex){
Logger.LogError("Reload Ticket Data", "Id = " + ticketnumber, ex);
}
return Json(new { success = isSuccess, value = result, isError = isError, errorDesc = errorDesc }, JsonRequestBehavior.AllowGet);
}
[HttpPost]
public JsonResult GetRefundData(string refund_id)
{
bool isSuccess = false;
var result = new spRefTicketRefundDetail();
int refundId = Encryption.Decrypt(refund_id);
try
{
result = _uow.StoreProc.spRefTicketRefundDetail(refundId);
isSuccess = true;
}
catch (Exception ex)
{
Logger.LogError("Reload Refund Data", "Id = " + refundId, ex);
}
return Json(new { success = isSuccess, value = result }, JsonRequestBehavior.AllowGet);
}
[HttpPost]
public JsonResult GetCFData(string ticketNumber, string refundCode)
{
bool isSuccess = false;
var result = new spRefTicketRefundChangeCF();
int isError = 0;
string errorDesc = "";
try
{
spRefTicketRefundChangeCFHeader obj = _uow.StoreProc.spRefTicketRefundChangeCF(ticketNumber, refundCode);
isError = obj.IsError;
errorDesc = obj.ErrorDesc;
if (obj.IsError == 0)
{
result = obj.listData;
}
isSuccess = true;
}
catch (Exception ex)
{
Logger.LogError("Reload CF Data", "Id = " + ticketNumber, ex);
}
return Json(new { success = isSuccess, value = result, isError = isError, errorDesc = errorDesc }, JsonRequestBehavior.AllowGet);
}
The selected value is about CfPercentage and variable result contains CF_PERCENTAGE which is representate of CfPercentage,
And here is my view and jQuery;
#Html.DropDownListFor(e => e.RefundCode, Model.DdlRefundPercentage, new { #class = "form-control", id= "ddl-refund",onchange="CFChange();" })
var GetRefundData = function (refundId) {
$.ajax({
url: '#Url.Action("GetRefundData")',
type: 'POST',
data: { refund_id: refundId },
success: function (result) {
console.log(result);
if (result.success) {
SetFormDetail(result.value);
}
else
{
}
},
error: function (result) {
alert('Something error occured, please refresh the page.')
}
});
};
var GetRefundViewData = function (refundId) {
$.ajax({
url: '#Url.Action("GetRefundData")',
type: 'POST',
data: { refund_id: refundId },
success: function (result) {
console.log(result);
if (result.success) {
SetFormView(result.value);
}
else {
}
},
error: function (result) {
alert('Something error occured, please refresh the page.')
}
});
};
var GetTicketData = function (ticketNumber) {
var target = $("#loading");
$.ajax({
beforeSend: function () {
target.html('<img src="#Url.Content("~/Content/images/ajax-loader.gif")"> loading...');
$('#divForm').css('display', 'none');
},
url: '#Url.Action("GetTicketData")',
type: 'POST',
data: { ticketnumber: ticketNumber },
success: function (result) {
console.log(result);
if (result.success) {
target.html('');
if (result.isError == "0") {
$('#divForm').css('display', 'block');
$('#txtHiddenTicketNumber').val(ticketNumber);
SetForm(result.value);
GetCFData();
}
else {
alert(result.errorDesc);
}
}
else {
$("#loading").html('');
}
},
error: function (result) {
alert('Something error occured, please refresh the page.')
}
});
};
var CFChange = function ()
{
GetCFData();
};
var GetCFData = function ()
{
var TicketNumber = $('#txtHiddenTicketNumber').val();
var RefundCode = $("#ddl-refund option:selected").val();
$.ajax({
url: '#Url.Action("GetCFData")',
type: 'POST',
data: { ticketNumber: TicketNumber, refundCode: RefundCode },
success: function (result) {
console.log(result);
if (result.success) {
SetCFDetail(result.value);
}
else {
}
},
error: function (result) {
alert('Something error occured, please refresh the page.')
}
});
};
var SetForm = function(list){
$(list).each(function () {
$('#txtManualRefundNo').val(this.MANUAL_REFUND_NO);
$('#lblLocOfficeCode').html(this.LOCATION_OFFICE_CODE);
$('#lblPnrCode').html(this.PNR_CODE);
$('#lblPnrTicket').html(this.PNR_CODE + "/ " + this.TICKET_NUMBER);
$('#lblIssuedDate').html(this.ISSUED_DATE_STR);
$('#lblPassengerName').html(this.PASSENGER_NAME);
$('#lblRouteClass').html(this.ROUTE + "/ " + this.CLASS_CODE);
$('#lblFlight').html(this.FLIGHT_DATE_STR + " - " + this.FLIGHT_NUMBER);
$('#lblBaseComm').html(this.BASE_PRICE_STR + "/ " + this.COMMISSION_NOMINAL_STR);
$('#lblTax').html(this.TOT_TAX_STR + "/ " + this.TOT_NON_TAX_STR);
$('#lblPublish').html(this.PUBLISH_RATE_STR);
$('#lblRefundPercentage').html(this.CANCELLATION_FEE_PERCENTAGE_STR);
$('#lblCancelFee').html(this.CANCELLATION_FEE_AMOUNT_STR);
$('#lblAdminFee').html(this.ADMIN_FEE_STR);
$('#lblCommFee').html(this.COMMISSION_FEE_STR);
$('#lblTicketUsed').html(this.TICKET_USED);
$('#lblTotalRefund').html(this.REFUND_AMOUNT_STR);
$('#txtReason').val('');
$('#ddl-refund :selected').text(this.CANCELLATION_FEE_PERCENTAGE_STR);
});
};
var SetFormDetail = function (list) {
$(list).each(function () {
$('#txtManualRefundNo').val(this.MANUAL_REFUND_NO);
$('#lblLocOfficeCode').html(this.LOCATION_OFFICE_CODE);
$('#lblPnrCode').html(this.PNR_CODE);
$('#lblPnrTicket').html(this.PNR_CODE + "/ " + this.TICKET_NUMBER);
$('#lblIssuedDate').html(this.ISSUED_DATE_STR);
$('#lblPassengerName').html(this.PASSENGER_NAME);
$('#lblRouteClass').html(this.ROUTE + "/ " + this.CLASS_CODE);
$('#lblFlight').html(this.FLIGHT_DATE_STR + " - " + this.FLIGHT_NUMBER);
$('#lblBaseComm').html(this.BASE_PRICE_STR + "/ " + this.COMMISSION_NOMINAL_STR);
$('#lblTax').html(this.TOT_TAX_STR + "/ " + this.TOT_NON_TAX_STR);
$('#lblPublish').html(this.PUBLISH_RATE_STR);
$('#lblCancelFee').html(this.CANCELLATION_FEE_AMOUNT_STR);
$('#lblAdminFee').html(this.ADMIN_FEE_STR);
$('#lblCommFee').html(this.COMMISSION_FEE_STR);
$('#lblTicketUsed').html(this.USED_FEE_STR);
$('#lblTotalRefund').html(this.REFUND_AMOUNT_STR);
$('#txtReason').val(this.DESCRIPTION);
$('#lblRefundPercentage').html(this.CANCELLATION_FEE_PERCENTAGE_STR);
//$('#txtHiddenTicketNumber').val(this.TICKET_NUMBER);
$("#ddl-refund").val(this.REFUND_CODE);
});
//GetCFData();
};
var SetFormView = function (list) {
$(list).each(function () {
$('#txtManualRefundNo').val(this.MANUAL_REFUND_NO);
$('#lblLocOfficeCode').html(this.LOCATION_OFFICE_CODE);
$('#lblPnrCode').html(this.PNR_CODE);
$('#lblPnrTicket').html(this.PNR_CODE + "/ " + this.TICKET_NUMBER);
$('#lblIssuedDate').html(this.ISSUED_DATE_STR);
$('#lblPassengerName').html(this.PASSENGER_NAME);
$('#lblRouteClass').html(this.ROUTE + "/ " + this.CLASS_CODE);
$('#lblFlight').html(this.FLIGHT_DATE_STR + " - " + this.FLIGHT_NUMBER);
$('#lblBaseComm').html(this.BASE_PRICE_STR + "/ " + this.COMMISSION_NOMINAL_STR);
$('#lblTax').html(this.TOT_TAX_STR + "/ " + this.TOT_NON_TAX_STR);
$('#lblPublish').html(this.PUBLISH_RATE_STR);
$('#lblCancelFee').html(this.CANCELLATION_FEE_AMOUNT_STR);
$('#lblAdminFee').html(this.ADMIN_FEE_STR);
$('#lblCommFee').html(this.COMMISSION_FEE_STR);
$('#lblTicketUsed').html(this.USED_FEE_STR);
$('#lblTotalRefund').html(this.REFUND_AMOUNT_STR);
$('#lblPaymentType').html(this.PAYMENT_TYPE);
$('#lblReason').html(this.DESCRIPTION);
$('#lblRefundPercentage').html(this.CANCELLATION_FEE_PERCENTAGE_STR);
//$('#txtHiddenTicketNumber').val(this.TICKET_NUMBER);
$("#ddl-refund").val(this.REFUND_CODE);
});
//GetCFData();
};
var SetCFDetail = function (list) {
$(list).each(function () {
$('#lblCancelFee').html(this.CANCELLATION_FEE_AMOUNT_STR);
$('#lblAdminFee').html(this.ADMIN_FEE_STR);
$('#lblCommFee').html(this.COMMISSION_FEE_STR);
$('#lblTotalRefund').html(this.REFUND_AMOUNT_STR);
});
};
After I running this, the view is always not select percentage based on sp that is relevant to ticketnumber. I have tried to modified it but nothing works. feel happy to be help :)
This line,
$('#ddl-refund :selected').text(this.CANCELLATION_FEE_PERCENTAGE_STR)
It actually set's the currently selected option's text to whatever value in this.CANCELLATION_FEE_PERCENTAGE_STR . It won't actually change the selected option. You can see it in action here.
What you should be doing Get the RefundCode value from your server call, and pass that in the val() method to set specific option item as the selected item.
Assuming your razor rendered your dropdown with this markup.
<SELECT id="ddl-refund">
<option value="25">Twenty Five</option>
<option value="26">Twenty Six</option>
<option value="28">Twenty Eight</option>
<option value="29">Twenty Nine</option>
And json data you received from your server call has a property called RedundCode.
$(list).each(function () {
$("#ddl-refund").val(this.RefundCode);
}
It will work if this.RefundCode is either 25 or 26 or 28 or 29.
I am not quite sure, why you are sending an array when all you want to send is a single item. But that is a different thing to fix.

jQuery : Calling a recursive function in AJAX succes

I have a problem :
function getArbre (recherche, div){
$.ajax({
//async : false,
type : "GET",
dataType: "json",
timeout : 2000,
url : "test.php?recherche=" + recherche,
success : function(donnees) {
if (donnees.Error) {
alert("Erreur");
} else {
console.log(donnees);
myjson = donnees;
}
},
complete : function(donnees) {
console.log("completed");
//JSONToTree(myjson);
},
error: function(donnees, status, err) {
console.log(status + " : " + err);
}
}).then(function(data){
JSONToTree(myjson);
});
And there is my function :
function JSONToTree(json){
console.log(json.id);
for (i = 0; i < json.Children.length; i++) {
JSONToTree(json.Children[i].id);
}
}
I have a problem, I can't read the content of my JSON, can someone help me ?
I think you are getting a JSON string and need to parse it. You can do this
function JSONToTree(json){
var jsonObj = JSON.parse(json);
console.log(jsonObj.id);
for (i = 0; i < jsonObj.Children.length; i++) {
JSONToTree(jsonObj.Children[i].id);
}
}

Using another variable in order to initialize the knockout observables

I am just wondering why one has to use a temporary variable "that" (initialized with the currently allocated object i.e. "this") in the script below:
$(document).ready(function() {
function ChatViewModel() {
var that = this;
that.userName = ko.observable('');
that.chatContent = ko.observable('');
that.message = ko.observable('');
that.messageIndex = ko.observable(0);
that.activePollingXhr = ko.observable(null);
var keepPolling = false;
that.joinChat = function() {
if (that.userName().trim() != '') {
keepPolling = true;
pollForMessages();
}
}
function pollForMessages() {
if (!keepPolling) {
return;
}
var form = $("#joinChatForm");
that.activePollingXhr($.ajax({url: form.attr("action"), type: "GET", data: form.serialize(), cache: false,
success: function(messages) {
console.log(messages);
for (var i = 0; i < messages.length; i++) {
that.chatContent(that.chatContent() + messages[i] + "\n");
that.messageIndex(that.messageIndex() + 1);
}
},
error: function(xhr) {
if (xhr.statusText != "abort" && xhr.status != 503) {
resetUI();
console.error("Unable to retrieve chat messages. Chat ended.");
}
},
complete: pollForMessages
}));
$('#message').focus();
}
that.postMessage = function() {
if (that.message().trim() != '') {
var form = $("#postMessageForm");
$.ajax({url: form.attr("action"), type: "POST",
data: "message=[" + that.userName() + "] " + $("#postMessageForm input[name=message]").val(),
error: function(xhr) {
console.error("Error posting chat message: status=" + xhr.status + ", statusText=" + xhr.statusText);
}
});
that.message('');
}
}
that.leaveChat = function() {
that.activePollingXhr(null);
resetUI();
this.userName('');
}
function resetUI() {
keepPolling = false;
that.activePollingXhr(null);
that.message('');
that.messageIndex(0);
that.chatContent('');
}
}
//Activate knockout.js
ko.applyBindings(new ChatViewModel());
});
Why can't I just use "this"? Can anyone please explain?
this always refers to the object that is in scope when the call has been made, and this can change depending on your code. If you want it to still be your object in a sub-function, then assigning it to a variable that won't change in value gets around this issue.
This refers to the owner.
You can rewrite your code like this :
$(document).ready(function() {
function ChatViewModel() {
var that = this;
this.userName = ko.observable('');
this.chatContent = ko.observable('');
this.message = ko.observable('');
this.messageIndex = ko.observable(0);
this.activePollingXhr = ko.observable(null);
var keepPolling = false;
this.joinChat = function() {
if (that.userName().trim() != '') {
keepPolling = true;
pollForMessages();
}
}
function pollForMessages() {
if (!keepPolling) {
return;
}
var form = $("#joinChatForm");
this.activePollingXhr($.ajax({url: form.attr("action"), type: "GET", data: form.serialize(), cache: false,
success: function(messages) {
console.log(messages);
for (var i = 0; i < messages.length; i++) {
that.chatContent(that.chatContent() + messages[i] + "\n");
that.messageIndex(that.messageIndex() + 1);
}
},
error: function(xhr) {
if (xhr.statusText != "abort" && xhr.status != 503) {
resetUI();
console.error("Unable to retrieve chat messages. Chat ended.");
}
},
complete: pollForMessages
}));
$('#message').focus();
}
this.postMessage = function() {
if (that.message().trim() != '') {
var form = $("#postMessageForm");
$.ajax({url: form.attr("action"), type: "POST",
data: "message=[" + that.userName() + "] " + $("#postMessageForm input[name=message]").val(),
error: function(xhr) {
console.error("Error posting chat message: status=" + xhr.status + ", statusText=" + xhr.statusText);
}
});
that.message('');
}
}
this.leaveChat = function() {
that.activePollingXhr(null);
resetUI();
that.userName('');
}
function resetUI() {
keepPolling = false;
that.activePollingXhr(null);
that.message('');
that.messageIndex(0);
that.chatContent('');
}
}
//Activate knockout.js
ko.applyBindings(new ChatViewModel());
//fixing bracet
});
Check this link: http://www.quirksmode.org/js/this.html

Function as a KnockoutJS observable

I have the following script (see below). I have two questions regarding it:
1.What does the following line mean in the context of Knockoutjs?
ko.observable(null);
2.How can I invoke a function not yet defined as in here:
that.activePollingXhr(...
Here is the full script:
$(document).ready(function() {
function ChatViewModel() {
var that = this;
that.userName = ko.observable('');
that.chatContent = ko.observable('');
that.message = ko.observable('');
that.messageIndex = ko.observable(0);
that.activePollingXhr = ko.observable(null);
var keepPolling = false;
that.joinChat = function() {
if (that.userName().trim() != '') {
keepPolling = true;
pollForMessages();
}
}
function pollForMessages() {
if (!keepPolling) {
return;
}
var form = $("#joinChatForm");
that.activePollingXhr($.ajax({url: form.attr("action"), type: "GET", data: form.serialize(), cache: false,
success: function(messages) {
console.log(messages);
for (var i = 0; i < messages.length; i++) {
that.chatContent(that.chatContent() + messages[i] + "\n");
that.messageIndex(that.messageIndex() + 1);
}
},
error: function(xhr) {
if (xhr.statusText != "abort" && xhr.status != 503) {
resetUI();
console.error("Unable to retrieve chat messages. Chat ended.");
}
},
complete: pollForMessages
}));
$('#message').focus();
}
that.postMessage = function() {
if (that.message().trim() != '') {
var form = $("#postMessageForm");
$.ajax({url: form.attr("action"), type: "POST",
data: "message=[" + that.userName() + "] " + $("#postMessageForm input[name=message]").val(),
error: function(xhr) {
console.error("Error posting chat message: status=" + xhr.status + ", statusText=" + xhr.statusText);
}
});
that.message('');
}
}
that.leaveChat = function() {
that.activePollingXhr(null);
resetUI();
this.userName('');
}
function resetUI() {
keepPolling = false;
that.activePollingXhr(null);
that.message('');
that.messageIndex(0);
that.chatContent('');
}
}
//Activate knockout.js
ko.applyBindings(new ChatViewModel());
});
ko.observable(null); creates an observable with a value of null. Nothing different than ko.observable(5);, where the value would be 5.
I see that you're using the that.activePollingXhr observable by passing it the result of an ajax call. However, this call is asynchronous and $.ajax doesn't return the data it got from the server, but rather a jquery deferred. You need to use that.activePollingXhr insude the success callback. Here's is how your code might look like:
$.ajax({url: form.attr("action"), type: "GET", data: form.serialize(), cache: false,
success: function(messages) {
console.log(messages);
for (var i = 0; i < messages.length; i++) {
that.chatContent(that.chatContent() + messages[i] + "\n");
that.messageIndex(that.messageIndex() + 1);
}
that.activePollingXhr(messages); // <-- Note where the call to activePollingXhr is
},
error: function(xhr) {
if (xhr.statusText != "abort" && xhr.status != 503) {
resetUI();
console.error("Unable to retrieve chat messages. Chat ended.");
}
},
complete: pollForMessages
});
As for the comment under your question: that.activePollingXhr is defined as that.activePollingXhr = ko.observable(null); - an observable with value of null.
That just initializes an observable with null as the initial value.
If you need to invoke a function that is an observable, just add a second set of parenthesis.
that.activePollingXhr()()

Categories

Resources