vkosyj vkosyj - 12 days ago 7
HTML Question

How to attach an element on the dynamically created div

I am a guitar addict and I try to make a UI for guitar tablature.

In my js code, you can see


var notes = ['s6f1', 's5f5', 's4f7', 's3f6', 's2f5', 's1f3', 's6f8',
's5f1', 's4f6', 's3f1', 's2f3', 's1f3', 's6f9', 's5f17', 's4f19'];


's6f1' means string 6 & fret 1 and I want to show it on tablature. The way I show this is to put a "1" on string 6. Please the picture below. In my code, I basically traverse the notes array and attach each note on tablature . I define each 6 six lines as a group. After a group is filled with 4 notes, a new group is shown. Since In my real application, I do not know how many notes that notes array has(In this examples, I just simplify there are 15 notes), I have to dynamically create each group and assign each line a unique id. My question is that I do not know how to attach the number on the string. For instance, after dynamically create a "six-line", how do I attach the number on the correct line. I think the challenge in my question is that I cannot predefine the location of six-liner in html. The code below is the html, css, js code that I wrote. Hope someone could help me out. Thank you in advance.

enter image description here

html:

<!DOCTYPE html>
<html>
<head>
<link type="text/css" rel="stylesheet" href="code.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script type="text/javascript" src="code_js.js"></script>
</head>
<body>

</div>

<div id = "output">

</body>
</html>


css:

.deco {
border-bottom: 1px solid black;
width: 120px;
margin-left:0px;
margin-bottom:10px;
z-index: 2;
position: relative;
display: block;
margin-right: 20px;
}


#output {
width: 300px;
height: 200px;
position:absolute;
float:left;
background-color: yellow;
}


.six_line {
width: 125px;
height: 80px;
float:left;
margin-right: 20px;
}


js:

"use strict"
var count = 0;
var group = -1;
$(document).ready(function() {
var notes = ['s6f1', 's5f5', 's4f7', 's3f6', 's2f5', 's1f3', 's6f8', 's5f1', 's4f6', 's3f1', 's2f3', 's1f3', 's6f9', 's5f17', 's4f19'];
hideNote(notes, 0);
});

function hideNote(notes, i) {
var x = -2;
if(count == 4) {count = 0;}
if(count++ == 0) {
group++;
makeItHappen();
}
var ns4 = notes[i];
// retrive the info of string
var ns2 = ns4.substring(0,2);
x = parseInt(ns4.substring(1,2)) + (group*6);
**/*How to attach fret(#) on the string*
// finds the line with corresponding id
$('#hr' + x).attr('class', '?');
*/**
hide(function(){
if(++i < notes.length) {
hideNote(notes, i);
}
},notes[i]);
}

function hide(callback, note) {
setTimeout(function(){
callback();
}, 1000);
}

function makeItHappen() {
var six = document.createElement('div');
six.className = "six_line";
for (var i = 1; i < 7; i++) {
var hr = document.createElement('hr');
hr.className = "deco";
hr.id = "hr" + (group * 6 + i);
six.append(hr);
}
$('#output').append(six);
}

Answer

I suggest some modifications in your code. Starting with the function that creates your strings:

function makeItHappen(nbGroup) {  
    for(var g = 1; g <= nbGroup; g++){
        var six = document.createElement('div');
        six.className = "six_line";
        for (var i = 6; i >= 1; i--) {
            var string = document.createElement('div');
            string.className = "deco";
            string.id = "string" + ('G' + g + 'S' + i);
            six.append(string);
        } 
        $('#output').append(six);
    }
}

That will create all your groups of strings at the same time. It becomes easily to attribute an explicit ID for each of them : strGiSj where i is the group and j the string in the group.

Next, how about the hideNode function:

function hideNote(notes) {
    makeItHappen(Math.ceil(notes.length / 4));

    notes.forEach(function(n, i){
        var values = n.match(/s(\d)f(\d)/); // values[1] = string, values[2] = fret
        var parentEl = $("#stringG" + (Math.ceil((i + 0.5) / 4)) + "S" + values[1]);
        var child = $("<div></div>")
            .addClass("fret")
            .css("left", (10+ (i%4) * 25) + "px")
            .text(values[2]);

        parentEl.append(child)
    });
}

We create the amount of groups needed (amount of notes / 4 rounded to next int). For each note in your array, we retrieve the string and the fret with a regular expression /s(\d)f(\d+)/:

  • \d matches a digit
  • \d+ matches one or more digits
  • Parenthesis allow to retrieve values easily

Next, we just have to retrieve the appropriate group, and retrieve the associated div with good id, then create the fret element and place it.

The full code looks like this:

"use strict"

$(document).ready(function() {
    var notes = ['s6f1', 's5f5', 's4f7', 's3f6', 's2f5', 's1f3', 's6f8', 's5f1', 's4f6', 's3f1', 's2f3', 's1f3', 's6f9', 's5f17', 's4f19'];
    hideNote(notes);
});

function hideNote(notes) {

    makeItHappen(Math.ceil(notes.length / 4))

    notes.forEach(function(n, i){
      var values = n.match(/s(\d)f(\d+)/);
      var parentEl = $("#stringG" + (Math.ceil((i + 0.5) / 4)) + "S" + values[1]);
      var child = $("<div></div>")
        .addClass("fret")
        .css("left", (10+ (i%4) * 25) + "px")
        .text(values[2]);

      parentEl.append(child)
    })
}

function makeItHappen(nbGroup) {  
  for(var g = 1; g <= nbGroup; g++){
    var six = document.createElement('div');
    six.className = "six_line";
    for (var i = 6; i >= 1; i--) {
        var string = document.createElement('div');
        string.className = "deco";
        string.id = "string" + ('G' + g + 'S' + i);
        six.append(string);
    }
    $('#output').append(six);
  }
}

Here is a codepen with a working sample.