TonyT
TonyT

Reputation: 407

How to Call a Function From a JSON Array

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.
Screen Capture of JSON Object from Console

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

Answers (3)

Richik SC
Richik SC

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

TonyT
TonyT

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

Lortet
Lortet

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

Related Questions