Is there a way to alter the height of elements created dynamically with JavaScript?

Is there a way to dynamically adjust the height of each string on a fretboard based on values from an array called stringGauge? The strings are initially set at a height of 8px using the .string:before class, but I want them to increase in thickness as they are created.

Since the height needs to be assigned using a pseudo-class, inline styling may not work for this situation. How can I achieve this?

    const root = document.documentElement;
    const fretboard = document.querySelector(".fretboard");

    // The stringGauge array below contains the values I want to assign to each new string
    const stringGauge = [1, 2, 3, 6, 7, 8];

    const instrumentTuningPresets = {
      Guitar: [4, 11, 7, 2, 9, 4],
    };
    
    let selectedInstrument = "Guitar";
    let numberOfStrings = instrumentTuningPresets[selectedInstrument].length;
    
    const app = {
      init() {
        this.setupFretboard();
      },
      setupFretboard() {
        fretboard.innerHTML = "";
    
        // This creates the strings for the fretboard
        for (let i = 0; i < numberOfStrings; i++) {
          let string = tools.createElement("div");
          string.classList.add("string");
          fretboard.appendChild(string);

          // This loops through the stringGauge array but only manages to assign the
          // last value in the array which is 8. Subtracting 1-5 from i (e.g. stringGauge[i-3])
          // does change the height but for all of them.
          root.style.setProperty("--string-height", stringGauge[i]);
        }
      },
    };
    
    const tools = {
      createElement(el, content) {
        el = document.createElement(el);
        if (arguments.length > 1) {
          el.innerHTML = content;
        }
        return el;
      },
    };
    
    app.init();
:root {
  --fretboard-height: 300;
  --string-height: 8;
}

.fretboard {
  display: flex;
  flex-direction: column;
  background-image: url(../assets/images/maple.jpg);
  width: 100%;
  min-width: 1500px;
  height: calc(var(--fretboard-height) * 1px);
  margin-top: 50px;
}

.string {
  display: flex;
  position: relative;
  width: 100%;
  height: 100%;
}

.string:before {
  content: "";
  width: 100%;
  height: calc(var(--string-height) * 1px);
  background: linear-gradient(#eee, #999);
  box-shadow: 76px 3px 10px #806233;
  z-index: 1;
  position: absolute;
  top: calc(var(--string-top-position) * 1px);
}
<div class="fretboard"></div>

Answer №1

To keep your existing code largely intact, the simplest approach would involve assigning names to your css variables based on the i index and using the nth-child selector to target each string. I'm adding i+1 for clarity since nth-child counts from 1, not 0.

root.style.setProperty(`--string-height-${i+1}`, stringGauge[i]);
.string:nth-child(1):before {
    height: calc(var(--string-height-1) * 1px);
}

You could simplify the nth-child logic by utilizing a Sass loop.

A sample snippet below illustrates a straightforward starting point.

const root = document.documentElement;
    const fretboard = document.querySelector(".fretboard");

    // The stringGauge array below contains the values I want to assign to each new string
    const stringGauge = [1, 2, 3, 6, 7, 8];

    const instrumentTuningPresets = {
      Guitar: [4, 11, 7, 2, 9, 4],
    };
    
    let selectedInstrument = "Guitar";
    let numberOfStrings = instrumentTuningPresets[selectedInstrument].length;
    
    const app = {
      init() {
        this.setupFretboard();
      },
      setupFretboard() {
        fretboard.innerHTML = "";
    
        // This creates the strings for the fretboard
        for (let i = 0; i < numberOfStrings; i++) {
          let string = tools.createElement("div");
          string.classList.add("string");
          fretboard.appendChild(string);

          // Looping through the stringGauge array only assigns the last value, 8. Adjusting from i-5 in stringGauge[i-3] alters the height for all.
          root.style.setProperty(`--string-height-${i+1}`, stringGauge[i]);
        }
      },
    };
    
    const tools = {
      createElement(el, content) {
        el = document.createElement(el);
        if (arguments.length > 1) {
          el.innerHTML = content;
        }
        return el;
      },
    };
    
    app.init();
:root {
  --fretboard-height: 300;
}

.fretboard {
  display: flex;
  flex-direction: column;
  background-image: url(../assets/images/maple.jpg);
  width: 100%;
  min-width: 1500px;
  height: calc(var(--fretboard-height) * 1px);
  margin-top: 50px;
}

.string {
  display: flex;
  position: relative;
  width: 100%;
  height: 100%;
}

.string:before {
  content: "";
  width: 100%;
  background: linear-gradient(#eee, #999);
  box-shadow: 76px 3px 10px #806233;
  z-index: 1;
  position: absolute;
  top: calc(var(--string-top-position) * 1px);
}

.string:nth-child(1):before {
    height: calc(var(--string-height-1) * 1px);
}
.string:nth-child(2):before {
    height: calc(var(--string-height-2) * 1px);
}
.string:nth-child(3):before {
    height: calc(var(--string-height-3) * 1px);
}
.string:nth-child(4):before {
    height: calc(var(--string-height-4) * 1px);
}
.string:nth-child(5):before {
    height: calc(var(--string-height-5) * 1px);
}
.string:nth-child(6):before {
    height: calc(var(--string-height-6) * 1px);
}
<div class="fretboard"></div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Retrieve the Corresponding Content Inside the Div Element

I have a div with text that needs to be matched with comma-separated values: <div class="val"> This is paragraph 1 </div> <div class="val"> This is paragraph 2 </div> Using an Ajax call, I retrieve the ...

Guide on how to indicate the specific sheet on a Google Sheets API node.js batchUpdate request

I need to insert a blank row above all the data on the second sheet, but I'm having trouble specifying the exact sheet. Right now, the empty row is being added to the first sheet. const request = { spreadsheetId: 'spreadsheetId', ...

Tips for avoiding cropped images on mobile websites:

I recently created a website that looks perfect on desktop but appears cropped on mobile devices. The site in question is doc.awsri.com Here are the images causing the issue: https://i.stack.imgur.com/eRJXU.png The problem arises when viewing it on a ph ...

Getting a particular attribute and adding it to a collection in backbone.js: The solution explained

With the given JSON structure, I am looking to extract a specific attribute and store it in a collection. The data is formatted as follows: { foo: "lorem ipsum", bars: [{ a: "a", b: {c: "d", e: "f"} }, { a: "u", b: {w: ...

Tips for securely concealing an API key during website deployment on Netlify

Recently, I created a small website using Javascript just for fun and I'm looking to deploy it to Netlify. However, I've encountered an issue with the API key that the website uses. I'm struggling to figure out how to conceal this key. Curre ...

What is the design for headers in accordion-groups with ngx-bootstrap?

Is there a way to customize the style of ngx-bootstrap accordion headers? I've attempted various methods, including copying and pasting code from the documentation for header customization. However, it hasn't been successful. When inspecting the ...

Applying drop cap styles to generated content in pseudo-elements

In my blogging Q&A section, I wanted to add a unique touch by starting each question with a large question mark and each answer with a large exclamation mark as a drop cap. I tried using the ::first-letter pseudo-element along with the initial-letter prope ...

Tips for inserting a page break after every item in a loop in Visualforce when generating a PDF document

I need help with rendering a VF page as PDF. The VF page iterates over a list of account records using the repeat tag. I want to apply a page break for each element in the repeat tag. The code below is working, but it has an issue - it shows an empty PDF p ...

Comparing boolean values in React JS

I am working with a React JavaScript code in which I am iterating through a series of boolean values. The issue I am facing is that when 'data.nextrow' is false, I expect nextrow1 to also be false but it ends up being set to true instead. co ...

Declarations and expressions in Node.js using JavaScript

Recently diving into Node Js, I stumbled upon the following code snippet in a tutorial const readline = require("readline"); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); const questions = [ " ...

JavaScript implementation of Content-disposition feature

Is it possible to use client-side JavaScript to make the browser behave the same way as when it encounters "Content-disposition: attachment; filename=..."? This would mean that the data for the file to be saved is only available on the client side. For ex ...

What is the method for calculating the 100% width of a flex child?

Adjusting the width of the .sidebar to 100% seems to make it smaller in size. Interestingly, removing the body's font-size: 1.3rem and toggling the .sidebar's width: 100% results in a slightly larger appearance. It is expected that setting the ...

Easy fix for 3 circles (images) placed in a row with equal distance between them and perfectly aligned

I've been spending the last 3 days trying to accomplish this specific task: 3 circular images arranged horizontally with equal spacing Occupying 70% of the central screen area Height and width based on percentages for browser resizing adjustment It ...

Issue with unsetting values in a loop causing unexpected behavior

The array $allowedViewLevels has elements that look like this: Array ( [0] => 1 [1] => 1 [2] => 2 [3] => 3 [4] => 4 [5] => 6 [6] => 7 [7] => 8 [8] => 9 [9] => 10 [10] => 11 [ ...

Using JavaScript, transfer files directly from a client's web browser to Google Cloud Storage

I have been exploring Google Cloud Storage for file uploads and have come across various methods. The most common method seems to involve sending the file to a server first before it is then sent to Google Cloud Storage. However, I am interested in bypass ...

Creating elegant Select Dropdown Box in AngularJS without relying on images

I am currently working on an angular page and have implemented a dropdown with ng-Options to fetch and set values successfully. However, I am now looking to enhance the appearance of this dropdown. After exploring options like ui-select, I realized that be ...

Remove several elements from an array within the state of a React component using values from a second array

Here is an array let removed = [ {id: '123', name: 'Something'}, {id: '321', name: 'Something1'} ]; and I also have this piece of code this.setState({ config: { ...this.state.config, ...

Controlling the maximum number of components displayed on each row in a loop or map using React

I'm having some trouble with this seemingly simple task and could use some guidance. Any suggestions would be greatly appreciated. Thank you. My Current Situation Currently, I am working with React.js and have an array containing 20 elements. What ...

An alternative function in Python similar to R's sweep() is the numpy or pandas equivalent

Is there a Python equivalent in numpy or pandas for the R function sweep()? For example, in R, if we have a coefficient vector called beta (numeric type) and an array named data (20x5 numeric type), we can overlay the vector on each row of the array and m ...

The mouseover and mouseleave functions remain active even during window resizing

I wish to create a dynamic menu that appears when hovering over a user, but only if the window size is above 977 pixels. Take a look at my code below: $(document).ready(function() { $(window).on("load resize", function(event){ var windowS ...