disable or enable checkboxes if belong to parent class

Viewed 90

I have 2 tabs with a list of checkboxes. I'd like to create dependent checkboxes so if the user will select a checkbox in the first tab then it will disable all checkboxes in tab 2 that don't belong to the checkbox in tab 1.

Both client_list and business_challange are the filters for my products and they are connected in relation ManyToMany with the Product model (models with view below).

html file

<div class="container">

  <ul class="nav nav-tabs flex-row f-12 mb-3" id="myTab" role="tablist">
    <li class="nav-item" role="presentation">
      <button class="nav-link active" id="client-list-tab" data-bs-toggle="tab" data-bs-target="#client_list" type="button" role="tab" aria-controls="client_list" aria-selected="true">Client</button>
    </li>
    
    <li class="nav-item" role="presentation">
      <button class="nav-link" id="business-challange-tab" data-bs-toggle="tab" data-bs-target="#business_challange" type="button" role="tab" aria-controls="business_challange" aria-selected="false">Challanges</button>
    </li>
  </ul>

  <div class="tab-content filters" id="myTabContent">

    <div class="tab-pane fade show active" id="client_list" role="tabpanel" aria-labelledby="client-list-tab">
      <div class="parent-checkbox">
        {% for object in client_list %}
          <div class="form-check">
            <input class="form-check-input" type="checkbox" value="{{object.title}}" id="{{object.title}}" data-filter="client_list" name="showCb" onclick="showMe('uncheck-all')">
            <label class="form-check-label ps-2" for="{{object.title}}">
                {{object.title}}
            </label>
          </div>
        {% endfor %}
      </div>
    </div>
    
    <div class="tab-pane fade" id="business_challange" role="tabpanel" aria-labelledby="business-challange-tab">
      <div class="child-checkbox">
        {% for object in business_challange %}
          <div class="form-check">
            <input class="form-check-input" type="checkbox" value="{{object.title}}" id="{{object.title}}" data-filter="business_challange" name="showCb" onclick="showMe('uncheck-all')">
            <label class="form-check-label ps-2" for="{{object.title}}">
                {{object.title}}
            </label>
          </div>
        {% endfor %}
      </div>
    </div>

  </div>
</div>

</div>

js file

$(document).on('click',
  '.parent-checkbox input[type=checkbox]',
  function(event) {

    // If parent-checkbox is checked add 
    // disabled attributes to its child
    if ($(this).is(":checked")) {
      $(this).closest(".container").
      find(".child-checkbox .form-check > input[type=checkbox]").
      attr("disabled", false);
    } else {

      // Else add disabled attrubutes to its 
      // all child checkboxes  
      $(this).closest(".container").
      find(".child-checkbox .form-check > input[type=checkbox]").
      attr("disabled", true);
    }
  }
);

models.py

class Client(models.Model):
    title = models.CharField(max_length=100, default='')
    short_description = models.CharField(max_length=250, default='')

class BusinessChallange(models.Model):
    title = models.CharField(max_length=150, default='-')

class Product(models.Model):
    title = models.CharField(max_length=400, default='')
    business_challange = models.ManyToManyField(BusinessChallange, related_name='business_challange_product', blank=True, default='-')
    client = models.ManyToManyField(Client, blank=True)
    status = models.IntegerField(choices=STATUS, default=0)

views.py

class GuidedSearch(LoginRequiredMixin, ListView):
    login_url = 'login'
    redirect_field_name = 'login'
    template_name = 'product_filters.html'
    model = Product
    queryset = Product.objects.all()

    def get_context_data(self, **kwargs):
        context = super(GuidedSearch, self).get_context_data(**kwargs)
        client_list = Client.objects.filter(product__status=1)
        business_challange = BusinessChallange.objects.filter(product__status=1)

        context['client_list'] = client_list
        context['business_challange'] = business_challange
        return context
1 Answers

First: your description and your JS code (and its comments) differ. I assume that the description is correct, because it makes more sense to me to disable the other checkboxes.


If you only want to disable the child checkboxes that belong to the selected parent checkbox you need to mark them appropriate (maybe with a data attribute, for example: data-class). Then you could select all child checkboxes that don't have this marker with the :not() selector.

Working example: (simplified for demonstration)

$(document).on('click',
  '.parent-checkbox input[type=checkbox]',
  function() {

    if ($(this).is(":checked")) {
      const data_class = $(this).data('class');
      
      $(this).closest(".container").
      find('.child-checkbox .form-check > input[type=checkbox]:not([data-class="' + data_class + '"])').
      attr("disabled", true);
    } else {

      const data_class = $(this).data('class');
      
      $(this).closest(".container").
      find('.child-checkbox .form-check > input[type=checkbox]').
      attr("disabled", false);
    }
  }
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="container">

  <div class="parent-checkbox">
    <p>parents</p>
    
    <div class="form-check">
      <input data-class="A" type="checkbox" value="A1" id="A1" name="A1">
      <label for="A1">A</label>
    </div>

    <div class="form-check">
      <input data-class="B" type="checkbox" value="B1" id="B1" name="B1">
      <label for="B1">B</label>
    </div>
  </div>

  <hr>

  <div class="child-checkbox">
    <p>children</p>
    
    <div class="form-check">
      <input data-class="A" type="checkbox" value="A2" id="A2" name="A2">
      <label for="A2">A</label>
    </div>

    <div class="form-check">
      <input data-class="B" type="checkbox" value="B2" id="B2" name="B2">
      <label for="B2">B</label>
    </div>
  </div>

</div>

Related