lewis4u
lewis4u

Reputation: 15047

Reference ID using a Class suffix integer

Situation:

There are many checkboxes, this is only a small part of a tree:

<li class="main">
    <input type="checkbox" id="cat_6" class="parent_cat_0" name="local[]">
    <label class="strong" for="cat_6">Stellenbeschreibungen</label>
    <ul>
        <li class="main">
            <input type="checkbox" id="doc_31" class="parent_cat_6" name="local[]">
            <label for="doc_31">Stellenbeschreibung Marketing/Vertrieb</label>
        </li>
    </ul>
</li>

I want to make a selector for parent of this checkbox that has class "parent_cat_6"

So the final selector should be:

let parent = $('#cat_6');

But I don't know how to cut off the 'parent_' out of checked checkbox class.

child has class="parent_cat_6"
parent has id="cat_6"

Do I need to use regex to make selector for the parent or there is another way?

UPDATE: This works:

selected.attr('class').split(' ').slice(-1)[0].substr(7);

But it's ugly, any improvements are welcome!

Upvotes: 1

Views: 41

Answers (1)

Roko C. Buljan
Roko C. Buljan

Reputation: 206121

Suffixed or prefixed ClassNames are not the best when you have to deal with references in JavaScript.

Crazy selector

Just to target such suffixed class - the selector gets complicated:

[class^="parent_cat_"], [class*=" parent_cat_"]

you would better go using two classes in such case, one that is common to all your elements, and the specific one: class="cat_checkbox parent_cat_42". That way the selector becomes as simple as

.cat_checkbox   // BETTER - Common class for all checkboxes

Too much work to extract the suffix Integer

The problem is that a className can house many names, and to find the desired one might be tricky.
How to get 42 out of class="foo bar fooBar parent_cat_42 bla_bli_40" ?

  • Read the entire classList
  • Find the one that matches this format parent_cat_\d+
  • Retrieve it's index
  • Extract it
  • Get the digits
  • Finally transform it to some ID #cat_[ID]

const findIndex_parent_cat = klass => /^parent_cat_\d+$/.test(klass);
const findNum_parent_cat = klass => klass.replace(/\D+/, '');


$('[class^="parent_cat_"], [class*=" parent_cat_"]').on('change', function() {
  const klasses = $(this).attr('class');
  const ID = klasses.match(/(?:^|\s)parent_cat_(\d+)(?:$|\s)/)[1];
  const cat_ID = `#cat_${ID}`;
  console.log(`ID: ${cat_ID}`);
  $(cat_ID).prop({checked: this.checked});
});
<ul>
  <li class="main">
    <input type="checkbox" id="cat_6" class="something parent_cat_0 bla" name="local[]">
    <label class="strong" for="cat_6">Stellenbeschreibungen</label>
    <ul>
      <li class="main">
        <input type="checkbox" id="doc_31" class="blue red inp parent_cat_6 foo bar" name="local[]">
        <label for="doc_31">Stellenbeschreibung Marketing/Vertrieb</label>
      </li>
    </ul>
  </li>
</ul>

<script src="//code.jquery.com/jquery-3.4.1.min.js"></script>

Get class suffix Integer by using Regex

or it can be done by using Regex (?:^|\s)parent_cat_(\d+)(?:$|\s) :

const findIndex_parent_cat = klass => /^parent_cat_\d+$/.test(klass);
const findNum_parent_cat = klass => klass.replace(/\D+/, '');


$('[class^="parent_cat_"], [class*=" parent_cat_"]').on('change', function() {
  const klasses = [...this.classList];
  const klassIndex = klasses.findIndex(findIndex_parent_cat); // Get index
  const klass = klasses[klassIndex]; // Find it in classList
  const ID = findNum_parent_cat(klass); // Now let's extract the N number ID
  const cat_ID = `#cat_${ID}`; // Finally we have the ID...
  
  console.log(`${klass} found in classList at index ${klassIndex}. ID: ${cat_ID}`);
  
  $(cat_ID).prop({checked: this.checked});
});
<ul>
  <li class="main">
    <input type="checkbox" id="cat_6" class="something parent_cat_0 bla" name="local[]">
    <label class="strong" for="cat_6">Stellenbeschreibungen</label>
    <ul>
      <li class="main">
        <input type="checkbox" id="doc_31" class="blue red inp parent_cat_6 foo bar" name="local[]">
        <label for="doc_31">Stellenbeschreibung Marketing/Vertrieb</label>
      </li>
    </ul>
  </li>
</ul>

<script src="//code.jquery.com/jquery-3.4.1.min.js"></script>

Use data-* attribute instead!

Exactly, here's a remake of the above madness.
And yeah, see HTML how to use the <label> without the for attribute:

$('[data-cat]').on('change', function() {

  const cat_ID = $(this).attr('data-cat'); // Finally we have the ID...
  console.log(`ID: ${cat_ID}`);
  
  $(cat_ID).prop({checked: this.checked});
});
<ul>
  <li class="main">
    <label>
      <input type="checkbox" id="cat_6" data-cat="#cat_0" name="local[]">
      Stellenbeschreibungen
    </label>
    <ul>
      <li class="main">
        <label>
          <input type="checkbox" id="doc_31" data-cat="#cat_6" name="local[]">
          Stellenbeschreibung Marketing/Vertrieb
        </label>
      </li>
    </ul>
  </li>
</ul>

<script src="//code.jquery.com/jquery-3.4.1.min.js"></script>

Upvotes: 1

Related Questions