Reputation: 407
I’m trying to figure out how I can call a function in my project without using so many if Statements. The concept using the if statement works great. But every time I create a new function call, I have to write a new if statement. What I am hoping to do is add the new function call in my JSON Array and invoke my function(s) that way. I’m currently loading my data from a JSON Array by the way of D3, I’m hoping to add the function call that way. Below is a copy of my working concept with the if statements, which works great.
var funcData;
d3.csv("data/pointData5.csv", function(error, data) {
funcData = JSON.parse(JSON.stringify(data));
console.log(funcData);
var select = d3.select("#selectL")
.append("div")
.append("select")
select
.on("change", function() {
var v = d3.select(this).property("value");
if (v == 2) {
updateDataA();
}
if (v == 3) {
updateDataB();
}
if (v == 4) {
updateDataC();
}
if (v == 5) {
updateDataD();
}
})
select.selectAll("option")
.data(data)
.enter()
.append("option")
.attr('class', function(d,i) { return 'option' + i;})
.attr("value", function (d) { return d.value; })
.text(function (d) { return d.label; })
});
Below is the concept I’m trying to get working but I can’t seem to get working. The function name loading but it won’t call the function like the script does above.
var funcData;
d3.csv("data/pointData5.csv", function(error, data) {
funcData = JSON.parse(JSON.stringify(data));
console.log(funcData);
var select = d3.select("#selectL")
.append("div")
.append("select")
select
.on("change", function() {
var v = d3.select(this).property("value");
for (var i = 1; i < funcData.length; i++)
if (v == i && funcData[i].dataF) {
console.log(funcData[i].dataF);
funcData[i].dataF;
}
})
select.selectAll("option")
.data(data)
.enter()
.append("option")
.attr('class', function(d,i) { return 'option' + i;})
.attr("value", function (d) { return d.value; })
.text(function (d) { return d.label; })
});
Below is a screen capture of my JSON Array.
I really appreciate if anyone can offer a solution or if this concept is even possible. Thank you in advance.
Added Edition of what the function is invoking:
updateDataA();
function updateDataA() {
updateData("gTank.png");
}
function updateDataB() {
updateData("bTank.png");
}
function updateDataC() {
updateData("diamond.svg");
}
////////////Add Markers to Map//////////////////
function updateData(url) {
removeMarkers()
omnivore.csv('data/pointData5.csv')
.on('ready', function(layer) {
this.eachLayer(function(marker) {
if (marker.toGeoJSON().properties.graphic != url)
marker.remove();
//////////////////////////////////////////////////////////////
// Add a flyTo button
//////////////////////////////////////////////////////////////
var button = document.createElement("button");
button.className += " myBtns";
if(marker.toGeoJSON().properties.graphic == url) {
button.innerHTML =
marker.toGeoJSON().properties.cityName;
$('.zoomPoint').append(button);
}
// button.innerHTML = marker.toGeoJSON().properties.cityName;
button.addEventListener("click", function (event) {
event.preventDefault();
// map.flyTo(layer.getLatLng(), 5); // This works obviously,
but just to demonstrate use of xy conversion:
map.flyTo(xy(marker.toGeoJSON().geometry.coordinates), 9, {
animate: true,
duration: 2.5
});
map.once("moveend", function () {
marker.openPopup();
});
});
//////////////////////////////////////////////////////////////
//Load Icons from CSV file
var customIcon = L.icon({
iconUrl: 'graphic/' +
marker.toGeoJSON().properties.graphic,//add graphic from CSV file
iconSize: [20, 10 ], //size of the icon in pixels
iconAnchor: [9, 9], //point of the icon which will
correspond to marker's location (the center)
popupAnchor: [0, 0] //point from which the popup should
open relative to the iconAnchor
});
//Add ID to each image - can now style each icon with CSS
$('#map').find('img').each(function (i) {
$(this).attr('id', 'img_');
});
$(".content ").find(".myBtns:first-child").prop("disabled", true);
//change the icons for each point on the map
marker.setIcon(customIcon);
//create popup with text and image - click image in popup,
large image displays in fancybox
var popupText =
marker.bindPopup('<strong>' +
marker.toGeoJSON().properties.cityName + '</strong>' + ', ' + '</br>'
+ marker.toGeoJSON().properties.discrip + "<br /><a class='fancybox-
thumb' ' style='width:150px;' rel='fancybox-button' rel='fancybox-
thumb' data-fancybox-group='"+ marker.toGeoJSON().properties.popup +"'
title='" + marker.toGeoJSON().properties.discrip + " '
href='graphic/"+
marker.toGeoJSON().properties.popup + "' ><img src='graphic/" +
marker.toGeoJSON().properties.popup + "' alt='Image' ' s
style='width:150px;'
></a>" + "<br/><a href='http://www.google.com'
target='_blank'>Cedellion Report</a>");
});
}).addTo(map);
}
Upvotes: 0
Views: 1053
Reputation: 884
You could use eval()
, but that is highly discouraged. There are other options to do this, but most likely you could do some rearchitecture here. What do your updateDataA()
, updateDataB()
, and updateDataC()
functions do? How different are they from each other? Most likely you could refactor to have a single updateData
function that takes a parameter based on the current array element and updates data accordingly. I'm going to need some more details before I can fully answer your question.
The best way to go about this is to store the URL in the JSON array (e.g. "url": "gTank.png"
) and then call the updateData()
function passing in the url
property.
let url = d3.select(this).property("url");
updateData(url);
This is probably the best practice way to do it, as eval is a security risk and highly discouraged.
Upvotes: 1
Reputation: 407
After a little more research I found my solution, the eval(). This was M. Page and Richik suggestion....thank you. To do what I was seeking to accomplish, I added my function in my loop like this, eval('(' + funcData[i].dataF + ')'); and everything worked as I hoped. Thank you all for putting me on the correct path.
Upvotes: 0
Reputation: 678
You can store functions in array. But it is necessary to add parentheses for the call.
Try
if (v == i && funcData[i].dataF) {
console.log(funcData[i].dataF);
funcData[i].dataF(); // see the parentheses
}
You can also use this code to check that it is a function before the call
if(typeof funcData[i].dataF === 'function') {
}
Examples
let funcs = [
(a, b) => { return a+b; },
(a, b) => { return a-b; },
() => { return true; }
];
funcs[0](2, 4); // return 6
funcs[1](2, 4); // return -2
funcs[2](); // return true
or
let funcs = {
addition: (a, b) => { return a+b; },
soustraction: (a, b) => { return a-b; }
};
funcs.addition(2, 4); // return 6
funcs['addition'](2, 4); // return 6
funcs.soustraction(2, 4); // return -2
funcs['soustraction'](2, 4); // return -2
Upvotes: 0