The Code

See the example code block below for the actual Javascript code used to build this app.

                    
var events = [
{
    event: "ThronesCon",
    city: "New York",
    state: "New York",
    attendance: 275000,
    date: "05/01/2020",
},
{
    event: "ThronesCon",
    city: "New York",
    state: "New York",
    attendance: 250000,
    date: "05/01/2021",
},
{
    event: "ThronesCon",
    city: "New York",
    state: "New York",
    attendance: 225000,
    date: "05/01/2022",
},
{
    event: "ThronesCon",
    city: "San Francisco",
    state: "California",
    attendance: 325000,
    date: "06/01/2020",
},
{
    event: "ThronesCon",
    city: "San Francisco",
    state: "California",
    attendance: 350000,
    date: "06/01/2021",
},
{
    event: "ThronesCon",
    city: "San Francisco",
    state: "California",
    attendance: 375000,
    date: "06/01/2022",
},
{
    event: "ThronesCon",
    city: "Los Angeles",
    state: "California",
    attendance: 450000,
    date: "07/01/2020",
},
{
    event: "ThronesCon",
    city: "Los Angeles",
    state: "California",
    attendance: 425000,
    date: "07/01/2021",
},
{
    event: "ThronesCon",
    city: "Los Angeles",
    state: "California",
    attendance: 475000,
    date: "07/01/2022",
},
];
                      
// build dropdown for specific cities
function buildDropDown() {
let dropdownMenu = document.getElementById("eventDropDown");
dropdownMenu.innerHTML = "";
                      
let currentEvents = getEventData();
                      
let cityNames = currentEvents.map((event) => event.city);
let citiesSet = new Set(cityNames);
let distinctCities = [...citiesSet]; // ['Los Angeles', 'San Francisco']
                      
const dropdownTemplate = document.getElementById("dropdownItemTemplate");
                      
// copy the template
let dropdownItemNode = document.importNode(dropdownTemplate.content, true);
                      
// make our changes
let dropdownItemLink = dropdownItemNode.querySelector('a');
dropdownItemLink.innerText = 'All Cities';
dropdownItemLink.setAttribute('data-string', 'All');
                      
// add our copy to the page
dropdownMenu.appendChild(dropdownItemNode);
                      
for (let i = 0; i < distinctCities.length; i += 1) {
    // get the city name
    let cityName = distinctCities[i];
                      
    // generate a dropdown element
    let itemNode = document.importNode(dropdownTemplate.content, true);
    let anchorTag = itemNode.querySelector('a');
    anchorTag.innerText = cityName;
    anchorTag.setAttribute('data-string', cityName);
                      
    // append it to the dropdown menu
    dropdownMenu.appendChild(itemNode);
}
                      
displayEventData(currentEvents);
displayStats(currentEvents);
document.getElementById('location').innerText = 'All Events';
}
                      
function displayEventData(currentEvents) {
                      
const eventTable = document.getElementById('eventTable');
const template = document.getElementById('tableRowTemplate');
                      
eventTable.innerHTML = '';
                      
for (let i = 0; i < currentEvents.length; i++) {
    let event = currentEvents[i];
    let tableRow = document.importNode(template.content, true);
                      
    tableRow.querySelector('[data-id="event"]').textContent = event.event;
    tableRow.querySelector('[data-id="city"]').textContent = event.city;
    tableRow.querySelector('[data-id="state"]').textContent = event.state;
    tableRow.querySelector('[data-id="attendance"]').textContent = event.attendance.toLocaleString();
    tableRow.querySelector('[data-id="date"]').textContent = new Date(event.date).toLocaleDateString();
                      
    tableRow.querySelector('tr').setAttribute('data-event', event.id);
                      
    eventTable.appendChild(tableRow);
}
}
                      
function calculateStats(currentEvents) {
let total = 0;
let average = 0
let most = 0;
let least = currentEvents[0].attendance;
                      
for (let i = 0; i < currentEvents.length; i++) {
    let currentAttendance = currentEvents[i].attendance;
                      
    total += currentAttendance;
                      
    if (currentAttendance > most) {
    most = currentAttendance;
    }
                      
    if(currentAttendance < least) {
    least = currentAttendance;
    }
}
                      
average = total / currentEvents.length;
                      
let stats = {
    total: total,
    average: average,
    most: most,
    least: least
}
                      
return stats;
}
                      
function displayStats(currentEvents) {
let statistics = calculateStats(currentEvents);
                      
document.getElementById('total').textContent = statistics.total.toLocaleString();
document.getElementById('average').textContent = Math.round(statistics.average).toLocaleString();
document.getElementById('most').textContent = statistics.most.toLocaleString();
document.getElementById('least').textContent = statistics.least.toLocaleString();
}
                      
function getEventData() {
let data = localStorage.getItem('fantasyconEventData');
                      
if (data == null) {
    let identifiedEvents = events.map((event) => {
    event.id = generateId();
    return event;
    });
                      
    localStorage.setItem('fantasyconEventData', JSON.stringify(identifiedEvents));
    data = localStorage.getItem('fantasyconEventData');
}
                      
let currentEvents = JSON.parse(data);
                      
if (currentEvents.some(event => event.id == undefined)) {
                      
    currentEvents.forEach(event => event.id = generateId());
                      
    localStorage.setItem('fantasyconEventData', JSON.stringify(currentEvents));
                      
    // same as above if loop
    // for (let i = 0; i < currentEvents.length; i++) {
    //  let event = currentEvents[i];
    //
    //  event.id == generateId();
    }
                          
return currentEvents;
}
                      
function viewFilteredEvents(dropdownItem) {
let cityName = dropdownItem.getAttribute('data-string');
                      
// get all my events
let allEvents = getEventData();
                      
if (cityName == 'All') {
    displayStats(allEvents);
    displayEventData(allEvents);
    document.getElementById('location').innerText = 'All Events';
                      
    return;
}
                      
// filter those events to just the selected city
let filteredEvents = allEvents.filter(event => event.city.toLowerCase() == cityName.toLowerCase());
                      
// same as above
// let filteredEvents2 = allEvents.filter(
//  function (event) {
//  return event.city.toLowerCase() == cityName.toLowerCase();
// });
                        
// display the stats for those events
displayStats(filteredEvents);
                      
// change the stats header
document.getElementById('location').innerText = cityName;
                      
// display only those events in the table
displayEventData(filteredEvents);
}
                      
function saveNewEvent() {
// get the form input values
let name = document.getElementById('newEventName').value;
let city = document.getElementById('newEventCity').value;
let attendance = parseInt(document.getElementById('newEventAttendance').value, 10);
                      
let dateValue = document.getElementById('newEventDate').value;
dateValue = new Date(dateValue + ' 00:00');
                      
let date = dateValue.toLocaleDateString();
                      
let stateSelect = document.getElementById('newEventState');
let selectedIndex = stateSelect.selectedIndex;
let state = stateSelect.options[selectedIndex].text;
                      
// create a new event object
let newEvent = {
    event: name,
    city: city,
    state: state,
    attendance: attendance,
    date: date,
    id: generateId()
};
                      
// add it to the array of current events
let events = getEventData();
events.push(newEvent);
                      
// then, save the array with the new event
localStorage.setItem('fantasyconEventData', JSON.stringify(events));
                      
buildDropDown();
document.getElementById('newEventForm').clear();
}
                      
function generateId() {
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
    (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
);
}
                      
function editEvent(eventRow) {
let eventId = eventRow.getAttribute('data-event');
                      
let currentEvents = getEventData();
                      
let eventToEdit = currentEvents.find(event => event.id == eventId);
                      
document.getElementById('editEventId').value = eventToEdit.id;
document.getElementById('editEventName').value = eventToEdit.event;
document.getElementById('editEventCity').value = eventToEdit.city;
document.getElementById('editEventAttendance').value = eventToEdit.attendance;
                      
let eventDate = new Date(eventToEdit.date + ' 00:00');
let eventDateString = eventDate.toISOString();
let dateArray = eventDateString.split('T');
let formattedDate = dateArray[0];
                      
                        
document.getElementById('editEventDate').value = formattedDate;
                      
/*
let stateSelect = document.getElementById('newEventState');
let stateIndex = stateSelect.selectedIndex;
let state = stateSelect.options[stateIndex].text;
*/
                      
let editStateSelect = document.getElementById('editEventState');
                      
let optionsArray = [...editStateSelect.options]
                      
let index = optionsArray.findIndex(option => eventToEdit.state == option.text);
editStateSelect.selectedIndex = index // the index of the state for our event
                      
/* for loop to find the option
for (let i = 0; i < editStateSelect.options.length; i++) {
    let option = editStateSelect.option[i];
                      
    if (eventToEdit.state == option.text) {
    editStateSelect.selectedIndex = i;
    }
} */
}
                      
function deleteEvent() {
let eventId = document.getElementById('editEventId').value;
                      
// get the events in local storage as an array
let currentEvents = getEventData();
// filter out any event(s) with that eventId
let filteredEvents = currentEvents.filter(event => event.id != eventId);
// save that array to local storage
localStorage.setItem('fantasyconEventData', JSON.stringify(filteredEvents));
                      
buildDropDown();
}
                      
function updateEvent() {
let eventId = document.getElementById('editEventId').value;
                      
// get the form input values
let name = document.getElementById('editEventName').value;
let city = document.getElementById('editEventCity').value;
let attendance = parseInt(document.getElementById('editEventAttendance').value, 10);
                      
let dateValue = document.getElementById('editEventDate').value;
dateValue = new Date(dateValue);
                      
let date = dateValue.toLocaleDateString();
                      
let stateSelect = document.getElementById('editEventState');
let stateIndex = stateSelect.selectedIndex;
let state = stateSelect.options[stateIndex].text;
                      
// create a new event object
let newEvent = {
    event: name,
    city: city,
    state: state,
    attendance: attendance,
    date: date,
    id: eventId
};
                      
// get my events array
let currentEvents = getEventData();
// find the location of the OLD event with this ID
let index = -1;
for (let i = 0; i < currentEvents.length; i++) {
    if (currentEvents[i].id == eventId) {
    // replace that event with newEvent
    currentEvents[i] = newEvent;
    break;
    }
}
                      
// save it in local storage
localStorage.setItem('fantasyconEventData', JSON.stringify(currentEvents));
                      
buildDropDown();
}
                    
                

The code is structured in seven functions. The first 65 lines that comprise of the events variable, are just text that we put into the table so we don't have to put a bunch in manually.


The first function, buildDropDown, is responsible for building the dropdown menu for specific cities, instead of listing every city that was input by the user.
The second function, displayEventData, is responsible for displaying the event data of the events input by the user. This function creates a table and template for the user input events. The function then pulls the data from the text the user input, and assigns it values. It then displays the values on the table, using the template it made.
The third function calculates the various attendance stats that will be displayed in a later function. These values are taken from the currentAttendance value, and are then used in various statements to calculate the stats. They are then assigned values, and returned.
The fourth function displays those stats by pulling those values and inserting them into the table with the user's preferred structure.
The next function is tasked with getting the event data and presenting it in a readable manner. The function gets data from the local storage the user created, and then transforms it into strings from the original object that it was. This data is then returned since it now usable for us.
The next function has to filter through the events and only pick unique cities to display their respective attendance numbers. It gets all of the event data first, and then checks what the dropdown menu name is. The user then picks what city data they want, and the function filters through the events, picking unique cities but collecting the data from those same cities. It then displays the data from that city.
The final function allows the user to add a new event to the event table. It assigns strings to the user input values, and inserts this data into a new event object. This object is then put into the events variable and combined with the previous event array. This is all stored into the users local storage, so that it doesn't disappear if the user exits or refreshes the page. Finally, it calls the buildDropDown function again, since a new event has been given.