1

This question is similar to THIS ONE, but I still could not solve my issue after reading.

Basically I am trying to make the table below dynamic in size. Also, when a value is changed, I want it to update the underlying JavaScript function. enter image description here

**However I can't figure out how to both reference the elements uniquely and also pass the relevant parameters through to update the object. updatePlanner() is called upon a change, but the the value passed through is always the last unique ID created: in this case "2-11". What am I doing wrong? **

Here is my initial object:

builerObj.dataArray = [4,3,[[[5, .65, 0],[5, .75, 0],[5, .85, 1]], 
                            [[3, .70, 0],[3, .80, 0],[3, .90, 1]],
                            [[5, .75, 0],[3, .85, 0],[1, .95, 1]],
                            [[5, .40, 0],[5, .50, 0],[5, .60, 0]]]];

Here is the function to update it (Notice that I pass through the Id of an element to reference its value):

function updatePlanner(passedId, week, set, index) {
    var value = document.getElementById(passedId).value;

    // I've removed some irrelevant manipulation of the value variable

    builerObj.dataArray[2][week][set][index] = value;

        columns = $('#planBuilderWeeks')[0].value; // columns
        rows = $('#planBuilderSets')[0].value; // rows
        createPlanningTable(columns, rows);

}

And here is the table generator (styling code removed):

function createPlanningTable(columns, rows){
    var body = document.getElementById('planBuilderTable'),
        tbl  = document.createElement('table');

    // Styling and Headers are here

    for(var i = 0; i < rows; i++){
        var tr = tbl.insertRow();
        var week = 0;

        for(var j = 0; j < columns * 3; j++){
            var td = tr.insertCell();
            var currID = i.toString() + "-" + j.toString(); // Unique ID for each input

            if (j % 3 == 0 ){              // This handels all columns labeled '%Max'
                var currItem = document.createElement('input');
                currItem.value = builerObj.dataArray[2][week][i][0];
                currItem.addEventListener("change", function(){
                     updatePlanner(currID, week, i, 0); // This is where I haven't been able to make it work
                }, false);
            } else if (j % 3 == 1){        // This handels all columns labeled 'Reps'
                var currItem = document.createElement('input');
                currItem.value = builerObj.dataArray[2][week][i][1];
            } else if (j % 3 == 2){        // This handels all columns labeled '+'
                var currItem = document.createElement('button');
                currItem.style.display = "block";
                var span = document.createElement('span');
                if (builerObj.dataArray[2][week][i][2] == 1){
                    span.className = "glyphicon glyphicon-ok box";
                } else{
                    span.className = "glyphicon box";
                }
                currItem.appendChild(span);
                week += 1;
            } else {
                alert("Something went wrong");
            }

            currItem.setAttribute("id", currID);   
            td.appendChild(currItem);
        }
    }
    body.innerHTML = "";
    body.appendChild(tbl);
}
Community
  • 1
  • 1
Nate May
  • 3,814
  • 7
  • 33
  • 86

2 Answers2

1

currID is evaluated at the moment the listener is executed. At that moment, currID has already reached its last value. Instead of passing the id, you can pass the value to updatePlanner, like this:

function updatePlanner(value, week, set, index) {

and then the call is:

updatePlanner (this.value, week, i, 0);

But note, that 'week' and 'i' have also already reached their last values. I noticed that you are using JQuery in the updatePlanner function. JQuery's ".on" function can remember the right values for you. Here is the solution:

         if (j % 3 == 0 ){ 
             var currItem = document.createElement('input');
             var eventData = { week : week, set : i };
             $(currItem).on("change", null, eventData, function(event){
                 updatePlanner(event.target.value, event.data.week, event.data.set, 0);
             });
www.admiraalit.nl
  • 5,768
  • 1
  • 17
  • 32
  • @www.admiaalit.nl YES! thank you so much! This is my first major JavaScript creation. Would you say that this is a bad design? If so how else can I build this functionality? – Nate May Oct 29 '15 at 16:20
  • I have changed my answer by using JQuery – www.admiraalit.nl Oct 29 '15 at 16:28
  • Personally, I would have used AngularJS. This would eliminate the need to create HTML tags in JavaScript. Instead, you would use so-called 'directives' in the HTML page to dynamically build the table. But there are other frameworks that have similar functionality. – www.admiraalit.nl Oct 29 '15 at 16:32
  • I have just learned about parameter 'data' of JQuery's ".on" function, which simplifies the solution. For more info, see http://api.jquery.com/on/ – www.admiraalit.nl Oct 30 '15 at 20:49
1

You could also use Closures, so you would not need to alter your HTML.

function updatePlannerEvent( currId, week, i ) {
    return function() {
        updatePlanner(currId, week, i, 0);
    }
}

currItem.addEventListener("change", updatePlannerEvent(currId, week, i), false);
alvarodms
  • 671
  • 5
  • 8