0

I am creating a table of inputs. enter image description here

When an input is changed, the change event should trigger a function ( updatePlanner()) to change the data in the underlying data. Here is where I create the table.

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

    // header code removed

    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();
            td.style.height = "26px";

            switch(j % 3){
                case 0:
                    var currItem = document.createElement('input');
                    currItem.value = builerObj.dataArray[2][week][i][0];
                    currItem.addEventListener("change", function(){
                        updatePlanner(this.value, week, i, 0);  //<-----------THIS IS MY ISSUE
                    });
                    break;
                case 1:
                    var currItem = document.createElement('input');
                    currItem.value = builerObj.dataArray[2][week][i][1];
                    break;
                case 2:
                    var currItem = document.createElement('button');
                    currItem.style.height = "26px";
                    currItem.style.border = "none";
                    currItem.style.padding = "0px";
                    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;
                    break;
            }

            currID = i.toString() + "-" + j.toString()
            currItem.setAttribute("id", currID);
            currItem.style.width = "40px";


            td.appendChild(currItem);
            td.style.border = '1px solid black';

        }
    }
    body.innerHTML = "";
    body.appendChild(tbl);
}

As you can see I am trying to use this.value, but that isn't returning a value. I've also tried assigning the ID earlier and refer to it:

        ...
        currID = i.toString() + "-" + j.toString();

            switch(j % 3){
                case 0:

                    var currItem = document.createElement('input');
                    currItem.setAttribute("id", currID);
                    currItem.value = builerObj.dataArray[2][week][i][0];
                    currItem.addEventListener("change", function(){
                        updatePlanner(document.getElementById(currID).value, week, i, 0);
                    });
                    break;
                    ...
Nate May
  • 3,814
  • 7
  • 33
  • 86
  • Are you averse to using [jQuery](https://jquery.com/)? – Chloe Oct 28 '15 at 19:58
  • 1
    Define "isn't working". In any case, you don't even need a `this` reference, you can use `currItem.value` if nothing else. But the value of `this` depends a lot on the context of how you're creating the function etc. – Dave Newton Oct 28 '15 at 20:00
  • @FelesMortis I'm fine with jQuery – Nate May Oct 28 '15 at 20:02
  • @DaveNewton the this.value and currItem.value do not return a value. I get the error "Uncaught TypeError: Cannot read property '3' of Undefined" – Nate May Oct 28 '15 at 20:04
  • Provide more details on the error. Is the error in `updatePlanner`? Is `currItem`'s value correct when you set it? – Dave Newton Oct 28 '15 at 20:05
  • Possible duplicate of [addEventListener to an element, with the element itself as parameter](http://stackoverflow.com/questions/31272118/addeventlistener-to-an-element-with-the-element-itself-as-parameter) – Dan Lowe Oct 28 '15 at 20:06
  • You could assign each element an id as well as a common class to all of them as you create them. Use the class as the trigger and the id to identify which specific element triggered it. – SunKnight0 Oct 28 '15 at 20:10
  • 1
    The only location in this example where the error could be thrown is `builerObj.dataArray[2][week][i]`, which doesn't have anything to do with how you bind the handler. Not sure if we can help you if you don't provide a *runnable* example that reproduces the issue. – Felix Kling Oct 28 '15 at 20:13
  • @SunKnight0 I tried that, as you can see in my edit – Nate May Oct 28 '15 at 20:30
  • @Nate May I do all this with JQuery not vanilla JavaScript so I wouldn't know why it is not working for you, sorry. – SunKnight0 Oct 28 '15 at 20:43
  • I believe `this.value` works just fine, and your issue is actually with `week` and `i`: [JavaScript closure inside loops – simple practical example](http://stackoverflow.com/q/750486/218196). – Felix Kling Oct 28 '15 at 22:23
  • Argh, I accidentally undid my upvote on @FelixKling's comment. Agreed! Nothing wrong with your use of `this`, as it's within the event handler, so it refers to the input that changed. – James Oct 28 '15 at 23:58

2 Answers2

0

this.value returns the correct value, but the other parameters, week and i, don't have the values you expect. You want them to have the values at the time the listener was added, but instead, they have the values at the time the listener was executed. To solve this, you can store these values as attributes in the input tag and retrieve them later on, like this:

    $(currItem).attr("data-week", week);
    $(currItem).attr("data-i", i);
    currItem.addEventListener("change", function(){
         var week_value = $(this).attr("data-week");
         var i_value = $(this).attr("data-i");
         updatePlanner(this.value, parseInt(week_value), parseInt(i_value), 0);
    }, false);
www.admiraalit.nl
  • 5,768
  • 1
  • 17
  • 32
  • What's wrong with the OP's approach using `this`? How does it solve the problem? – Felix Kling Oct 28 '15 at 20:12
  • I have completely changed my answer. – www.admiraalit.nl Oct 28 '15 at 22:16
  • *"The image in your question shows that the input fields are actually checkboxes."* What makes you think the inputs correspond to the checkboxes and not the text inputs next to them? The code certainly doesn't generate checkboxes, nowhere I can see `currItem.type = 'checkbox';`? Also if you look closely, the checkboxes in the image are actually buttons with a special glyph. – Felix Kling Oct 28 '15 at 22:20
  • Again, I have completely changed my answer. – www.admiraalit.nl Oct 29 '15 at 16:39
0

There are several things you could be looking for here. The easiest is to add the event argument to the callback function like so:

currItem.addEventListener("change", function(e){
  updatePlanner(e.target.value, week, i, 0);
});
Chloe
  • 483
  • 4
  • 14