To directly address your question, the problem lies in the code:
// this line returns a NodeList of all elements matching the // supplied CSS selector ('.ckb'), this NodeList has no // 'checked' property, and so will ultimately return // undefined. var checkedValue = document.querySelectorAll('.ckb').checked; document.getElementById('btn').addEventListener('click', function(){ // here you try to access the 'value' property of the undefined // Object returned earlier, which returns null: document.getElementById('txt').innerText = checkedValue.value ; });
As an alternative, I would suggest something like the following:
// using a const to declare the element, since it's unlikely // you'll want to change which element triggers the function: const button = document.getElementById('btn'); //here we bind the anonymous function of EventTarget.addEventListener() // to the 'click' event upon that identified <button> element, using // Arrow function syntax (since we don't require access to the // 'this'): button.addEventListener('click', (e) => { // here we retrieve all elements which are checked (using the // CSS pseudo-class ':checked') and have the class of 'ckb': let checked = document.querySelectorAll('.ckb:checked'), // retrieving the element into which the output should be // displayed: output = document.querySelector('#txt'); // here we update the text-content (using the textContent property) // and set it equal to the results returned from: // first converting the NodeList of checked // into an Array, using Array.from(), using the // Array.prototype.map() method to iterate over that // Array: output.textContent = Array.from(checked).map( // returning the value of the element ('el'): (el) => el.value // joining those array elements together into a String, using // Array.prototype.join(), and appending a period for // grammatical correctness: ).join(', ') + '. '; });
const button = document.getElementById('btn'); button.addEventListener('click', (e) => { let checked = document.querySelectorAll('.ckb:checked'), output = document.querySelector('#txt'); output.textContent = Array.from(checked).map( (el) => el.value ).join(', ') + '. '; });
*, ::before, ::after { box-sizing: border-box; font-size: 1rem; line-height: 1.4; margin: 0; padding: 0; } #txt::before { content: 'Checked items: ' } #txt:empty::before { color: #999; content: 'No items checked.'; } input { margin-right: 0.5em; }
<p id='txt'></p> <button id="btn" type="button">Click</button> <label> <input type="checkbox" class="ckb" value="1">one </label> <label> <input type="checkbox" class="ckb" value="2">two </label> <label> <input type="checkbox" class="ckb" value="3">three </label>
JS Fiddle demo.
Note that I've also wrapped each <input> element within a <label> element, in order that clicking the text associated with each <input> also toggles the checked state of that element.
Using CSS generated content, I've taken the liberty of giving an indication of the current state; when the <p id="txt"> element is empty (matching the :empty pseudo-class, containing not even white-space) it shows the message "No items checked"), this may — or may not — represent a user-experience/interface improvement, but adjust to your own preference.
Further we move the event-binding out of the HTML mark-up, in order to reduce clutter in that mark-up, and reduce complications when it comes to future maintenance of the page.
You could, of course, bind the change event on the <input> elements themselves:
const inputs = document.querySelectorAll('.ckb'), output = () => { let results = document.querySelector('#txt'), checked = Array.from(inputs).filter( (el) => el.checked ); results.textContent = checked.length === 0 ? '' : checked.map( (el) => el.value ).join(', ') + '. '; }; inputs.forEach( (el) => el.addEventListener('change', output) );
// getting a NodeList of all elements matching the supplied // CSS selector: const inputs = document.querySelectorAll('.ckb'), // defining the function to bind as the event- // handler, using Arrow function syntax: output = () => { // retrieving the element to which the results // should be inserted: let results = document.querySelector('#txt'), // using Array.from() to convert the 'inputs' // variable to an Array, and then calling // Array.prototype.filter() to filter that // Array returning a new one: checked = Array.from(inputs).filter( // 'el' refers to the current Array-element // (node) of the Array we're iterating over, // el.checked is a Boolean, and // Array.protoype.filter() retains those Array- // elements the assessment of which returns a // true/truthy value (discarding those which do // not): (el) => el.checked ); // here we use a ternary - conditional operator - to first // check if the length of the checked Array is exactly zero; // if so we return an empty string; otherwise we return // the map of Array-element (node) values joined - as above - // with a comma and space, with an appended period: results.textContent = checked.length === 0 ? '' : checked.map( (el) => el.value ).join(', ') + '. '; }; // iterating over the NodeList of .ckb elements, with an // Arrow function, and in each iteration we bind the // output() function as the event-handler for the 'change' // event: inputs.forEach( (el) => el.addEventListener('change', output) );
*, ::before, ::after { box-sizing: border-box; font-size: 1rem; line-height: 1.4; margin: 0; padding: 0; } #txt::before { content: 'Checked items: '; } #txt:empty::before { color: #999; content: 'No items checked.'; }
<p id='txt'></p> <label> <input type="checkbox" class="ckb" value="1">one </label> <label> <input type="checkbox" class="ckb" value="2">two </label> <label> <input type="checkbox" class="ckb" value="3">three </label>
JS Fiddle demo.
References:
checkedValueis a Boolean representing the checked state of the first.ckbelement, and has novalueproperty. You haven't shown your attempted loop, what are you trying to do?document.querySelector('.ckb'). Also.checked gives a Boolean value