Javascript/JQuery- Match string in dropdown to string in JSON and display the JSON sibling's array

Dawn
Dawn used Ask the Experts™
on
I'm attempting to display part of an array from JSON when the user clicks on an ID in the dropdown. The data is loading data twice and then subsequent clicks just layer array upon array even though I have set my array to clear when update() is fired. I'm also getting a "update is not defined at HTMLAnchorElement.onclick" although that function itself is firing when the page loads.

How can I resolve the error and only display the one set of matching data? Here is a fiddle: https://jsfiddle.net/dtepdc/4e6mfoct/

Here is the code:

let dataset = [
    {
        "scene": "IR0006426320",
        "scene_start_time": "2018-02-05T15:03:30",
        "chips": [
        {
            "chip": "2018.02.05.150",
            "start_date": "2018-02-05T00:05:07",
            "end_date": "2018-02-05T01:26:23",
            "co_num":["None"],
            "cause": false
        },
        {
            "chip": "2018.02.05.192",
            "start_date": "2018-02-05T15:48:08",
            "end_date": "2018-02-05T17:22:34",
            "co_num": [
                "C03619354",
                "C03618763",
                "C03619064",
                "C03619325"
            ],
            "cause": false
        },
        {
            "chip": "2018.02.05.26",
            "start_date": "2018-02-05T16:38:56",
            "end_date": "2018-02-05T21:08:00",
            "co_num": [
                "C03610724"
            ],
            "cause": false
        },
        {
            "chip": "2018.02.05.303",
            "start_date": "2018-02-05T13:34:58",
            "end_date": "2018-02-05T13:34:58",
            "co_num": [
                "C03610724"
            ],
            "cause": true
        },
        {
            "chip": "2018.02.05.44",
            "start_date": "2018-02-05T21:20:39",
            "end_date": "2018-02-05T23:41:59",
            "co_num": [
                "C03610724"
            ],
            "cause": false
        },
        {
            "chip": "2018.02.05.53",
            "start_date": "2018-02-05T13:59:46",
            "end_date": "2018-02-05T16:01:35",
            "co_num": [
                "C03610724"
            ],
            "cause": true
        },
        {
            "chip": "2018.02.05.54",
            "start_date": "2018-02-05T01:04:53",
            "end_date": "2018-02-05T01:09:58",
            "co_num":["None"],
            "cause": false
        },
        {
            "chip": "2018.02.06.63",
            "start_date": "2018-02-05T23:44:23",
            "end_date": "2018-02-05T23:59:18",
            "co_num": [
                "C03610724"
            ],
            "cause": false
        }
    ]
},
{
    "scene": "IR0006633836",
    "scene_start_time": "2018-05-2418T14:20:00",
    "chips": [
        {
            "chip": "2018.05.25.50",
            "start_date": "2018-05-24T02:10:04",
            "end_date": "2018-05-24T06:39:41",
            "co_num": [
                "C03726697", "None"
            ],
            "cause": false
        },
        {
            "chip": "2018.05.25.59",
            "start_date": "2018-05-24T03:02:01",
            "end_date": "2018-05-24T04:26:06",
            "co_num": [
                "C03728974",
                "C03729029",
                "C03704816",
                "C03728657",
                "C03719067"
            ],
            "cause": false
        },
        {
            "chip": "2018.05.26.137",
            "start_date": "2018-05-24T18:02:47",
            "end_date": "2018-05-24T18:43:10",
            "co_num":["None"],
            "cause": false
        },
        {
            "chip": "2018.05.26.194",
            "start_date": "2018-05-24T15:08:40",
            "end_date": "2018-05-24T15:10:40",
            "co_num":["None"],
            "cause": false
        },
        {
            "chip": "2018.05.26.197",
            "start_date": "2018-05-24T18:20:53",
            "end_date": "2018-05-24T18:20:53",
            "co_num": [
                "C03726648"
            ],
            "cause": false
        },
        {
            "chip": "2018.05.26.269",
            "start_date": "2018-05-24T21:07:35",
            "end_date": "2018-05-24T21:08:48",
            "co_num": [
                "C03726648"
            ],
            "cause": false
        },
        {
            "chip": "2018.05.26.30",
            "start_date": "2018-05-24T14:20:17",
            "end_date": "2018-05-24T21:14:25",
            "co_num":[
                "C03704816",
                "C03719067",
                "C03728657"
            ],
            "cause": false
        },
        {
            "chip": "2018.05.26.31",
            "start_date": "2018-05-24T15:19:35",
            "end_date": "2018-05-24T17:33:52",
            "co_num": [
                "C03704816",
                "C03719067",
                "C03728657", "None"
            ],
            "cause": false
        },
        {
            "chip": "2018.05.26.377",
            "start_date": "2018-05-24T14:59:08",
            "end_date": "2018-05-24T15:25:06",
            "co_num": [
                "C03730107",
                "C03714722",
                "C03728407",
                "C03728209"
            ],
            "cause": false
        },
        {
            "chip": "2018.05.26.39",
            "start_date": "2018-05-24T18:13:52",
            "end_date": "2018-05-24T18:13:53",
            "co_num": [
                "C03728284"
            ],
            "cause": false
        }
    ]
}
]

Open in new window

        $.each(dataset, function (i) {
            $('#dropdownMenuButtonAnchor').append('<a class="dropdown-item" onclick="update()" href="#">' + dataset[i].scene  + '</a>');
    });

            $.each(dataset, function (j) {
            let firstIncident = dataset[0].scene;
            $("#incidentNumber").html(firstIncident);

        });


setTimeout(function() {
    update();
}, 100);

  /* change() ********************* */
  function update() {
    d3.selectAll('svg').remove();
    let changed = [];
    let start = moment().subtract(24, 'months').valueOf();
    let timeRange =     d3.select('input[name="options"]:checked').property("value");

if (timeRange < 12) {
    start = moment().subtract(timeRange, 'minutes').valueOf();
} else if (timeRange >= 12 && timeRange < 36) {
    start = moment().subtract(timeRange, 'hours').valueOf();
} else if (timeRange === 24) {
    start = moment().subtract(16, 'months').valueOf();
}

let end = moment().valueOf();

const coNumW = window.innerWidth,
        coNumH = window.innerHeight,
        margin = {top: coNumH * 0.15, right: coNumW * 0.05, bottom: coNumH * 0.12, left: coNumW * 0.12},
        w = coNumW - margin.left - margin.right,
        h = coNumH - margin.top - margin.bottom;

let x = d3.scaleTime().range([w, 0]),
    y = d3.scaleBand().range([h, 0]),
    xAxis = d3.axisBottom(x)
    yAxis = d3.axisLeft(y),
    filtered = [],
    dateFormat = d3.timeFormat("%Y-%m-%d %I:%M %p"),
    weekdayFormat = d3.timeFormat("%w");

    let newSvg = d3.select("body")
    .append("svg")
    .attr("width", coNumW)
    .attr("height", coNumH)
    .append("g").classed("no-select", true)
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

// ********************************************* LOOPS *********************************************
   $('div#dropdownMenuButtonAnchor a').click(function(){

    let incident = $(this).text();
    $("#incidentNumber").html(incident);

            //dataset.forEach(function(d, i) {
                for (let i = 0;i < dataset.length;i++){
                    if (incident === dataset[i].scene) {
                        dataset[i].chips.forEach(function(c, j) {
                            changed.push(c);

                            $('.incidentInfo').append('<a class="dropdown-item" onclick="update()" href="#">' + c.co_num  + '</a>');

                          });


// ********************************************* LOOPS *********************************************

x.domain([new Date(start), new Date(end)]).range([0, w]);
y.domain(changed.map(d => d.chip)).padding(0.1);

newSvg.append("g")
        .attr("class", "x_Axis")
        .attr("transform", "translate(0, " + h + ")")
        .call(xAxis)

newSvg.append("g")
        .attr("class", "y_Axis")
        .call(yAxis);

let tasksChange = newSvg.append("g")
        .attr("class", "dataCont")
        .selectAll("g")
        .data(changed)
        .enter()
        .append("g")
        .on("mouseenter", showData);

    let parseDate = d3.timeParse('%Y-%m-%dT%H:%m:%s');
    tasksChange.append("rect")
            .attr("x", function(d) {
                return x(moment(d.start_date).valueOf()) + 2;
            })
            .attr("y", function(d) {
            return y(d.chip);
            })
            .attr("width", function(d) {
                return x(moment(d.end_date)) - x(moment(d.start_date)) +2;
            })
            .attr("height", function(d) {
                return y.bandwidth();
            });


            d3.selectAll("#inlineRadio2, #inlineRadio3, #inlineRadio4")
                .on("change", function(){
                    update();
            });

            d3.selectAll("#inlineRadio1")
                .on("change", function(){
                setInterval(update, 10);
                var svg = d3.select("svg");

                let start = moment().subtract(timeRange, 'minutes').valueOf();
                let end = moment().valueOf();

                x.domain([start, end]);
                xAxis.scale(x);

                    //move the xaxis left
                svg.select(".x_axis")
                  .transition()
                  .duration(100)
                  .ease(d3.easeLinear)
                  .call(xAxis);
              });


    function showData(d) {
        console.log("Start Date: " + moment(d.start_date).format());
        console.log("End Date: " + moment(d.end_date).format());
        console.log('CO: ', d.chip)
        console.log('************************* ')

    }
}
}
});
  }

Open in new window

Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Author

Commented:
Will do...
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
Hint:You have posted a significant amount of code. In future try to narrow it down to what code is integral to the problem or at least give pointers as to where to start looking.
A short synopsis of your code will also help.

Let's look at your code you have this

setTimeout(function() {
	update();
}, 100);

Open in new window

In other words, every 100 milliseconds you are calling the update function.
In the update function you have this
$('div#dropdownMenuButtonAnchor a').click(function(){
		let incident = $(this).text();

Open in new window

So every 100 milliseconds you are binding ANOTHER click handler to your markup. That means every time it fires ALL handlers are going to fire.
Whether or not this is the cause of your problem is not clear but it is something you need to fix.

Move your click handler outside of the update function - move the function closing } to above the $(`div#dropdown...) line

You may need to change your .click to a .on handler - it is important to understand the difference between these two and why you would use one over the other.
If you are creating content dynamically that you need to bind a click event to then it will fail because the element needs to exist when you bind it. The .on() handler will allow you to bind the handler to a static parent and specify a child class / element to relate the event to.

You can also move your showData function outside of the event handler.

I updated your fiddle as best I could (see below)
Hint2: Tidy code is much easier to work with than untidy code. Take some time to format your code neatly and lay it out in an ordered way. I found it very difficult to figure out what your code was doing as the formatting and layout were very chaotic.
let dataset = [
    {
        "scene": "IR0006426320",
        "scene_start_time": "2018-02-05T15:03:30",
        "chips": [
            {
                "chip": "2018.02.05.150",
                "start_date": "2018-02-05T00:05:07",
                "end_date": "2018-02-05T01:26:23",
                "co_num":["None"],
                "cause": false
            },
            {
                "chip": "2018.02.05.192",
                "start_date": "2018-02-05T15:48:08",
                "end_date": "2018-02-05T17:22:34",
                "co_num": [
                    "C03619354",
                    "C03618763",
                    "C03619064",
                    "C03619325"
                ],
                "cause": false
            },
            {
                "chip": "2018.02.05.26",
                "start_date": "2018-02-05T16:38:56",
                "end_date": "2018-02-05T21:08:00",
                "co_num": [
                    "C03610724"
                ],
                "cause": false
            },
            {
                "chip": "2018.02.05.303",
                "start_date": "2018-02-05T13:34:58",
                "end_date": "2018-02-05T13:34:58",
                "co_num": [
                    "C03610724"
                ],
                "cause": true
            },
            {
                "chip": "2018.02.05.44",
                "start_date": "2018-02-05T21:20:39",
                "end_date": "2018-02-05T23:41:59",
                "co_num": [
                    "C03610724"
                ],
                "cause": false
            },
            {
                "chip": "2018.02.05.53",
                "start_date": "2018-02-05T13:59:46",
                "end_date": "2018-02-05T16:01:35",
                "co_num": [
                    "C03610724"
                ],
                "cause": true
            },
            {
                "chip": "2018.02.05.54",
                "start_date": "2018-02-05T01:04:53",
                "end_date": "2018-02-05T01:09:58",
                "co_num":["None"],
                "cause": false
            },
            {
                "chip": "2018.02.06.63",
                "start_date": "2018-02-05T23:44:23",
                "end_date": "2018-02-05T23:59:18",
                "co_num": [
                    "C03610724"
                ],
                "cause": false
            }
        ]
    },
    {
        "scene": "IR0006633836",
        "scene_start_time": "2018-05-2418T14:20:00",
        "chips": [
            {
                "chip": "2018.05.25.50",
                "start_date": "2018-05-24T02:10:04",
                "end_date": "2018-05-24T06:39:41",
                "co_num": [
                    "C03726697", "None"
                ],
                "cause": false
            },
            {
                "chip": "2018.05.25.59",
                "start_date": "2018-05-24T03:02:01",
                "end_date": "2018-05-24T04:26:06",
                "co_num": [
                    "C03728974",
                    "C03729029",
                    "C03704816",
                    "C03728657",
                    "C03719067"
                ],
                "cause": false
            },
            {
                "chip": "2018.05.26.137",
                "start_date": "2018-05-24T18:02:47",
                "end_date": "2018-05-24T18:43:10",
                "co_num":["None"],
                "cause": false
            },
            {
                "chip": "2018.05.26.194",
                "start_date": "2018-05-24T15:08:40",
                "end_date": "2018-05-24T15:10:40",
                "co_num":["None"],
                "cause": false
            },
            {
                "chip": "2018.05.26.197",
                "start_date": "2018-05-24T18:20:53",
                "end_date": "2018-05-24T18:20:53",
                "co_num": [
                    "C03726648"
                ],
                "cause": false
            },
            {
                "chip": "2018.05.26.269",
                "start_date": "2018-05-24T21:07:35",
                "end_date": "2018-05-24T21:08:48",
                "co_num": [
                    "C03726648"
                ],
                "cause": false
            },
            {
                "chip": "2018.05.26.30",
                "start_date": "2018-05-24T14:20:17",
                "end_date": "2018-05-24T21:14:25",
                "co_num":[
                    "C03704816",
                    "C03719067",
                    "C03728657"
                ],
                "cause": false
            },
            {
                "chip": "2018.05.26.31",
                "start_date": "2018-05-24T15:19:35",
                "end_date": "2018-05-24T17:33:52",
                "co_num": [
                    "C03704816",
                    "C03719067",
                    "C03728657", "None"
                ],
                "cause": false
            },
            {
                "chip": "2018.05.26.377",
                "start_date": "2018-05-24T14:59:08",
                "end_date": "2018-05-24T15:25:06",
                "co_num": [
                    "C03730107",
                    "C03714722",
                    "C03728407",
                    "C03728209"
                ],
                "cause": false
            },
            {
                "chip": "2018.05.26.39",
                "start_date": "2018-05-24T18:13:52",
                "end_date": "2018-05-24T18:13:53",
                "co_num": [
                    "C03728284"
                ],
                "cause": false
            }
        ]
    }
]
    
        $.each(dataset, function (i) {
            $('#dropdownMenuButtonAnchor').append('<a class="dropdown-item" onclick="update()" href="#">' + dataset[i].scene  + '</a>');
        });
        
            $.each(dataset, function (j) {
            let firstIncident = dataset[0].scene;
            $("#incidentNumber").html(firstIncident);
            
        });


setTimeout(function() {
    update();
}, 100);

  /* change() ********************* */
  function update() {
    d3.selectAll('svg').remove();
    let changed = [];
    let start = moment().subtract(24, 'months').valueOf();
    let timeRange = d3.select('input[name="options"]:checked').property("value");
    
    if (timeRange < 12) {
        start = moment().subtract(timeRange, 'minutes').valueOf();
    } else if (timeRange >= 12 && timeRange < 36) {
        start = moment().subtract(timeRange, 'hours').valueOf();
    } else if (timeRange === 24) {
        start = moment().subtract(16, 'months').valueOf();
    }

    let end = moment().valueOf();

    const coNumW = window.innerWidth,
            coNumH = window.innerHeight,
            margin = {top: coNumH * 0.15, right: coNumW * 0.05, bottom: coNumH * 0.12, left: coNumW * 0.12},
            w = coNumW - margin.left - margin.right,
            h = coNumH - margin.top - margin.bottom;

    let x = d3.scaleTime().range([w, 0]),
        y = d3.scaleBand().range([h, 0]),
        xAxis = d3.axisBottom(x)
        yAxis = d3.axisLeft(y),
        filtered = [],
        dateFormat = d3.timeFormat("%Y-%m-%d %I:%M %p"),
        weekdayFormat = d3.timeFormat("%w");

        let newSvg = d3.select("body")
        .append("svg")
        .attr("width", coNumW)
        .attr("height", coNumH)
        .append("g").classed("no-select", true)
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    // ********************************************* LOOPS *********************************************
}

$('div#dropdownMenuButtonAnchor a').click(function(){
  let incident = $(this).text();
  $("#incidentNumber").html(incident);

  //dataset.forEach(function(d, i) {
  for (let i = 0;i < dataset.length;i++){
    if (incident === dataset[i].scene) {
      dataset[i].chips.forEach(function(c, j) {
        changed.push(c);
        $('.incidentInfo')
        	.append('<a class="dropdown-item" onclick="update()" href="#">' + c.co_num  + '</a>');
      });
                    

      // ********************************************* LOOPS *********************************************
        
      x.domain([new Date(start), new Date(end)]).range([0, w]);
      y.domain(changed.map(d => d.chip)).padding(0.1);
    
      newSvg.append("g")
        .attr("class", "x_Axis")
        .attr("transform", "translate(0, " + h + ")")
        .call(xAxis)

    	newSvg.append("g")
        .attr("class", "y_Axis")
        .call(yAxis);
            
    	let tasksChange = newSvg.append("g")
        .attr("class", "dataCont")
        .selectAll("g")
        .data(changed)
        .enter()
        .append("g")
        .on("mouseenter", showData);

			let parseDate = d3.timeParse('%Y-%m-%dT%H:%m:%s');
      tasksChange.append("rect")
        .attr("x", function(d) {
          return x(moment(d.start_date).valueOf()) + 2;
        })
        .attr("y", function(d) {
	        return y(d.chip);
  	    })
        .attr("width", function(d) {
    	    return x(moment(d.end_date)) - x(moment(d.start_date)) +2;
      	})
        .attr("height", function(d) {
        	return y.bandwidth();
      	});

				d3.selectAll("#inlineRadio2, #inlineRadio3, #inlineRadio4")
					.on("change", function(){
						update();
				});

				d3.selectAll("#inlineRadio1")
					.on("change", function(){
						setInterval(update, 10);
						var svg = d3.select("svg");

						let start = moment().subtract(timeRange, 'minutes').valueOf();
						let end = moment().valueOf();

            x.domain([start, end]);
            xAxis.scale(x);
                
            //move the xaxis left
            svg.select(".x_axis")
              .transition()
              .duration(100)
              .ease(d3.easeLinear)
              .call(xAxis);
					});
	    }
    }
});
function showData(d) {
	console.log("Start Date: " + moment(d.start_date).format());
	console.log("End Date: " + moment(d.end_date).format());
  console.log('CO: ', d.chip)
  console.log('************************* ')
}

Open in new window

Author

Commented:
Ok, I'll keep this simple :) In the code below (and fiddle here: https://jsfiddle.net/dtepdc/qcvrh5ez/), I'm simply trying to display the array items from "co_num" in the browser when the "incident" number matches "dataset.scene". The items are currently displayed, but entire blocks of items are displayed as opposed to one-by-one. I can see that this is because I still need to drill down into "co_num" and display those items as opposed to the entire array but that is where I'm getting stuck:

let dataset = [
    {
        "scene": "IR0006426320",
        "scene_start_time": "2018-02-05T15:03:30",
        "chips": [
            {
                "chip": "2018.02.05.150",
                "start_date": "2018-02-05T00:05:07",
                "end_date": "2018-02-05T01:26:23",
                "co_num":["None"],
                "cause": false
            },
            {
                "chip": "2018.02.05.192",
                "start_date": "2018-02-05T15:48:08",
                "end_date": "2018-02-05T17:22:34",
                "co_num": [
                    "C03619354",
                    "C03618763",
                    "C03619064",
                    "C03619325"
                ],
                "cause": false
          }   
     ]
   }
]
     

          let incident = "IR0006426320"
	       for (const x in dataset) {
		
                    if (incident === dataset[x].scene) {
                	for (const a in dataset[x].chips) {
                    $('.incidentInfo').append('<a class="dropdown-item" onclick="update()" href="#">' + dataset[x].chips[a].co_num  + '</a><br />');
                  }
                    
                }
            }
       

Open in new window

Ensure you’re charging the right price for your IT

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden using our free interactive tool and use it to determine the right price for your IT services. Start calculating Now!

Most Valuable Expert 2017
Distinguished Expert 2018
Commented:
Is this what you were wanting
// Dummy our incident     
let incident = "IR0006426320";

// Find the item we are interested in
var item = dataset.find(x => x.scene === incident);

// Setup referecne to target element
var target = $('.incidentInfo');

// If we found him
if (item) {
  // iterate over the chips for this item
  item.chips.forEach(x => {
    // iterate over the co_num for each chip
    x.co_num.forEach(y => {
      // create and append a new <a> item with a click handler linked to the update function
        target.append(
          $('<a>', {class: 'dropdown-item', href: '#'})
            .html(y)
            .on('click', update)
        );
    })
  })
}

// Event handler for our click event
function update(e)
{
  // Prevent default behaviour
  e.preventDefault();
  
  // Dump some output
  console.log(e);
}

Open in new window


Updated fiddle here https://jsfiddle.net/ux3zf2n7/

Author

Commented:
Thank you so much! I can see how you did that in regards to the nested "co_num" array (as well as the more current javascript).
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
You are welcome - be aware that arrow functions have not gained full cross browser support status( i.e. that browser).
I used them for brevity but depending on the target environment you may need to downgrade them to the normal anonymous functions.

Author

Commented:
Will do, thanks again!

Author

Commented:
Julian, I'm trying to remove duplicate items from within the rendered array.

For this block:

x.co_num.forEach(y => {

                            target.append($('<a>', {class: 'dropdown-item', href: '#'}).html(y).on('click', update));

Open in new window


I thought that I could use something like the code below but it's not working:

x.co_num.forEach(y => {
                                const deduped = [...new Set(y)];
                                
                            target.append($('<a>', {class: 'dropdown-item', href: '#'}).html(deduped).on('click', update));
                    });

Open in new window


Does "Set" need to happen before looping through "y"?
Most Valuable Expert 2017
Distinguished Expert 2018
Commented:
If you are going to do it like that you need to build up your Set independently of the output otherwise you are going to output a progressive state of the Set on each iteration.
A better way is to use the Set to determine output.
let conum = new Set();
item.chips.forEach(x => {
  x.co_num.forEach(y => {
    if (!conum.has(y)) {
      target.append($('<a>', {class: 'dropdown-item', href: '#'}).html(y).on('click', update));
      conum.add(y);
    }
  });
});

Open in new window

However, Set has not reached full cross browser compatibility (i.e that browser again)

A more cross browser version would be
let conum = [];
item.chips.forEach(x => {
  x.co_num.forEach(y => {
    if (conum.indexOf(y) === -1) {
      target.append($('<a>', {class: 'dropdown-item', href: '#'}).html(y).on('click', update));
      conum.push(y);
    }
  });
});

Open in new window

Author

Commented:
Thank you! I realized I couldn't use Set with the code I had written since it was already a string. This makes total sense, thanks!

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial