Creating a dynamic football table

Creating a dynamic football table

It works no matter if it is real, FIFA, or eFootball

Good day, fellow reader. Football is by far the most popular sport in the world. From the World Cup to regional leagues, this game of low scores, team game, and angry fans, has evolved from the 16th century. Its rules had been changed several times, the target audience has spread, and the system of registering and pointing the results from matches has also not been a universal format. To avoid further discussions, we are going to elaborate an automatic positions table.

clarence-seedorf-running.webp Clarence Seedorf running with the UEFA Champions League trophy

The problem

For the most part of the world, a game in a league can have three outcomes: win, draw or loss. A winning team gets 3 points, a losing team gets 0, and a draw awards each team with 1 point. We will create a simple script using JavaScript that will process a set of matches and will provide as output a nifty table like this

table-example.png

Reference

  • PL: Played (matches)
  • W: Wins
  • D: Draws
  • L: Losses
  • GF: Goals for
  • GA: Goals against
  • GD: Goal difference (GF - GA)
  • P: Points

Dynamically generating an HTML table

With aid from the HTMLTableElement interface, you can follow this tutorial from Valentino Gagliardi to grasp an idea of how are we going to modify the DOM dynamically using JavaScript. The main purpose of this article is not how to introduce the data, but how to process and get the needed information for the sports objective.

Storing the data

We are going to store the matches in an array of objects. Each object will contain the basic information about the match the simplest way possible

{
  home: "Home Team Name",
  away: "Away Team Name",
  result: "1-2"
}

Input for the table

We will provide the insertTableBody and insertTableHead function with the data, with the following format example.

{NAME: "River Plate" , PL: 14, W: 7, D: 6, L: 1, GF: 19, GA: 9, GD: 10, P: 27}

Processing the input

So, we must build an array with that information, but how do we convert an array of matches to that? We are going to use two functions, one to prepare the info and get the participating teams, and another one to calculate the amounts of every property. The basic pseudocode is

data = []
getDataFromMatches(matches)
    foreach match from matches
        getHomeTeam of match
        getAwayTeam of match
        getHomeGoals of match
        getAwayGoals of match
        if homeTeam is not in data
            add homeTeam to data with empty scores
        if awayTeam is not in data
            add awayTeam to data with empty scores
        processMatchResult(data, homeTeam, awayTeam, homeGoals, awayGoals)
    sort data by points, if equal, by goal difference, if equal, by goals for

In the above function, we only get the data from the object, and we initialize the scores with the team names. Then, it's all up to processMatchResult to fill the scores for every match. In this case, the winning, draw, lose, and points depend on the comparison of the scores, but the played, goals for, goals against, and goal difference only represent simple additions.

processMatchResult(data, homeTeam, awayTeam, homeGoals, awayGoals)
    homeTeam.PLAYED = homeTeam.PLAYED + 1
    awayTeam.PLAYED = awayTeam.PLAYED + 1
    homeTeam.GF = homeTeam.GF + homeGoals
    awayTeam.GF = awayTeam.GF + awayGoals
    homeTeam.GA = homeTeam.GA + awayGoals
    awayTeam.GA = awayTeam.GA + homeGoals
    homeTeam.GD = homeTeam.GF - homeTeam.GA
    awayTeam.GD = awayTeam.GF - awayTeam.GA

    if homeGoals == awayGoals
        homeTeam.D = homeTeam.D + 1
        homeTeam.P = homeTeam.P + 1
        awayTeam.D = awayTeam.D + 1
        awayTeam.P = awayTeam.P + 1
    if homeGoals > awayGoals
        homeTeam.W = homeTeam.W + 1
        homeTeam.P = homeTeam.P + 3
        awayTeam.L = awayTeam.L + 1
        awayTeam.P = awayTeam.P + 0
    if homeGoals < awayGoals
        awayTeam.W = awayTeam.W + 1
        awayTeam.P = awayTeam.P + 3
        homeTeam.L = homeTeam.L + 1
        homeTeam.P = homeTeam.P + 0

JavaScript code

Now let's just write those functions in JavaScript.

let data = [];

function getDataFromMatches(matches) {    
  matches.forEach((match) => {
    let homeTeam = match.home;
    let awayTeam = match.away;
    let homeGoals = match.result.split("-")[0];
    let awayGoals = match.result.split("-")[1];
    let index = data.findIndex(team => team.NAME === homeTeam);
    // Home team non-existant in array, let's create it with default scores
    if (index === -1) {
      data.push({NAME: homeTeam, PL: 0, W: 0, D: 0, L: 0, GF: 0, GA: 0, GD: 0, P: 0});
    }
    index = data.findIndex(team => team.NAME === awayTeam);
    // Away team non-existant in array, let's create it with default scores
    if (index === -1) {
      data.push({NAME: awayTeam, PL: 0, W: 0, D: 0, L: 0, GF: 0, GA: 0, GD: 0, P: 0});
    }
    // parseInt is neccesary because goals are strings at this point
    processMatchResult(data, homeTeam, awayTeam, parseInt(homeGoals, 10), parseInt(awayGoals, 10));
  });
  // data is filled, let's sort it by points, goal difference, goals for.
  data.sort((teamA,teamB)=>(teamA.P - teamB.P || teamA.GD - teamB.GD || teamA.GF - teamB.GF));
  // sort gets ascending order, we need to reverse it for a normal league table
  data.reverse();
}

function processMatchResult(data, homeTeam, awayTeam, homeGoals, awayGoals) {
  // We get the reference to each team object
  let indexHT = data.findIndex(team => team.NAME === homeTeam);
  let indexAT = data.findIndex(team => team.NAME === awayTeam);
  // Common data (home) - plus one played and registering the goals
  data[indexHT].PL += 1;
  data[indexHT].GF += homeGoals;
  data[indexHT].GA += awayGoals;
  data[indexHT].GD = data[indexHT].GF - data[indexHT].GA;
  // Common data (away) - plus one played and registering the goals
  data[indexAT].PL += 1;
  data[indexAT].GF += awayGoals;
  data[indexAT].GA += homeGoals;
  data[indexAT].GD = data[indexAT].GF - data[indexAT].GA;

  // Draw
  if (homeGoals === awayGoals) {
    // Home team register a draw
    data[indexHT].D += 1;
    data[indexHT].P += 1;
    // Away team register a draw
    data[indexAT].D += 1;
    data[indexAT].P += 1;
  }
  // Home win
  if (homeGoals > awayGoals) {
    // Home team register a win
    data[indexHT].W += 1;
    data[indexHT].P += 3;
    // Away team register a loss
    data[indexAT].L += 1;
  }
  // Away win
  if (homeGoals < awayGoals) {
    // Away team register a win
    data[indexAT].W += 1;
    data[indexAT].P += 3;
    // Home team register a loss
    data[indexHT].L += 1;
  }
}

Now, we just need to add the data to the table, and we're done!

Note: I added some tailwind classes to make it look better,

Play around with the code snippet, modifying the matches, you will see instant changes in the table without further actions. Sweet!

See you around!