Build a Sorting Visualizer - Build a Sorting Visualizer Step 18

Tell us what’s happening:

Failed:18. After you click #sort-btn, #array-container should contain as many div elements as the steps required by the Bubble Sort algorithm to sort the starting array, including the div representing the starting array and a div representing the sorted array.

I tried more than an hour fixing this issue but the 18th point is not getting covered. Can anyone look into it and give me solution?

Your code so far

<!-- file: index.html -->

/* file: styles.css */

/* file: script.js */

Your browser information:

User Agent is: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36

Challenge Information:

Build a Sorting Visualizer - Build a Sorting Visualizer

Hey there,

Please update the message to include your code. The code was too long to be automatically inserted by the help button.

When you enter a code, please precede it with a separate line of three backticks and follow it with a separate line of three backticks to make it easier to read.

You can also use the “preformatted text” tool in the editor (</>) to add backticks around text.

See this post to find the backtick on your keyboard.
Note: Backticks (`) are not single quotes (').

Below is my code:

Sorting Visualizer

Generate Array

Sort Array

Could you please help me out with Step18

please use the formatting guide shared in the post above, or we are unable to read your code

I’m working on Step 18 of the Sorting Visualizer project and I’m stuck. The requirement says that after clicking Sort Array, the #array-container should contain as many div elements as the steps required by the Bubble Sort algorithm, including the starting array and the sorted array.

Below is my current code:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Sorting Visualizer</title>
<link rel="stylesheet" href="styles.css">
</head>

<body>
<main>
<div id="array-container">
<div id="starting-array"></div>
</div>

<div id="btn-container">
Generate Array
Sort Array
</div>
</main>

<script>
let currentArray = [];

function generateElement() {
  return Math.floor(Math.random() * 100) + 1;
}

function generateArray() {
  const arr = [];
  for (let i = 0; i < 5; i++) {
    arr.push(generateElement());
  }
  return arr;
}

function generateContainer() {
  return document.createElement("div");
}

function fillArrContainer(container, arr) {
  container.innerHTML = "";
  arr.forEach(num => {
    const span = document.createElement("span");
    span.textContent = num;
    container.appendChild(span);
  });
}

function isOrdered(a, b) {
  return a <= b;
}

function swapElements(arr, index) {
  if (!isOrdered(arr[index], arr[index + 1])) {
    const temp = arr[index];
    arr[index] = arr[index + 1];
    arr[index + 1] = temp;
    return true;
  }
  return false;
}

function highlightCurrentEls(container, index) {
  const children = container.children;
  if (children[index]) {
    children[index].style.border = "2px dashed red";
  }
  if (children[index + 1]) {
    children[index + 1].style.border = "2px dashed red";
  }
}

document.getElementById("generate-btn").addEventListener("click", () => {
  currentArray = generateArray();
  const arrayContainer = document.getElementById("array-container");
  arrayContainer.innerHTML = "";

  const startingArray = document.createElement("div");
  startingArray.id = "starting-array";
  arrayContainer.appendChild(startingArray);

  fillArrContainer(startingArray, currentArray);
});

document.getElementById("sort-btn").addEventListener("click", () => {
  if (!currentArray.length) return;

  const arrayContainer = document.getElementById("array-container");
  arrayContainer.innerHTML = "";

  let arr = [...currentArray];
  const n = arr.length;

  // Div 1: starting array
  const startingDiv = document.createElement("div");
  startingDiv.id = "starting-array";
  fillArrContainer(startingDiv, arr);
  highlightCurrentEls(startingDiv, 0);
  arrayContainer.appendChild(startingDiv);

  for (let i = 0; i < n - 1; i++) {
    for (let j = 0; j < n - i - 1; j++) {

      swapElements(arr, j);

      const isLastComparison = (i === n - 2) && (j === n - i - 2);
      if (isLastComparison) break;

      const step = generateContainer();
      fillArrContainer(step, arr);

      if (j + 1 < n - i - 1) {
        highlightCurrentEls(step, j + 1);
      } else if (i + 1 < n - 1) {
        highlightCurrentEls(step, 0);
      }

      arrayContainer.appendChild(step);
    }
  }

  const finalDiv = generateContainer();
  fillArrContainer(finalDiv, arr);
  arrayContainer.appendChild(finalDiv);
});
</script>

</body>
</html>

Could someone please help me understand what might be missing or incorrect for Step 18?

let currentArray = [];

// 1. Generate random number between 1 and 100
function generateElement() {
  return Math.floor(Math.random() * 100) + 1;
}

// 2. Generate array of 5 numbers
function generateArray() {
  const arr = [];
  for (let i = 0; i < 5; i++) {
    arr.push(generateElement());
  }
  return arr;
}

// 3. Create empty div container
function generateContainer() {
  return document.createElement("div");
}

// 4. Fill container with spans
function fillArrContainer(container, arr) {
  container.innerHTML = "";
  arr.forEach(num => {
    const span = document.createElement("span");
    span.textContent = num;
    container.appendChild(span);
  });
}

// 5. Compare numbers
function isOrdered(a, b) {
  return a <= b;
}

// 6. Swap elements if needed
function swapElements(arr, index) {
  if (!isOrdered(arr[index], arr[index + 1])) {
    const temp = arr[index];
    arr[index] = arr[index + 1];
    arr[index + 1] = temp;
  }
}

// 7. Highlight compared elements
function highlightCurrentEls(container, index) {
  const children = container.children;

  if (children[index]) {
    children[index].style.border = "2px dashed red";
  }

  if (children[index + 1]) {
    children[index + 1].style.border = "2px dashed red";
  }
}

function getBubbleSortSteps(array) {
  const arr = [...array];
  const steps = [];

  // Push starting array
  steps.push([...arr]);

  const n = arr.length;

  for (let i = 0; i < n - 1; i++) {
    for (let j = 0; j < n - i - 1; j++) {

      // Swap if needed
      if (arr[j] > arr[j + 1]) {
        const temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
      }

      // Push step AFTER every comparison
      steps.push([...arr]);
    }
  }

  return steps;
}


// GENERATE BUTTON
document.getElementById("generate-btn").addEventListener("click", () => {
  currentArray = generateArray();

  const arrayContainer = document.getElementById("array-container");
  arrayContainer.innerHTML = "";

  const startingArray = document.createElement("div");
  startingArray.id = "starting-array";

  fillArrContainer(startingArray, currentArray);
  arrayContainer.appendChild(startingArray);
});

document.getElementById("sort-btn").addEventListener("click", () => {
  if (!currentArray.length) return;

  const arrayContainer = document.getElementById("array-container");
  arrayContainer.innerHTML = "";

  let arr = [...currentArray];
  const n = arr.length;

  // Starting step
  const startingDiv = document.createElement("div");
  startingDiv.id = "starting-array";
  fillArrContainer(startingDiv, arr);
  highlightCurrentEls(startingDiv, 0);
  arrayContainer.appendChild(startingDiv);

  for (let i = 0; i < n - 1; i++) {
    for (let j = 0; j < n - i - 1; j++) {

      swapElements(arr, j);

      const stepDiv = generateContainer();
      fillArrContainer(stepDiv, arr);

      if (j + 1 < n - i - 1) {
        highlightCurrentEls(stepDiv, j + 1);
      } else if (i + 1 < n - 1) {
        highlightCurrentEls(stepDiv, 0);
      }

      arrayContainer.appendChild(stepDiv);
    }
  }
  const finalDiv = generateContainer();
  fillArrContainer(finalDiv, arr);
  arrayContainer.appendChild(finalDiv);
});

The Step18 is getting failed after many attempts:

18. After you click #sort-btn, #array-container should contain as many div elements as the steps required by the Bubble Sort algorithm to sort the starting array, including the div representing the starting array and a div representing the sorted array.

generate an array with the example app, then see what your app does with that same array (you can make generateArray return that array to test)

let currentArray = [];

// 1. Generate random number between 1 and 100
function generateElement() {
  return Math.floor(Math.random() * 100) + 1;
}

// 2. Generate array of 5 numbers
function generateArray() {
  const arr = [];
  for (let i = 0; i < 5; i++) {
    arr.push(generateElement());
  }
  return arr;
}

// 3. Create empty div container
function generateContainer() {
  return document.createElement("div");
}

// 4. Fill container with spans
function fillArrContainer(container, arr) {
  container.innerHTML = "";
  arr.forEach(num => {
    const span = document.createElement("span");
    span.textContent = num;
    container.appendChild(span);
  });
}

// 5. Compare numbers
function isOrdered(a, b) {
  return a <= b;
}

// 6. Swap elements if needed
function swapElements(arr, index) {
  if (!isOrdered(arr[index], arr[index + 1])) {
    const temp = arr[index];
    arr[index] = arr[index + 1];
    arr[index + 1] = temp;
  }
}

// 7. Highlight compared elements
function highlightCurrentEls(container, index) {
  const children = container.children;

  if (children[index]) {
    children[index].style.border = "2px dashed red";
  }

  if (children[index + 1]) {
    children[index + 1].style.border = "2px dashed red";
  }
}

function getBubbleSortSteps(array) {
  const arr = [...array];
  const steps = [];

  // Push starting array
  steps.push([...arr]);

  const n = arr.length;

  for (let i = 0; i < n - 1; i++) {
    for (let j = 0; j < n - i - 1; j++) {

      // Swap if needed
      if (arr[j] > arr[j + 1]) {
        const temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
      }

      // Push step AFTER every comparison
      steps.push([...arr]);
    }
  }

  return steps;
}


// GENERATE BUTTON
document.getElementById("generate-btn").addEventListener("click", () => {
  currentArray = generateArray();

  const arrayContainer = document.getElementById("array-container");
  arrayContainer.innerHTML = "";

  const startingArray = document.createElement("div");
  startingArray.id = "starting-array";

  fillArrContainer(startingArray, currentArray);
  arrayContainer.appendChild(startingArray);
});

document.getElementById("sort-btn").addEventListener("click", () => {
  if (!currentArray.length) return;

  const arrayContainer = document.getElementById("array-container");
  arrayContainer.innerHTML = "";

  const steps = getBubbleSortSteps(currentArray);
  const n = currentArray.length;

  // Pre-compute which index to highlight for each step
  const highlights = [];
  highlights.push(0); // step 0: starting array, highlight first pair

  for (let i = 0; i < n - 1; i++) {
    for (let j = 0; j < n - i - 1; j++) {
      const isLast = (i === n - 2 && j === n - i - 2);
      if (isLast) {
        highlights.push(null); // final sorted array, no highlight
      } else {
        const nextJ = j + 1 >= n - i - 1 ? 0 : j + 1;
        highlights.push(nextJ);
      }
    }
  }

  steps.forEach((stepArr, idx) => {
    const stepDiv = generateContainer();
    if (idx === 0) stepDiv.id = "starting-array";
    fillArrContainer(stepDiv, stepArr);
    if (highlights[idx] !== null) {
      highlightCurrentEls(stepDiv, highlights[idx]);
    }
    arrayContainer.appendChild(stepDiv);
  });
});

Still Step 18 is getting failed. Please could you deeply dive and find a workaround.

Learning to debug your own code is an important developer skill.

Did you try this?

yes i did it but it didnot worked.

What didn’t work? What did you do? Steps, please.

As per the example array, we have generateArray as

function generateArray() { return [86, 72, 2, 36, 73]; }

but this is hardcoded array.

are you comparing what the example app does and what your code does

Yes, I am comparing the two. To follow your requirement, I am using the exact data from the example app.

are you sure you shared working code with us? I only see Uncaught TypeError: Cannot read properties of null (reading 'addEventListener') and am unable to interact with the app

let currentArray = [];

// 1. Generate random number between 1 and 100
function generateElement() {
  return Math.floor(Math.random() * 100) + 1;
}

// 2. Generate array of 5 numbers
function generateArray() {
  const arr = [];
  for (let i = 0; i < 5; i++) {
    arr.push(generateElement());
  }
  return arr;
}

// 3. Create empty div container
function generateContainer() {
  return document.createElement("div");
}

// 4. Fill container with spans
function fillArrContainer(container, arr) {
  container.innerHTML = "";
  arr.forEach(num => {
    const span = document.createElement("span");
    span.textContent = num;
    container.appendChild(span);
  });
}

// 5. Compare numbers
function isOrdered(a, b) {
  return a <= b;
}

// 6. Swap elements if needed
function swapElements(arr, index) {
  if (!isOrdered(arr[index], arr[index + 1])) {
    const temp = arr[index];
    arr[index] = arr[index + 1];
    arr[index + 1] = temp;
  }
}

// 7. Highlight compared elements
function highlightCurrentEls(container, index) {
  const children = container.children;

  if (children[index]) {
    children[index].style.border = "2px dashed red";
  }

  if (children[index + 1]) {
    children[index + 1].style.border = "2px dashed red";
  }
}

function getBubbleSortSteps(array) {
  const arr = [...array];
  const steps = [];

  // Push starting array
  steps.push([...arr]);

  const n = arr.length;

  for (let i = 0; i < n - 1; i++) {
    for (let j = 0; j < n - i - 1; j++) {

      // Swap if needed
      if (arr[j] > arr[j + 1]) {
        const temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
      }

      // Push step AFTER every comparison
      steps.push([...arr]);
    }
  }

  return steps;
}


// GENERATE BUTTON
document.getElementById("generate-btn").addEventListener("click", () => {
  currentArray = generateArray();

  const arrayContainer = document.getElementById("array-container");
  arrayContainer.innerHTML = "";

  const startingArray = document.createElement("div");
  startingArray.id = "starting-array";

  fillArrContainer(startingArray, currentArray);
  arrayContainer.appendChild(startingArray);
});

document.getElementById("sort-btn").addEventListener("click", () => {
  if (!currentArray.length) return;   // ← DELETE THIS LINE
  
  const arrayContainer = document.getElementById("array-container");

  arrayContainer.innerHTML = "";

  const steps = getBubbleSortSteps(currentArray);
  const n = currentArray.length;

  // Pre-compute which index to highlight for each step
  const highlights = [];
  highlights.push(0); // step 0: starting array, highlight first pair

  for (let i = 0; i < n - 1; i++) {
    for (let j = 0; j < n - i - 1; j++) {
      const isLast = (i === n - 2 && j === n - i - 2);
      if (isLast) {
        highlights.push(null); // final sorted array, no highlight
      } else {
        const nextJ = j + 1 >= n - i - 1 ? 0 : j + 1;
        highlights.push(nextJ);
      }
    }
  }

  steps.forEach((stepArr, idx) => {
    const stepDiv = generateContainer();
    if (idx === 0) stepDiv.id = "starting-array";
    fillArrContainer(stepDiv, stepArr);
    if (highlights[idx] !== null) {
      highlightCurrentEls(stepDiv, highlights[idx]);
    }
    arrayContainer.appendChild(stepDiv);
  });
});

what about your html?

Yes i have shared a working code with just Step 18 failure.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Sorting Visualizer</title>
    <link rel="stylesheet" href="styles.css">
</head>

<body>
    <main>
        <div id="array-container">
            <div id="starting-array"></div>
        </div>
        <div id="btn-container">
            <button id="generate-btn" type="button">Generate Array</button>
            <button id="sort-btn" type="button">Sort Array</button>
        </div>
    </main>
    <script src="script.js"></script>
</body>

</html>

so you are testing your app and seeing no differences?

are you sure they are doing the same thing?