Jquery $.map function giving error - javascript

I have the following code to map events to FullCalendar
events: function(start, end, callback)
{
$.ajax(
{
type: 'POST',
dataType: 'json',
url: "Calendar.aspx/GetEvents",
contentType: 'application/json; charset=utf-8',
cache: false,
success: function (response) {
var events = [];
$.map(response.d, function (item) {
var event = new Object();
event.id = item.EventID;
event.start = new Date(item.StartDate);
event.end = new Date(item.EndDate);
event.title = item.EventName;
return event;
events.push(event);
})
callback(events);
},
error: function (err) {
alert('Error');
}
});
},
The Calendar.aspx/GetEvents function returns the following data successfully:
"[{"EventID":1,"EventName":"EventName 1","StartDate":"04-04-2014","EndDate":"04-06-2014"},{"EventID":2,"EventName":"EventName 2","StartDate":"04-08-2014","EndDate":"04-09-2014"},{"EventID":3,"EventName":"EventName 3","StartDate":"04-14-2014","EndDate":"04-15-2014"},{"EventID":4,"EventName":"EventName 4","StartDate":"04-26-2014","EndDate":"04-29-2014"}]"
I want to iterate through this data and assign it to the calendar.
My above $map function gives me the following error:
Cannot use in operator to search for 352 in [{"EventID":1,"EventName":"EventName 1","StartDate":"04-04-2014","EndDate
How can I do this??

You're using $.map incorrectly. The point of it is that it creates an Array, so there's no need to create one before the loop and .push() into it.
You should keep the return statement, remove the .push, and set the return value of $.map to the events variable.
success: function (response) {
var events = $.map(response.d, function (item) {
var event = new Object();
event.id = item.EventID;
event.start = new Date(item.StartDate);
event.end = new Date(item.EndDate);
event.title = item.EventName;
return event;
});
callback(events);
},
However, object literal syntax is nicer.
success: function (response) {
var events = $.map(response.d, function (item) {
return {
id: item.EventID,
start: new Date(item.StartDate),
end: new Date(item.EndDate),
title: item.EventName,
};
});
callback(events);
},
The error message shown in your question doesn't seem to make sense for the code provided.

Related

ajax loading before document despite using when().then() function with leaflet JS

Here is what the console reads:
Uncaught TypeError: Cannot read property 'addTo' of undefined
I am currently working with leaflet JS and before the page loads, there is quite a number of Ajax calls going on so that the website can render the acquired data for the user.
I have used two particular methods to synchronize certain ajax calls which rely on the previous. One method is passing the next ajax call into the complete function, whilst another is the when().then() function
The objective with the function below, which is called with the window.onload method, is to determine the users location using the javascript navigator, set the map, and proceed with the ajax calls as mentioned above.
$(window).on('load', function() {
//Pre-loader Jquery
if ($('#preloader').length) {
$('#preloader').delay(200).fadeOut('slow', function() {
$(this).remove();
});
}
//Determine users location, initiate leaflet map, synchornised ajax calls to retreive country core information
navigator.geolocation.getCurrentPosition((success) => {
const crd = success.coords;
onLoadLat = crd.latitude;
onLoadLng = crd.longitude;
currentMap = L.map('map').setView([onLoadLat, onLoadLng], 5);
mapTileLayer.addTo(currentMap);
$.ajax({
url: "libs/php/openCage.php",
type: "POST",
dataType: "JSON",
data: {
latLng: onLoadLat + "+" + onLoadLng
},
success: function(data, textStatus, jqXHRs) {
iso_a2 = data["results"][0]["components"]["ISO_3166-1_alpha-2"];
},
complete: function() {
//Retreive GeoJson file, mark polygon and set initial map for to reflect user location
$.ajax({
url: "libs/php/getCountryBorder.php",
type: "POST",
dataType: "JSON",
data: {
countryCode: iso_a2
},
success: function(geoData, txtSt, jq) {
//Reference details of existing country for further API's and functionality
nameOfCountry = geoData["properties"]["name"];
//Use the index to target the array and create polygon border on map
targetMapData = L.geoJSON(geoData, {
style: borderStyle
});
targetMapData.addTo(currentMap);
currentMap.fitBounds(targetMapData.getBounds(), {
padding: [50, 50],
});
},
complete: function() {
$.ajax({
url: "libs/php/keyCountryInfo.php",
type: "POST",
dataType: "JSON",
data: {
country_code: iso_a2
},
success: function(data, textStatus, jqXHR) {
capitalCity = data["capital"];
currencyCode = data.currencies[0].code;
coordinates = [...data.latlng];
$("#timezoneList").empty();
$("#countryName").text(data["name"]);
$("#region").text(data["region"]);
$("#sub-region").text(data["subregion"]);
$("#countryFlag").attr("src", data["flag"]);
$("#population").text(numeral(data["population"]).format(0, 0));
$("#capital").text(data["capital"]);
$("#timezoneList").text(data["timezones"][0]);
},
complete: function() {
$.when(**getPopularCities()**, getCityWeatherList(), getWikiEntries(onLoadLat, onLoadLng), getGeoNameId(), getCountryImages(), getPublicHolidays(), getLatestExchange(), populateSelect()).
then(function(data, textStatus, jqXHR) {
infoEasyBtn.addTo(currentMap);
wikiEasyBtn.addTo(currentMap);
currencyEasyBtn.addTo(currentMap);
covidEasyBtn.addTo(currentMap);
newsEasyBtn.addTo(currentMap);
weatherEasyBtn.addTo(currentMap);
airportMarkers.addTo(currentMap);
cityMarkers.addTo(currentMap);
siblingMarkers.addTo(currentMap);
});
}
})
}
})
}
})
})
});
within the onload function above, is the getPopularCities() method, which is where the issue is. I have set markers to be shown on the map, but there is one group of markers which do not load, from within that function
Get Popular Cities Method
function getPopularCities() {
let cityPopulation = [];
cityMarkers = new L.MarkerClusterGroup();
if (mainLayer) {
currentMap.removeControl(mainLayer);
}
$.ajax({
url: "libs/php/getCountryCities.php",
type: "POST",
dataType: "JSON",
data: {
getCountryIso: iso_a2
},
success: function(success, textStatus, jqXHRs) {
$("#top10CityTable").empty();
let cityList = success["cities"]; //grab all the cities from the response
//create an array in global variable named cityPopulation, to contain all the markers
cityList.sort((a, b) => {
if (a["population"] > b["population"]) {
return -1
} else {
return 1
}
})
cityList.forEach((element, index) => {
let formatedPop = numeral(element["population"]).format(0, 0);
//depending on how many citys have returned, title the heading accordingly
if (cityList.length < 10) {
$("#top10CityHeading").text("Major Cities")
}
if (cityList.length >= 10) {
$("#top10CityHeading").text("Top 10 Most Populated Cities");
}
//stop index at 9 to get data of top 10 most populated cities for modal section
if (index <= 9) {
$("#top10CityTable").append(`<tr><td>${element["name"]}</td><td>${formatedPop}</td></tr>`)
}
cityMarkers.addLayer(L.marker([element["latitude"], element["longitude"]], {
icon: populatedCities
}).bindPopup(`<h3>${element["name"]}</h3></br>Population: ${formatedPop}`));
})
//create a new overlay prop/value pairing in the global overlays variable
overlays["Major Cities"] = cityMarkers;
},
error: function(text, xh, errorThrown) {
console.log(errorThrown);
},
complete: function() {
let siblingsMapArr = [];
siblingMarkers = new L.MarkerClusterGroup();
$.ajax({
url: "libs/php/getCountrySiblings.php",
type: "POST",
dataType: "JSON",
data: {
countryGeoId: geoNameId
},
success: function(success, textStatus, jqXHRs) {
$("#countrySiblings").empty();
let siblingsArr = success["geonames"];
siblingsArr.sort((a, b) => {
if (a["population"] > b["population"]) {
return -1
} else {
return 1
}
})
let top10Sib = siblingsArr.slice(0, 10);
top10Sib.forEach((element, index) => {
let formatedPop = numeral(element["population"]).format(0, 0);
let rank = index + 1;
siblingMarkers.addLayer(L.marker([element["lat"], element["lng"]], {
icon: citySiblings
}).bindPopup(`<h3>${rank}. ${element["countryName"]}</h3><br/>Population: ${formatedPop}`));
$("#countrySiblings").append(`
<tr>
<td>${element["countryName"]}</td>
<td>${formatedPop}</td>
<td>${element["lat"]} / ${element["lng"]}</td>
</tr>`)
})
overlays["Top 10 Siblings (By Population)"] = siblingMarkers;
},
complete: function(success, data, jq) {
$.ajax({
url: "libs/php/getAirports.php",
type: "POST",
dataType: "JSON",
data: {
countryCode: iso_a2
},
success: function(success, txtStatus, jqXHR) {
let airportsArr = [];
airportMarkers = new L.MarkerClusterGroup();
const airportsList = success["data"];
airportsList.forEach((element) => {
airportMarkers.addLayer(L.marker([element["location"]["latitude"], element["location"]["longitude"]], {
icon: airportIcon
}).bindPopup(`<h3>${element["name"]["original"]}</h3></br>ICAO: ${element["icao"]}</br>Elevation: ${element["elevationFeet"]}<br/>Classification: ${element["classification"]}`));
})
overlays["Airports"] = airportMarkers;
mainLayer = L.control.layers(baseMaps, overlays);
mainLayer.addTo(currentMap);
airportMarkers.addTo(currentMap);
cityMarkers.addTo(currentMap);
siblingMarkers.addTo(currentMap);
}
})
}
})
}
})
}
The markers saved in the variable airportMarkers and cityMarkers appear on the map as well as the leaflet control panel, but the siblings markers do not.
So Im guessing the safe bet is that it is not bringing the data back in time before the page loads? Does anyone have a solution for this or perhaps I have done something wrong in my code?

Backbone + Promises - How to fetch after post

I have a model which has two functions - one posts, and one gets.
The fetch:
fetch: function (options) {
var self = this;
return P1Comm.get({
'dataType': 'json',
'processAjaxResponse': self.processAjaxResponse,
'onStatusInvalid': function (e) {
P1.log(e, 'status');
},
'onSuccess': options.success,
'onError': function (e) {
P1.log(e);
},
'sourceURL': P1.API_APPS_ROOT + 'v1.0/accepted-terms'
});
},
The post:
acceptTerms: function (appId) {
var self = this;
self.set({
'app_id': parseInt(appId,10)
});
self.createEdit(self.toJSON(), {
}).pipe(function () {
var def = $.Deferred();
var saveOpts = {
dataType: 'json',
stringify: true,
contentType: 'application/json',
processData: false,
processAjaxResponse: self.processAjaxResponse
};
self.save(self.toJSON(), saveOpts);
return def.promise();
});
},
Calling the post from the view: acceptAppTerms.acceptTerms(1);
These both work in their own right but I want to change this so that:
- Make the POST acceptTerms()
- Then make the GET fetch()
- Then call another function
I think it would be something like this (at least for the first two points):
acceptAppTerms.acceptTerms(id).then(function () {
this.launchApp(event, id);
});
But I get the error of Uncaught TypeError: Cannot read property 'then' of undefined
I am not that good at front-end - can someone point me in the right direction?
Thanks
UPDATE:
fetchAcceptedTerms: function () {
var self = this;
this.appAcceptedTerms = new T1AppAcceptedTerms();
this.acceptedTerms = new AppAcceptedTerms();
this.acceptedTerms.fetch({
success: function (data) {
if (data.meta.status === 'success') {
self.appAcceptedTerms.set(data.data);
}
}
});
},
Example below works but it breaks the setting of the data into the model.
The reason you get the error is because your acceptTerms doesn't return anything, or in other words returns undefined which doesn't have a then() method.
Your code should be something like:
fetch: function(options) {
var self = this;
return P1Comm.get({
dataType: 'json',
processAjaxResponse: self.processAjaxResponse,
onStatusInvalid: function(e) {
P1.log(e, 'status');
},
onSuccess: options.success,
onError: function(e) {
P1.log(e);
},
sourceURL: P1.API_APPS_ROOT + 'v1.0/accepted-terms'
});
},
acceptTerms: function(appId) {
var self = this;
self.set({
'app_id': parseInt(appId, 10)
});
return self.createEdit(self.toJSON(), {}).pipe(function() {
//---------------------------------------^ better use .then()
var saveOpts = {
dataType: 'json',
stringify: true,
contentType: 'application/json',
processData: false,
processAjaxResponse: self.processAjaxResponse
};
return self.save(self.toJSON(), saveOpts);
});
},
This code asummes that P1Comm.get, self.createEdit and self.save returns a promise object. If they don't then you need to create a Deferred object and return it's promise from these functions. And inside the success/error callbacks of their asynchronous actions you need to resolve/reject the promise accordingly.
I'd also like to mention that .pipe() is a deprecated method, you should use then() unless you're using ancient version of jQuery.

Creating multidimensional array inside each

I want to create a multidimensional array from the values I retrieved on an ajax post request.
API response
[{"id":"35","name":"IAMA","code":"24"},{"id":"23","name":"IAMB","code":"08"}]
jQuery code
var mulArr = [];
$.ajax({
type: 'POST',
url: '/path/to/APIendpoint',
dataType: 'json',
data: {
codes: codes
},
success: function(data) {
$.each(data, function(key, value) {
mulArr[key]['id'] = value.code;
mulArr[key]['text'] = value.name;
});
}
});
Syntax error
TypeError: mulArr[key] is undefined
I can properly fetch the data from the endpoint, the only error I encounter is the one I stated above. In perspective, all I want to do is simply a multidimensional array/object like this:
mulArr[0]['id'] = '24';
mulArr[0]['text'] = 'IAMA';
mulArr[1]['id'] = '08';
mulArr[1]['text'] = 'IAMB';
or
[Object { id="24", text="IAMA"}, Object { id="08", text="IAMB"}]
It happens because mulArr[0] is not an object, and mulArr[0]['id'] will throw that error. Try this:
var mulArr = [];
$.ajax({
type: 'POST',
url: '/path/to/APIendpoint',
dataType: 'json',
data: {
codes: codes
},
success: function(data) {
$.each(data, function(key, value) {
mulArr.push({id: parseInt(value.code), text: value.name});
// or try this if select2 requires id to be continuous
// mulArr.push({id: key, text: value.name});
});
}
});
Alternative to using push (which is a cleaner approach) is to define the new object.
mulArr[key] = {
id: value.code,
text:value.name
};
Another way of achieving what you want would be this one:
var mulArr = [];
$.ajax({
type: 'POST',
url: '/path/to/APIendpoint',
dataType: 'json',
data: {
codes: codes
},
success: function(data) {
mulArr = data.map(value => ({ id: parseInt(value.code), text: value.name }));
}
});
This is cleaner and also uses builtin map instead of jQuery $.each. This way you also learn the benefits of using the map function (which returns a new array) and also learn useful features of ES2015.
If you cannot use ES6 (ES2015) here is another version:
mulArr = data.map(function (value) {
return {
id: parseInt(value.code),
text: value.name
};
});
I guess you can already see the advantages.

Dynamically send parameter in ajax-chosen

I am new to Jquery world.
I have these following codes:
$target.ajaxChosen({
type: 'GET',
url: '<s:url action="getFilterValueJSON" namespace="/cMIS/timetable"></s:url>?filterKey='+keyword,
dataType: 'json',
jsonTermKey: 'filterWord'
}, function (data) {
var terms = [];
mydata = data.valueMap;
$.each(mydata, function (i, val) {
terms.push({ value: i, text: val });
});
return terms;
});
It seems the variable 'keyword' does not dynamically changed its value. The value for 'keyword' comes from an element with on change event. Would someone enlighten me about this on how to solve this? Thanks in advance.
its better you compose your url object just before call
function onclick(keyword)
{
var url = '<s:url action="getFilterValueJSON" namespace="/cMIS/timetable"></s:url>?
filterKey='+keyword;
ajaxCall(url);
}
function ajaxCall(url)
{
$target.ajaxChosen({
type: 'GET',
url: url,
dataType: 'json',
jsonTermKey: 'filterWord'
}, function (data) {
var terms = [];
mydata = data.valueMap;
$.each(mydata, function (i, val) {
terms.push({ value: i, text: val });
});
return terms;
});
}

How to initialize knockoutjs view model with .ajax data

The following code works great with a hardcoded array (initialData1), however I need to use jquery .ajax (initialData) to initialize the model and when I do the model shows empty:
$(function () {
function wiTemplateInit(winame, description) {
this.WIName = winame
this.WIDescription = description
}
var initialData = new Array;
var initialData1 = [
{ WIName: "WI1", WIDescription: "WIDescription1" },
{ WIName: "WI1", WIDescription: "WIDescription1" },
{ WIName: "WI1", WIDescription: "WIDescription1" },
];
console.log('gridrows:', initialData1);
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: "{UserKey: '10'}",
url: "WIWeb.asmx/GetTemplates",
success: function (data) {
for (var i = 0; i < data.d.length; i++) {
initialData.push(new wiTemplateInit(data.d[i].WiName,data.d[i].Description));
}
//console.log('gridrows:', initialData);
console.log('gridrows:', initialData);
}
});
var viewModel = function (iData) {
this.wiTemplates = ko.observableArray(iData);
};
ko.applyBindings(new viewModel(initialData));
});
I have been trying to work from the examples on the knockoutjs website, however most all the examples show hardcoded data being passed to the view model.
make sure your "WIWeb.asmx/GetTemplates" returns json array of objects with exact structure {WIName : '',WIDescription :''}
and try using something like this
function wiTemplateInit(winame, description)
{
var self = this;
self.WIName = winame;
self.WIDescription = description;
}
function ViewModel()
{
var self = this;
self.wiTemplates = ko.observableArray();
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: "{UserKey: '10'}",
url: "WIWeb.asmx/GetTemplates",
success: function (data)
{
var mappedTemplates = $.map(allData, function (item) { return new wiTemplateInit(item.WiName, item.Description) });
self.wiTemplates(mappedTemplates);
}
});
}
var vm = new ViewModel();
ko.applyBindings(vm);
If you show us your browser log we can say more about your problem ( Especially post and response ). I prepared you a simple example to show how you can load data with ajax , bind template , manipulate them with actions and save it.
Hope this'll help to fix your issue : http://jsfiddle.net/gurkavcu/KbrHX/
Summary :
// This is our item model
function Item(id, name) {
this.id = ko.observable(id);
this.name = ko.observable(name);
}
// Initial Data . This will send to server and echo back us again
var data = [new Item(1, 'One'),
new Item(2, 'Two'),
new Item(3, 'Three'),
new Item(4, 'Four'),
new Item(5, 'Five')]
// This is a sub model. You can encapsulate your items in this and write actions in it
var ListModel = function() {
var self = this;
this.items = ko.observableArray();
this.remove = function(data, parent) {
self.items.remove(data);
};
this.add = function() {
self.items.push(new Item(6, "Six"));
};
this.test = function(data, e) {
console.log(data);
console.log(data.name());
};
this.save = function() {
console.log(ko.mapping.toJSON(self.items));
};
}
// Here our viewModel only contains an empty listModel
function ViewModel() {
this.listModel = new ListModel();
};
var viewModel = new ViewModel();
$(function() {
$.post("/echo/json/", {
// Data send to server and echo back
json: $.toJSON(ko.mapping.toJS(data))
}, function(data) {
// Used mapping plugin to bind server result into listModel
// I suspect that your server result may contain JSON string then
// just change your code into this
// viewModel.listModel.items = ko.mapping.fromJSON(data);
viewModel.listModel.items = ko.mapping.fromJS(data);
ko.applyBindings(viewModel);
});
})

Categories

Resources