Display attributes of multiple jscript objects with a (forEach loop) onload of html page

I need to create car objects with some attributes in jscript and display them on the html page onload. I also need to add a click event listener so that when a car image is clicked an alert displays all attributes as text. I have not been able to display any thus far. See my efforts below. Each car objects has some attributes. I should display each image with two more attributes (make and model) initially. When an image is clicked, an alert should display all attributes in a text block. I am stuck at the point of displaying the first of attributes on the html. An assistance is appreciated.

Html :

<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>Cars</title>
  </head>
  <body>
    <h1>Cars On Sale</h1>
    <p>Click on each profile picture to see more details</p>
    <div id="showCars"></div>
    <script src="cars-2.js"></script>
  </body>
</html>

Javascript :

function carDescription(make, model, colour, image, regNumber, price) {
    this.make = make;
    this.model = model;
    this.colour = colour;
    this.image = image;
    this.regNumber = regNumber;
    this.price = price;
  showMore : function() {
      alert("This is " + this.make + ", " + this.model + ", " + this.color\n this.regNumber + ". It costs " + this.price + ".");
    }
   };

  const car = new carDescription("Lexus", "LX 600 SUV", "Gold", "image/Lexus.jpg", "PZ20CT", "$50,000");
  const car2 = new carDescription("Chrysler", "Pacifica", "Red", "image/Chrysler.jpg","ED50EC", "$60,000");


  let arrayOfCars = [car, car2, car3, car4, car5];

window.onload = function() {
 arrayOfCars.forEach(function(cars)) { 

   let carProfile = document.createElement("img");
   carProfile.src = cars.image;
   carProfile.alt = cars.make + " " + cars.model + ".";
   carProfile.style.height = "150px";
   carProfile.style.width = "200px";
   carProfile.innerHTML = cars.make +", " + cars.model + ".";

   document.getElementById("showCars").appendChild(carProfile);

   carProfile.addEventListener("click", function onOpen(e)) {
     this.moreDetails();
   }
 }
} 

There seem to be a few problems with the JavaScript code that you’ve written here. If you don’t have a good JavaScript editor, one thing you can do to examine the problems is open Chrome’s DevTools (Ctrl+Shift+J), copy your code there, hit Enter, and see if there are any complaints.

I did this, and I saw an error message straightaway: “Uncaught SyntaxError: Function statements require a function name”. This is coming from your showMore function in carDescription (not declared correctly). Once you fix that, you’ll see more errors (for example, the line separator “\n” is not quoted in the alert message).

So what you want to do is fix up all those errors that are obvious, and then see if your code works.

PS currently I use VS Code as a JavaScript editor. It is currently free of charge, and It works pretty well. It points out multiple issues in the JavaScript you’ve pasted here. If I were doing anything other than trivial JavaScript code edits, I’d definitely install a JavaScript editor and use it.

Good luck!

1 Like

First we get the code working. One way to do that is to use the browser console to watch for errors, but I find that a more effective way is to use a linter such as JSLint.

There are many issues that it finds, but it’s easier to accept criticism from an automated checking system than when it comes from a person.

The first issue that the automated checking system at JSLint mentions (not my complaints but the linter) is:

Unexpected character ‘\’.

The slash is with \n which is meant to be a newline. That’s only useful as part of a string, so we’ll put string quotes around it.

before:

      alert("This is " + this.make + ", " + this.model + ", " + this.color\n this.regNumber + ". It costs " + this.price + ".");

after:

      alert("This is " + this.make + ", " + this.model + ", " + this.color + "\n" + this.regNumber + ". It costs " + this.price + ".");

To make it easier to see changes, I’ll comment out the old code and show the updated code below it, like this:

   // alert("This is " + this.make + ", " + this.model + ", " + this.color\n this.regNumber + ". It costs " + his.price + ".");
      alert("This is " + this.make + ", " + this.model + ", " + this.color + "\n" + this.regNumber + ". It costs " + this.price + ".");

Unexpected ‘this’.

The this keyword can easily lead to confusion, so it’s recommended by this linter to use more expressive solutions instead. In this case, it’s an object that contains the car information.

Also, this is a good time to rename carDescription. It’s usually better to call functions like this, makeCar.

// function carDescription(make, model, colour, image, regNumber, price) {
function makeCar(make, model, colour, image, regNumber, price) {
    return {
     // this.make = make;
        make,
     // this.model = model;
        model,
     // this.colour = colour;
        colour,
     // this.image = image;
        image,
     // this.regNumber = regNumber;
        regNumber,
     // this.price = price;
        price,
     // showMore = function() {
        showMore: function() {
            alert("This is " + makeCar.make + ", " + makeCar.model + ", " + makeCar.color + "\n" + makeCar.regNumber + ". It costs " + makeCar.price + ".");
        }
    };
};

And, the new keyword isn’t used anymore.

 // const car = new carDescription("Lexus", "LX 600 SUV", "Gold", "image/Lexus.jpg", "PZ20CT", "$50,000");
    const car = makeCar("Lexus", "LX 600 SUV", "Gold", "image/Lexus.jpg", "PZ20CT", "$50,000");
 // const car2 = new carDescription("Chrysler", "Pacifica", "Red", "image/Chrysler.jpg","ED50EC", "$60,000");
    const car2 = makeCar("Chrysler", "Pacifica", "Red", "image/Chrysler.jpg","ED50EC", "$60,000");

Line is longer than 80 characters.

That is the alert line. We can break it down into multiple parts.

         // alert("This is " + newCar.make + ", " + newCar.model + ", " + newCar.color + "\n" + newCar.regNumber + ". It costs " + newCar.price + ".");
            alert(
                "This is " + newCar.make + ", " +
                newCar.model + ", " + newCar.color + "\n" +
                newCar.regNumber + ". It costs " + newCar.price + "."
            );

Another option is to define the function separately, and refer to the function from elsewhere. That helps to give us one or two sets of indents to use for extra characters.

    function showMore() {
        alert(
            "This is " + newCar.make + ", " + newCar.model + ", " + newCar.color
            + "\n" + newCar.regNumber + ". It costs " + newCar.price + "."
        );
    }
...
        regNumber,
        price,
     // showMore: function () {
         // alert("This is " + newCar.make + ", " + newCar.model + ", " + newCar.color + "\n" + newCar.regNumber + ". It costs " + newCar.price + ".");
     // }
        showMore
    };

Unexpected ‘;’.

Function declarations do not end with a semicolon.

function makeCar(make, model, colour, image, regNumber, price) {
    ...
    return newCar;
//};
}

Line is longer than 80 characters.

This time it is the car initialization lines causing the problem. Sometimes the solution is to place each parameter on separate lines:

 // const car = makeCar("Lexus", "LX 600 SUV", "Gold", "image/Lexus.jpg", "PZ20CT", "$50,000");
    const car = makeCar(
        "Lexus",
        "LX 600 SUV",
        "Gold",
        "image/Lexus.jpg",
       "PZ20CT",
        "$50,000"
    );

Other times the solution is to place the information in an array:

const carsInfo = [
    ["Lexus", "LX 600 SUV", "Gold", "image/Lexus.jpg", "PZ20CT", "$50,000"],
    ["Chrysler", "Pacifica", "Red", "image/Chrysler.jpg","ED50EC", "$60,000"]
];
const car = makeCar.apply(null, carsInfo[0]);
const car2 = makeCar.apply(null, carsInfo[1]);
// or
const cars = carsInfo.map((carInfo) => makeCar.apply(null, carInfo));

I won’t use the array thing this time, and instead place the function arguments onto different lines.

Expected ‘{’ and instead saw ‘)’.

The function parameters use only one closing parenthesis:

 // arrayOfCars.forEach(function(cars)) { 
    arrayOfCars.forEach(function(cars) { 

Unexpected trailing space.

The linter gets picky about spacing. Extra space at the end of a line should be remove too, in this case at the end of the arrayOfCars line.

Expected ‘{’ and instead saw ‘)’.

The carProfile line also has a similar issue as dealt with above:

// carProfile.addEventListener("click", function onOpen(e)) {
   carProfile.addEventListener("click", function onOpen(e) {

Unexpected ‘this’.

The line that we’re dealing with now is the following:

     this.moreDetails();

Instead of moreDetails, do you mean the showMore function of the car? Even when the command is this.showMore, that won’t do what you expect, because the this keyword is confusing. Here, the this keyword doesn’t refer to the car, but to the HTML element that triggered the click event.

A safe way to deal with this is to add a data index to the element, so that you can easily refer back to the car information once again.

// arrayOfCars.forEach(function(cars) {
arrayOfCars.forEach(function(cars, index) {
    let carProfile = document.createElement("img");
    carProfile.dataset.index = index;
    ...
});
   carProfile.addEventListener("click", function onOpen(e) {
     // this.showDetails();
     const el = e.target;
     const carIndex = el.dataset.index;
     arrayOfCars[carIndex].showMore();
   });

Expected ‘)’ to match ‘(’ from line 41 and instead saw ‘}’.

This is about the addEventListener closing brace. You’ve closed off the function, but also need to close off the function arguments with a closing parenthesis, and a semicolon to end the expression.

   carProfile.addEventListener("click", function onOpen(e) {
     ...
// }
   })

Expected ‘;’ and instead saw ‘}’.

It is the forEach closing brace being mentioned here. The line before it needs a semicolon to end to indicate that it’s the end of the expression.

 arrayOfCars.forEach(function(cars, index) {
   ...
   carProfile.addEventListener("click", function onOpen(e) {
     ...
// })
   });
 }

Expected ‘)’ to match ‘(’ from line 30 and instead saw ‘}’.

What this is referring to is the forEach closing parenthesis that is expected. We can also end it with a semicolon too to avoid a repeat of the previous semicolon message.

 arrayOfCars.forEach(function(cars, index) {
   ...
//}
});

Undeclared ‘alert’.

Alert is a part of the window object, so we should use window.alert instead of just alert.

     // alert(
        window.alert(

Undeclared ‘window’.

Gah! We should tell jslint that we expect that a web browser is being used, so that window is available. We do that by placing the following declaration comment at the top of the code:

/*jslint browser */
function makeCar(make, model, colour, image, regNumber, price) {

Undeclared ‘car3’.

I’ll remove the other cars that you referred to in the code:

//let arrayOfCars = [car, car2, car3, car4, car5];
  let arrayOfCars = [car, car2];

Unexpected trailing space.

The closing brace at the end of the code has a trailing space. The trailing space should be removed from the end of it.

Expected ‘;’ and instead saw ‘(end)’.

This is the same closing brace that had the trailing space. Place a semicolon after the brace.

window.onload = function() {
    ...
//}
};

Expected ‘const’ at column 0, not column 2.

And now a whole new set of complaints occur about the formatting of the code. Spaces only (no tabs), using four spaces per indent is the standard.

We can shortcut that by using the Online Javascript Beautifier

Pasting the JSLint updated code into the online JS beautifier, gives us the following improved formatted code:

/*jslint browser */
function makeCar(make, model, colour, image, regNumber, price) {
    function showMore() {
        window.alert(
            "This is " + newCar.make + ", " + newCar.model + ", " + newCar.color
            + "\n" + newCar.regNumber + ". It costs " + newCar.price + "."
        );
    }
    const newCar = {
        make,
        model,
        colour,
        image,
        regNumber,
        price,
        showMore
    };
    return newCar;
}

const car = makeCar(
    "Lexus",
    "LX 600 SUV",
    "Gold",
    "image/Lexus.jpg",
    "PZ20CT",
    "$50,000"
);
const car2 = makeCar(
    "Chrysler",
    "Pacifica",
    "Red",
    "image/Chrysler.jpg",
    "ED50EC",
    "$60,000"
);

let arrayOfCars = [car, car2];

window.onload = function() {
    arrayOfCars.forEach(function(cars, index) {
        let carProfile = document.createElement("img");
        carProfile.dataset.index = index;
        carProfile.src = cars.image;
        carProfile.alt = cars.make + " " + cars.model + ".";
        carProfile.style.height = "150px";
        carProfile.style.width = "200px";
        carProfile.innerHTML = cars.make + ", " + cars.model + ".";

        document.getElementById("showCars").appendChild(carProfile);

        carProfile.addEventListener("click", function onOpen(e) {
            const el = e.target;
            const carIndex = el.dataset.index;
            arrayOfCars[carIndex].showMore();
        });
    });
};

We can paste the improved formatted code back in to JSLint, and carry on with the improvements.

Expected one space between ‘function’ and ‘(’.

The code beautifier removes an empty space between the function keyword and the opening parenthesis of the function parameters.

JSLint doesn’t like that space being removed, and warns us about it, making it easy for us to find anonymous functions. These are a problem for several reasons, and naming them helps with debugging the code, and in understanding what the function does.

In this case, it’s the window.onload function that should have a name given to it. Here we are adding cars to the page, so that’s a good name to give to the function:

// window.onload = function() {
window.onload = function addCarsToPage() {

Expected one space between ‘function’ and ‘(’.

The other place that has an unnamed function is the forEach line. There we are adding a single car to the page.

 // arrayOfCars.forEach(function(cars, index) {
    arrayOfCars.forEach(function addCarToPage(cars, index) {

No more complaints

We now have code that the linter finds no more problems with.

Testing out the code, clicking on a car shows the alert, but one part of it is undefined.

Investigating the code I see that you used colour in a few places, but color for the alert. Let’s fix that.

        window.alert(
         // "This is " + newCar.make + ", " + newCar.model + ", " + newCar.color
            "This is " + newCar.make + ", " + newCar.model + ", " + newCar.colour
            + "\n" + newCar.regNumber + ". It costs " + newCar.price + "."
        );

And the code now looks like it’s working in the manner that is expected of it.

3 Likes

Thanks Paul. This took some of your time but its clear and I have picked up some more logic and syntax knowledge. As for criticism, I see myself as a learner, a teachable person. So criticism is my greatest resource, next to working knowledge. Many thanks.

Hey just a quick point. I might consider making this a class instead of a normal function. Would help for re use.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.