3

I've searched a while for this, but can't find a solution. Basically, I have a simple form, that will by dynamic (up to 20 cycles can exist for an ID). The validation to delete the Cycles, say that there are 3 of them, 1, 2, and 3, is that you can delete #3, but you cannot delete #2 until you delete #3, and you cannot delete #1 until you delete #2.

So, on the front-end, I was thinking of a design that would disable all but the last checkbox, then as you check the last checkbox, the next previous checkbox would be enabled and be able to be checked, and so on. Then, the user would delete (through a Bootbox modal submit button callback, which is even a bit trickier).

Here's a simple form I was using to test with:

 <form class="form-horizontal" id="deleteCycles" action="/deleteCyclesScript" method="post">
<div class="col-md-12" style="margin-top: 30px; margin-bottom: 10px;">
    <div class="checkbox"><label><input id="cycle1" type="checkbox" value="cycle1" class="dynamicCheckboxes">Cycle 1</label></div>
    <div class="checkbox"><label><input id="cycle2" type="checkbox" value="cycle2" class="dynamicCheckboxes">Cycle 2</label></div>
    <div class="checkbox"><label><input id="cycle3" type="checkbox" value="cycle3" class="dynamicCheckboxes">Cycle 3</label></div>
</div>
</form>

How can you dynamically write JavaScript (I'm using jQuery 1.12.4) to achieve this? I'm hoping to have something in the ID's that can almost make a chain of enabling the checkboxes -- the last one being enabled by default since it's not dependent on others to be deleted, but, then enabling the other checkboxes on the fly as the one above it is enabled.

Can anyone help with this?

Thanks so much!

kukkuz
  • 41,512
  • 6
  • 59
  • 95
gamehendgeVA
  • 149
  • 1
  • 3
  • 15
  • If the identifiers are guaranteed to be sequential, you could probably add a data-attribute, say `data-dependsOn`, with the antecedent's ID, and check if the matching checkbox is checked. – Tieson T. Dec 07 '16 at 02:31
  • Wow, that's a very interesting idea. I'm very new to all of this, is there any way you can help with a script? – gamehendgeVA Dec 07 '16 at 02:34

3 Answers3

1

So you can do this using jquery:

  1. Initially set all but the last checkbox disabled

  2. Use a checkbox listener that will:

    a. enable the preceeding checkbox on ticking

    b. disable all preceeding checkbox when unticking

See demo below:

// Initialize : disable all but the last checkbox
$('#deleteCycles .checkbox:last').prevAll().each(function() {
  $(this).find('input').attr('disabled', 'disabled');
});

// checbox listener
$('#deleteCycles .checkbox input').change(function() {
  if ($(this).is(":checked")) {
    // enable the checkbox just above
    $(this).closest('.checkbox').prev('.checkbox').find('input').removeAttr('disabled');
  } else {
    // disable all checkboxes preceeding
    $(this).closest('.checkbox').prevAll().each(function() {
      $(this).find('input').attr({
        'disabled': 'disabled',
        'checked': false
      });
    });
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />

<form class="form-horizontal" id="deleteCycles" action="/deleteCyclesScript" method="post">
  <div class="col-md-12" style="margin-top: 30px; margin-bottom: 10px;">
    <div class="checkbox">
      <label>
        <input id="cycle1" type="checkbox" value="cycle1" class="dynamicCheckboxes">Cycle 1</label>
    </div>
    <div class="checkbox">
      <label>
        <input id="cycle2" type="checkbox" value="cycle2" class="dynamicCheckboxes">Cycle 2</label>
    </div>
    <div class="checkbox">
      <label>
        <input id="cycle3" type="checkbox" value="cycle3" class="dynamicCheckboxes">Cycle 3</label>
    </div>
  </div>
</form>
kukkuz
  • 41,512
  • 6
  • 59
  • 95
  • 1
    wow, this is EXACTLY what I was thinking of, thank you so much! I'll read up on prevAll now, this awesome. Again, much thanks! – gamehendgeVA Dec 07 '16 at 02:59
  • shouldn't disabled be a property vs using attr()? – Anthony C Dec 07 '16 at 03:00
  • @AnthonyC you are right, its better to use prop()... thanks for the heads up :) – kukkuz Dec 07 '16 at 03:09
  • Thank you both, so can I just change the .attr.('disabled', 'disabled') to .prop( "checked", false ) ? (Sorry, I'm also trying to find out how everyone is making these "Run Code Snippet" windows). Is attr deprecated or something? – gamehendgeVA Dec 07 '16 at 03:16
  • no, `prop` is recommended when we set a *property* like `checked`, `disabled` etc (affects the DOM), while `attr` should be used for *attributes* like `id`,`class` etc... – kukkuz Dec 07 '16 at 03:18
  • So, it's really as simple as just changing attr to prop, right. I just did a fiddle here: https://jsfiddle.net/gamehendgeVA/654cwmbp/2/ (and, how do you get the run code snippet to work, even in comments?) Thanks for that tip about prop vs attr, very good to know! – gamehendgeVA Dec 07 '16 at 03:27
1

        $(function () {
            $(':checkbox').attr('disabled', true).each(function (index, element) {
                $(this).data('index', index);
            }).change(function () {
                if($(this).is(':checked'))
                {
                    $(this).parents('.checkbox:first').prev().find(':checkbox').attr('disabled', null);
                }
                else
                {
                    $(this).parents('form:first').find(':checkbox:lt(' + $(this).data('index') + ')').attr('checked', false).attr('disabled', true);
                }
            }).last().attr('disabled', null);
        });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<form class="form-horizontal" id="deleteCycles" action="/deleteCyclesScript" method="post">
        <div class="col-md-12" style="margin-top: 30px; margin-bottom: 10px;">
            <div class="checkbox"><label><input id="cycle1" type="checkbox" value="cycle1" class="dynamicCheckboxes">Cycle 1</label></div>
            <div class="checkbox"><label><input id="cycle2" type="checkbox" value="cycle2" class="dynamicCheckboxes">Cycle 2</label></div>
            <div class="checkbox"><label><input id="cycle3" type="checkbox" value="cycle3" class="dynamicCheckboxes">Cycle 3</label></div>
        </div>
    </form>
Bob Dust
  • 2,370
  • 1
  • 17
  • 13
1

Assuming sequential IDs, something like this might work.

Add a data-attribute that lets you reference the checkbox that the currently-active checkbox "depends on":

<form class="form-horizontal" id="deleteCycles" action="/deleteCyclesScript" method="post">
    <div class="col-md-12" style="margin-top: 30px; margin-bottom: 10px;">
        <div class="checkbox">
            <label>
                <input id="cycle1" type="checkbox" value="cycle1" class="dynamicCheckboxes" />
                Cycle 1
            </label>
        </div>
        <div class="checkbox">
            <label>
                <input id="cycle2" type="checkbox" value="cycle2" class="dynamicCheckboxes" data-dependsOn="#cycle1" />
                Cycle 2
            </label>
        </div>
        <div class="checkbox">
            <label>
                <input id="cycle3" type="checkbox" value="cycle3" class="dynamicCheckboxes" data-dependsOn="#cycle2" />
                Cycle 3
            </label>
        </div>
    </div>
</form>

Then, when the checkbox is toggled, check both it's checkstate and the "depends on" checkbox's checkstate:

$('.dynamicCheckboxes').on('change', function(e){
    // hold reference to the current checkbox
    var _this = $(this);

    if(!_this.is(':checked')){  
        var dependsOn = _this.data('dependsOn');
        if(dependsOn != ""){
            if($(dependsOn).is(':checked')){
                e.preventDefault();

                // display some sort of error message
            }   
        }   
    }
});

You could use the jQuery .prev function, as well, if your markup supports it (if the dependent checkbox always precedes the checkbox you're checking, in the markup).

Tieson T.
  • 20,774
  • 6
  • 77
  • 92