Hecatonchires Hecatonchires - 1 year ago 63
jQuery Question

jQuery ajax call only works when I step through it

I am developing a page using Leaflet to display a map for a clients site. The page first loads the details of the map - name, lat, long etc based on an id. The load is via ajax to a very simple c# page that execs a stored proc and returns the recordset as JSON.

Once the map is loaded there is a second ajax call that clears and plots markers on the map. This is to a similar c# page that returns vehicle details. This ajax call is then set into a setInterval(function()) call to repeat every x seconds.

When I run the page normally, nothing loads properly. Looking through the debugger in firefox I can see that the first ajax call has returned undefined. If I add a breakpoint and step through to watch what happens, it works. If I remove the breakpoint, it fails.

What am I doing wrong here?

Main HTML file


<head>
<meta http-equiv="x-ua-compatible" content="IE=11">
<meta charset="utf-8" />
<meta http-equiv="refresh" content="3600">
<title>Map Viewer</title>
<link rel="stylesheet" type="text/css" href="/Content/themes/base/all.css" />
<link rel="stylesheet" type="text/css" href="/Content/Site.css" />
<link rel="stylesheet" type="text/css" href="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.css" />

<link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16">

<script type="text/javascript" src="/Scripts/jquery-3.0.0.min.js"></script>
<script type="text/javascript" src="/Scripts/jquery-ui-1.11.4.min.js"></script>
<script type="text/javascript" src="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.js"></script>
<script type="text/javascript" src="/Scripts/leaflet-providers.js"></script>
<script type="text/javascript" src="/Scripts/leaflet-tracksymbol.js"></script>
<script type="text/javascript" src="/Scripts/leaflet-tracklayer.js"></script>

<script type="text/javascript" src="/Scripts/ctrack-clearybros.js"></script>

<meta name="viewport" content="width=device-width" />
</head>
<body >
<h1 id="pageTitle"></h1>
<div id="errorText"></div>
<div id="map"></div>

<script id="mapScript" type="text/javascript">


Script Block


var mapDetails;
var mapId = 1;
var reloadTime = 15 * 1000; //15 seconds
//var w = $(window).width();
//var h = $(window).height();

mapDetails = getMapDetails(mapId);
console.debug("Map details retrieved");
console.debug(mapDetails);
//$("#map").width(w);
//$("#map").height(h);
$("#pageTitle").text(mapDetails.mapTitle);

var map = new L.Map("map", {
center: mapDetails.mapCenter,
minZoom: 16,
maxZoom: 16,
zoom: 16,
reuseTiles: true,
unloadInvisibleTiles: true
});
console.debug("Map Created");
//console.debug(map);

var appId = "snip";
var appCode = "snip";

//using plugin
var tilesLayer = new L.tileLayer.provider("HERE.terrainDay", {
attribution: "Event Data &copy; <a href=\"http://www.ctrackonline.com.au/\">Ctrack Australia</a> &#151; Map Data &copy; <a href=\"http://www.here.com\">HERE maps</a>",
app_id: appId,
app_code: appCode,
subdomains: '1234',
mapID: 'newest',
base: 'aerial',
maxZoom: 20,
type: 'maptile',
language: 'eng',
format: 'png8',
size: '256'
});
tilesLayer.addTo(map);
console.debug("tileLayer Created");
//console.debug(tilesLayer);

map.removeControl(map.zoomControl);
map.dragging.disable(); //disable map panning
map.doubleClickZoom.disable(); //disable click to recenter
map.touchZoom.disable();
map.scrollWheelZoom.disable();
map.boxZoom.disable();
map.keyboard.disable();
console.debug("Map options set");

var unitLayer = new L.FeatureGroup();
unitLayer.addTo(map);


populateUnitLayers(mapId) //prime the pump before the setInterval fires
console.debug("Vehicle layer populated");
console.debug(unitLayer);
//setInterval(function() {
// populateUnitLayers(mapId) //called every reloadTime seconds
//}, reloadTime);

</script>


<div id="ajaxLoadingHolder">
<div id="ajaxLoading"><img src="/Content/images/ajax-loader.gif" /></div>
</div>


Additional JS file


function getMapDetails(mapId) {
var _mapTitle;
var _mapLatitude;
var _mapLongitude;
var _mapCenter;

var JsonUrl;
if (window.location.pathname == "/ClearyBros.cshtml") { JsonUrl = "/JSON/GetDetailForLocation"; }
if (window.location.pathname == "/CtrackMaps/ClearyBros.cshtml") { JsonUrl = "/CtrackMaps/JSON/GetDetailForLocation"; }

$.ajax({
method: "GET",
url: JsonUrl,
processData: true, //means data sent as querystring
dataType: "json", //,"text"
data: { mapId: mapId },
timeout: 60000
})
.done(function (results) {
if (jQuery.isEmptyObject(results)) {
console.error("Map details are blank");
}
else {
console.debug("Map details are not blank");
console.debug(results);
}
$.each(results, function (index, result) {
_mapTitle = result.Name;
_mapLatitude = result.Latitude;
_mapLongitude = result.Longitude;
_mapCenter = new L.LatLng(_mapLatitude, _mapLongitude);
});
})
.fail(function (xhr, status, error) {
console.error("Failed to load map details");
if (status == "timeout") {
var errorText = "Timeout reached loading map details.";
displayError(errorText);
}
else {
var errortext = "Error state \"" + status + "\" occured loading map details. \n" + error;
displayError(errorText);
}
});

var obj = {
mapTitle: _mapTitle,
mapLatitude: _mapLatitude,
mapLongitude: _mapLongitude,
mapCenter: _mapCenter
};

return obj;
}

function populateUnitLayers(mapId) {
// set all our marker default values here. This doesnt get added to a layer.
var trackSymbolDefault = new L.trackSymbol(new L.LatLng(0.0, 0.0), {
trackId: 0,
fill: true,
fillColor: '#ffffff',
fillOpacity: 1.0,
stroke: true,
color: '#000000',
opacity: 1.0,
weight: 1.0,
speed: 0,
course: 0,
heading: 0,
leaderTime: 0
});

var JsonUrl;
if (window.location.pathname == "/ClearyBros.cshtml") { JsonUrl = "/JSON/GetUnitsForLocation"; }
if (window.location.pathname == "/CtrackMaps/ClearyBros.cshtml") { JsonUrl = "/CtrackMaps/JSON/GetUnitsForLocation"; }

unitLayer.clearLayers();
//unit0Layer.clearLayers();
//unit1Layer.clearLayers();
//unit2Layer.clearLayers();

$("#error-text").hide();

$.ajax({
method: "GET",
url: JsonUrl,
processData: true, //means data sent as querystring
dataType: "json", //"text",
data: { mapId: mapId },
timeout: 60000
})
.done(function (results) {

$.each(results, function (index, result) {
var marker = createUnitMarker(result, trackSymbolDefault);
if (marker.options.speed == 0) {
marker.options.color = '#cccccc';
//marker.addTo(unit0Layer);
//unit0Layer.addTrack(marker);
}
else if (marker.options.speed > 60) {
marker.options.color = '#ff0000';
//marker.addTo(unit1Layer);
//unit1Layer.addTrack(marker);
}
else {
marker.options.color = '#ffff00';
//marker.addTo(unit2Layer);
//unit2Layer.addTrack(marker);
}
//marker.addTo(map);
marker.addTo(unitLayer);
});
})
.fail(function (xhr, status, error) {
console.error("Failed to load vehicle details");
displayError("Error getting data while loading vehicle positions");
if (status == "timeout") {
//alert("Timeout reached.");
displayError("Timeout reached loading map details");
}
else {
//alert("Error state \"" + status + "\" occured loading vehicle positions. \n" + error );
var errorText = "Error state \"" + status + "\" occured loading vehicle positions.";
displayError(errorText);
}
});
}

function createUnitMarker(result, defaults) {
var _marker;
const kphToMph = 0.621371;

var _latlng = new L.LatLng(result.Latitude, result.Longitude);
var _track = result.NodeId;
var _speed = result.Speed * kphToMph; // Km/h to m/h
var _course = result.Heading * Math.PI / 180.0; // Radians from north
var _heading = result.Heading * Math.PI / 180.0;

_marker = new L.trackSymbol(_latlng, {
trackId: _track,
fill: defaults.options.fill,
fillColor: defaults.options.fillColor,
fillOpacity: defaults.options.fillOpacity,
stroke: defaults.options.stroke,
color: defaults.options.color,
opacity: defaults.options.opacity,
weight: defaults.options.weight,
speed: _speed,
course: _course,
heading: _heading,
leaderTime: defaults.options.leaderTime
});

var _note = "<p><b>Unit Name:</b> " + result.UnitName + "<br /><b>Unit Desc:</b> " + result.UnitDesc + "<br /><b>Last Updated:</b> " + result.AssembledTime + "<br /><b>Speed:</b> " + result.Speed + " km/h</p>"
_marker.bindPopup(_note);

console.debug("TrackId " + _marker.options.trackId + " added");

return _marker;
}

function displayError(message) {
$("#error-text").text(message);
$("#error-text").show();
}

$(document).ajaxStart(function () {
$("#ajaxLoading").show();
}).ajaxStop(function () {
$("#ajaxLoading").hide();
});

Answer Source

I ended up using jQuery's when() and then()

var ajaxOptions = {
    method: "GET",
    url: JsonUrl,
    processData: true, //means data sent as querystring
    dataType: "json", //"text",
    data: { mapId: mapId },
    timeout: 60000,
    cache: false
}

$.when($.ajax(ajaxOptions))
 .then(function (results) {
    $.each(results, function (index, result) {
        // do stuff with each result
    });
});

Putting my ajax in the first calls done did not suit, as the first call happened once on page load, and the 2nd occurred every refresh seconds.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download