73641

Targeting the closest class in javascript

Question:

I'm just learning javascript and ran into a problem.<br /> I'm trying to target the closest class and change the value, but I just keep getting Cannot read property 'innerText' of null at HTMLUListElement.<br /> Is this not possible or is there another way I should look into?<br /> Any help or guidance is appreciated.

<div id="someId"> <h2>Test</h2> <ul> <li> <p class="amount">5

<span class="name">My Name</span> <button class="plus">Plus</button> </li> <li> <p class="amount">10

<span class="name">My Name 2</span> <button class="plus">Plus</button> </li> <li> <p class="amount">15

<span class="name">My Name 3</span> <button class="plus">Plus</button> </li> </ul>

const someList = document.querySelector('#someId ul'); someList.addEventListener('click', function(e) { if (e.target.className === 'plus') { let newValue = e.target.closest('.amount'); newValue.innerText += "5"; } });

I've changed the .amount to lots of different things, p and li > p etc but no luck.

Answer1:

.closest() goes up the dom/xpath looking at ancestors. your p.amount is a sibling, not an ancestor, so nothing is returned from your .closest()

There is no single core js method for what you want to do. jQuery offers a function called <a href="https://api.jquery.com/siblings/" rel="nofollow">.siblings()</a> which is the closest to what you are intending to do, if you want to use it. But for pure javascript, the gist is to go up the dom/xpath tree and then back down.

There are different ways you can do it, depending on what selectors you want to be "anchors". @doodlemeister 's answer is one way to do it, but IMO it is not great because it may not be as flexible as you might like. It assumes going up to the first parent and then back down to the first child. IOW it expects your html structure to be exactly as you have it now.

A more flexible way is something like this:

const someList = document.querySelector('#someId ul'); someList.addEventListener('click', function(e) { if (e.target.className === 'plus') { let newValue = e.target.closest('li').querySelector('.amount'); newValue.innerText = +newValue.innerText + 5; } });

You can then adjust the .closest() selector if needed, and you use querySelector() to go back down the dom/xpath from there and target by your originally intended class.

Answer2:

.closest looks at ancestors, and .amount is not one. You can instead go to the .parentNode and then the .firstElementChild.

And I'd personally use .matches() instead of comparing the class name for exact equality.

someList.addEventListener('click', function(e) { if (e.target.matches('.plus')) { let newValue = e.target.parentNode.firstElementChild; newValue.innerText += "5"; } });

Answer3:

In javascript you can target the parent and select the matching child

<pre class="snippet-code-js lang-js prettyprint-override">const someList = document.querySelector('#someId ul'); someList.addEventListener('click', function(e) { if (e.target.className === 'plus') { let newValue = e.target.parentNode.querySelector('.amount').innerText += "5"; } }); <pre class="snippet-code-html lang-html prettyprint-override"><div id="someId"> <h2>Test</h2> <ul> <li> <p class="amount">5

<span class="name">My Name</span> <button class="plus">Plus</button> </li> <li> <p class="amount">10

<span class="name">My Name 2</span> <button class="plus">Plus</button> </li> <li> <p class="amount">15

<span class="name">My Name 3</span> <button class="plus">Plus</button> </li> </ul> </div>

Recommend

  • Return a dictionary with keys for a given dictionary's values and vice versa
  • Google play developer console crash reports
  • PHP: strlen returns character length instead of byte length
  • Link to open email client and attach file?
  • To make the output of Markdown Pandoc table clearer
  • using := gives unused error but using = don't in Go
  • ExpressJS client-sessions don't save session
  • python package compiled with nuitka fails with segmentation fault
  • Updating price of in app purchase
  • Disabling Add to Cart Button for Specific WooCommerce Products
  • webScriptNameForSelector and javascript method with underscore
  • MVC3 globalization issue
  • Why context.Wait in StartAsync didn't stop the dialog
  • Is there way to structure a QueryExpression so that you could dynamically handle a unknown number of
  • Button On Click event not firing
  • Firebase suddenly reports invalid signature
  • jqGrid Filter Toolbar and Date and Select filters
  • Planned Contrasts on glmmTMB
  • Google Apps Script fails to generate image from EmbeddedChartBuilder
  • Laravel 5 - Cache remember doesn't work
  • SELECT on JSONField with Django
  • can you use embedded ruby in custom javascript files in rails?
  • How to modify the way a ForeignKey field is rendered in a Django admin page to avoid browser crash?
  • How to get “crispEdges” for SVG text?
  • Boolean filter using a timestamp value on a dataframe in Python
  • css: column-count 3, image floating spanning 2, chrome not playing. why?
  • view details for exception in vs 2017
  • Use AutoIt with java applications
  • LINQ to populate treeview based upon grouping
  • how to specify different css for ie
  • Ajax call on Multiple selection in Select box
  • How can i move Clearcase dyamic/snapshot views to another host (Linux)
  • VS2010 RDLC C#. How can I set a LocalReport object to a ReportViewer?
  • How to use Streams api peek() function and make it work?
  • Using redis as an LRU cache for postgres
  • Google App Engine Datastore: Dealing with eventual consistency
  • PHP Permalinks.. how to change?