0

From this SO answer he said Object.keys() get properties defined on the object itself (the ones that return true for obj.hasOwnProperty(key) but below code returns 4 keys and also producing an error which is confusing to me.

(function () {
    "use strict";
    var buttons = document.getElementsByClassName('remove');
    console.log("No of keys: ", Object.keys(buttons).length);
    for ( var i in Object.keys( buttons ) ) {
        buttons[i].onclick = function() {
            this.parentElement.remove();
            console.log(this.id);
        };
    }
})();
<div>Some entry here
    <button id="0" class="remove">Remove</button>
</div>
<div>Another entry here
    <button id="1" class="remove">Remove</button>
</div>

how to do this properly in javascript?

6
  • but below code returns 4 keys nope, 2 in firefox Commented Sep 12, 2017 at 5:58
  • i am using chrome. Commented Sep 12, 2017 at 6:04
  • It's 4 in Chrome and 2 in Firefox. Because the ids are 0 and 1 the HTMLCollection has a collision between the index-based keys and id-based keys. I'm guessing that because the indexes are numbers Chrome is treating them as not equal to the string ids, though Object.keys is then converting them all to strings, so you end up with ['0', '1', '0', '1']. Commented Sep 12, 2017 at 6:12
  • ewww. chrome returns Object.keys() == ["0", "1", "0", "1"] for document.getElementsByClassName('remove') - how special is that! - even with the above explanation, why would chrome be so wrong? (note, it has NOTHING to do with the id's being 0 and 1) Commented Sep 12, 2017 at 6:12
  • 1
    try for ( var i in Object.keys(Array.from(buttons))) - chrome doesn't mess that up Commented Sep 12, 2017 at 6:18

2 Answers 2

1

So here's how you'd loop over the buttons from your original code using a for loop:

(function () {
    "use strict";
    var buttons = document.getElementsByClassName('remove');

    console.log(buttons);
    
    for (var index = 0 ; index < buttons.length ; ++index) {
        buttons[index].onclick = function() {
            this.parentElement.remove();
            console.log(this.id);
        };
    }
})();
<div>Some entry here
    <button id="a" class="remove">Remove</button>
</div>
<div>Another entry here
    <button id="b" class="remove">Remove</button>
</div>

Note that the buttons object is an HTMLCollection. This exposes elements by both index and id. In your original example your ids were 0 and 1, which is quite confusing in this case because it causes them to clash with the indexes. Object.keys(buttons) was returning ['0', '1', '0', '1'], which is a bit odd, presumably because of some number/string shenanigans. I've changed the ids in my example to a and b so now Object.keys(buttons) would be ['0', '1', 'a', 'b'].

Sign up to request clarification or add additional context in comments.

1 Comment

That's actually the correct answer to why it doesn't work, a HTMLCollection exposes the elements both by index and ID, and the OP's strange ID's was misleasing, making it look like the elements where exposed by index twice in Chrome
1

Not only for this true for obj.hasOwnProperty(key) condition, but also one of the properties attributes called enumerable must be also set to true.

What about your code. Lets see what is buttons actually. You see that this is an object, which contains 7 properties. Only 4 properties in Chrome are shown, because they are enumerable

(function () {
    "use strict";
    var buttons = document.getElementsByClassName('remove');
    console.log(buttons);
 
})();
<div>Some entry here
    <button id="0" class="remove">Remove</button>
</div>
<div>Another entry here
    <button id="1" class="remove">Remove</button>
</div>

So when you try to execute this code

(function () {
    "use strict";
    var buttons = document.getElementsByClassName('remove');

    for ( var i in Object.keys( buttons ) ) {
        console.log(i);
    }
 
})();
<div>Some entry here
    <button id="0" class="remove">Remove</button>
</div>
<div>Another entry here
    <button id="1" class="remove">Remove</button>
</div>

it actually get's the indexes of the array returned from the Object.keys which are 1,2,3,4, but you don't have a property with name 2, 3, 4 in your buttons object. So why you get the error. Use forEach function to iterate over each property and add your event listeners.

(function () {
    "use strict";
    var buttons = document.getElementsByClassName('remove');

    Array.prototype.forEach.call(buttons, button => {
        button.addEventListener('click', function() {
            this.parentElement.remove();
            console.log(this.id);
        });
    });
 
})();
<div>Some entry here
    <button id="0" class="remove">Remove</button>
</div>
<div>Another entry here
    <button id="1" class="remove">Remove</button>
</div>

2 Comments

thanks, can you explain why elements are repeated/duplicated in console
@Srinivas this is an Chrome issue, if you look it in Firefox you will see two.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.