Emrah Şentürk
Emrah Şentürk

Reputation: 107

when check a checkbox, unchecked other with javascript

I fill the table with a ADODB.Recordset. I have 25 rows. But it can change. And last column is checkboxes.

enter image description here

Only one checkbox can select. Check one and uncheck others automatic.

<input class="cb" id="txtdurum_<%=counter%>" name="txtdurum" type="checkbox" />

Help please :)

Upvotes: 0

Views: 3101

Answers (3)

David Thomas
David Thomas

Reputation: 253308

While I would – strongly – recommend that you use <input> elements of type="radio" (with a 'choose nothing' option, if that's required), I was intrigued enough to spend the last few hours putting together this approach.

This is one way of doing it, it feels little over-the-top and it's not quite as streamlined as I'd like, but it does suffice to meet your requirements. I've provided a simple demo for the introduction, and the JavaScript is commented throughout:

var Limit = (function () {
    // private to this function, but shared by all instances:

    // simple 'closest' function;
    // start: DOM Node,
    // needle: String, the tagName of the ancestor to find.

    // if no ancestor exists (we stop at the <body> element)
    // function returns null:
    var closest = function (start, needle) {
        // we begin at the 'start' node, but use
        // the 'current' variable as a pointer as
        // we move through the ancestors:
        var current = start,

            // converting the tagName to lower-case,
            // for predictable comparisons:
            find = needle.toLowerCase();

        // while the tagName of the current element-node is not
        // what we're looking for AND the current element-node is
        // not the <body> element:
        while (current.tagName.toLowerCase() !== find && current.tagName.toLowerCase() !== 'body') {
            // we set the current node to its parentNode,
            // thereby ascending through the DOM:
            current = current.parentNode;
        }

        // if the tagName of the current element-node is 'body'
        // we return null, otherwise we return that current node:
        return current.tagName.toLowerCase() === 'body' ? null : current;
    };

    return function (groupSelector) {
        // protected variables, available on a
        // per-instance basis:

        // the array in which we'll hold the selected
        // <input> elements as they're checked:
        var checked = [],

            // the group of elements to which this instance
            // will apply:
            group = document.querySelectorAll(groupSelector),

            // the defaults:
            // allowInvalidity, Boolean:
            //    true:  allows the user to select more than
            //           the maximum number of choices.
            //    false: prevents the selection of options
            //           beyond the maxumum number.
            // fifo, Boolean:
            //    true:  should the user try to select more
            //           than the maximum number of choices
            //           the first element in the array is
            //           removed.
            //    false: should the user try to select more
            //           than the maximum number of choices
            //           subsequent choices are prevented.
            // maxChoices, Number:
            //           defines the maximum number of choices
            //           that can be made.
            // parentErrorClass, String:
            //           the class-name to be applied to the
            //           parent of the <input> elements when
            //           the user chooses more than the maximum
            //           number of options (requires
            //           settings.invalidity to be true).

            defaults = {
                'allowInvalidity': false,
                    'fifo': true,
                    'maxChoices': 1,
                    'parentErrorClass': 'error'
            };

        // the object containing the function(s) we
        // make available:
        return {

            // opts is the user-defined settings
            // passed in:
            'nOnly': function (opts) {

                // a simple, though potentially costly,
                // means of avoiding JavaScript's
                // pass-by-reference (which prevents
                // settings = dafaults from working),
                // here creating a copy via the JSON functions:
                var settings = JSON.parse(JSON.stringify(defaults));

                // iterating over the user-defined settings in the
                // supplied opts object:
                for (var setting in opts) {

                    // avoiding iterating over inherited properties
                    // from the Object.prototype:
                    if (opts.hasOwnProperty(setting)) {

                        // setting the settings options to
                        // those supplied in the opts object:
                        settings[setting] = opts[setting];
                    }
                }

                // iterating over the Array-like NodeList returned by
                // document.querySelectorAll() (when we retrieved the
                // nodes for this 'group'), using Function.prototype.call()
                // to apply Array.prototype.forEach():
                Array.prototype.forEach.call(group, function (input) {
                    // there are three arguments available to
                    // Array.prototype.forEach(), the names are
                    // user-defined (within variable-naming constraints);
                    // the first (here: 'input') the current array-element
                    // from the array over which we're iterating,
                    // the second (not used) is the index of that array-element,
                    // the third (not used) is the full array over which
                    // we iterate.

                    // here we bind the anonymous function as the 'change'
                    // event-handler on each of the <input> elements in
                    // the parent group:
                    input.addEventListener('change', function (event) {

                        if (input.checked && settings.allowInvalidity === false) {
                            // add the <input> to the checked array:
                            checked.push(input);

                            // if too many choices have been made:
                            if (checked.length > settings.maxChoices) {

                                // we call Array.prototype.pop() (if
                                // settings.fifo is true) or
                                // Array.prototype.shift() (if
                                // settings.fifo is not exactly-true)
                                // to select the first element of the
                                // checked Array (shift()) or the last
                                // element (pop()) and set that element's
                                // checked property to false. Using shift()
                                // or pop() also removes it from the array:
                                checked[settings.fifo === true ? 'shift' : 'pop']().checked = false;
                            }

                        } else if (input.checked && settings.allowInvalidity === true) {
                            // we simply add the <input> to the array:
                            checked.push(input)
                        } else {

                            // we test that the <input> element is in
                            // the checked Array:
                            if (checked.indexOf(input) > -1) {

                                // using Array.prototype.splice() to
                                // remove it from the Array; using
                                // Array.prototype.indexOf() (again) 
                                // to retrieve its index in the Array:
                                checked.splice(checked.indexOf(input), 1);
                            }
                        }

                        // iterating over the group, with Array.prototype.forEach():
                        Array.prototype.forEach.call(group, function (input) {

                            // if the <input> is not checked, or the number of choices
                            // is less than the permitted maximum:
                            if (!input.checked || checked.length <= settings.maxChoices) {

                                // we remove the parentErrorClass from the parentNode:
                                input.parentNode.classList.remove(settings.parentErrorClass);

                                // otherwise if the <input> is checked, AND
                                // there are too many choices:
                            } else if (input.checked && checked.length > settings.maxChoices) {

                                // we add the parentErrorClass to the parentNode:
                                input.parentNode.classList.add(settings.parentErrorClass);
                            }
                        });

                    });
                });
            }
        };
    };
})();

new Limit('.group1 input').nOnly({
    'allowInvalidity': true,
        'maxChoices': 3
});
new Limit('.group2 input').nOnly({
    'maxChoices': 1,
        'fifo': false
});
new Limit('.group3 input').nOnly({
    'allowInvalidity': true,
    'maxChoices' : 2,
    'parentErrorClass' : 'oops'
});

var Limit = (function() {
  var closest = function(start, needle) {
    var current = start,
      find = needle.toLowerCase();
    while (current.tagName.toLowerCase() !== find && current.tagName.toLowerCase() !== 'body') {
      current = current.parentNode;
    }
    return current.tagName.toLowerCase() === 'body' ? null : current;
  };

  return function(groupSelector) {
    var checked = [],
      group = document.querySelectorAll(groupSelector),
      defaults = {
        'allowInvalidity': false,
        'fifo': true,
        'maxChoices': 1,
        'parentErrorClass': 'error'
      };
    return {
      'nOnly': function(opts) {
        var settings = JSON.parse(JSON.stringify(defaults));
        for (var setting in opts) {
          if (opts.hasOwnProperty(setting)) {
            settings[setting] = opts[setting];
          }
        }
        Array.prototype.forEach.call(group, function(input) {
          input.addEventListener('change', function(event) {

            if (input.checked && settings.allowInvalidity === false) {

              checked.push(input);
              if (checked.length > settings.maxChoices) {
                checked[settings.fifo === true ? 'shift' : 'pop']().checked = false;
              }

            } else if (input.checked && settings.allowInvalidity === true) {
              checked.push(input)
            } else {
              if (checked.indexOf(input) > -1) {
                checked.splice(checked.indexOf(input), 1);
              }
            }
            Array.prototype.forEach.call(group, function(input) {
              if (!input.checked || checked.length <= settings.maxChoices) {
                input.parentNode.classList.remove(settings.parentErrorClass);
              } else if (input.checked && checked.length > settings.maxChoices) {
                input.parentNode.classList.add(settings.parentErrorClass);
              }
            });

          });
        });
      }
    };
  };
})();

new Limit('.group1 input').nOnly({
  'allowInvalidity': true,
  'maxChoices': 3
});
new Limit('.group2 input').nOnly({
  'maxChoices': 1,
  'fifo': false
});
new Limit('.group3 input').nOnly({
  'allowInvalidity': true,
  'maxChoices': 2,
  'parentErrorClass': 'oops'
});
form {
  -moz-column-count: 3;
  -webkit-column-count: 3;
  column-count: 3;
  -moz-break-inside: avoid-column;
  -webkit-break-inside: avoid-column;
  break-inside: avoid-column;
}
label {
  display: block;
  border: 2px solid transparent;
  transition: all 0.5s linear;
}
.error {
  border: 2px solid #f00;
}
.oops {
  background-color: #f90;
}
<form action="#" method="post">
  <fieldset>
    <legend>Group 1</legend>
    <label class="group1">input 1
      <input type="checkbox" />
    </label>
    <label class="group1">input 2
      <input type="checkbox" />
    </label>
    <label class="group1">input 3
      <input type="checkbox" />
    </label>
    <label class="group1">input 4
      <input type="checkbox" />
    </label>
    <label class="group1">input 5
      <input type="checkbox" />
    </label>
  </fieldset>
  <fieldset>
    <legend>Group 2</legend>
    <label class="group2">input 1
      <input type="checkbox" />
    </label>
    <label class="group2">input 2
      <input type="checkbox" />
    </label>
    <label class="group2">input 3
      <input type="checkbox" />
    </label>
    <label class="group2">input 4
      <input type="checkbox" />
    </label>
    <label class="group2">input 5
      <input type="checkbox" />
    </label>
  </fieldset>
  <fieldset>
    <legend>Group 3</legend>
    <label class="group3">input 1
      <input type="checkbox" />
    </label>
    <label class="group3">input 2
      <input type="checkbox" />
    </label>
    <label class="group3">input 3
      <input type="checkbox" />
    </label>
    <label class="group3">input 4
      <input type="checkbox" />
    </label>
    <label class="group3">input 5
      <input type="checkbox" />
    </label>
  </fieldset>
</form>

External JS Fiddle demo, for experimentation.

To apply this to your own situation, the function can be called like so:

// here, the only difference is the CSS selector
// passed to the Constructor:
new Limit('table input[type=checkbox]').nOnly({
    'maxChoices': 1
});

var Limit = (function() {
  var closest = function(start, needle) {
    var current = start,
      find = needle.toLowerCase();
    while (current.tagName.toLowerCase() !== find && current.tagName.toLowerCase() !== 'body') {
      current = current.parentNode;
    }
    return current.tagName.toLowerCase() === 'body' ? null : current;
  };

  return function(groupSelector) {
    var checked = [],
      group = document.querySelectorAll(groupSelector),
      defaults = {
        'allowInvalidity': false,
        'fifo': true,
        'maxChoices': 1,
        'parentErrorClass': 'error'
      };
    return {
      'nOnly': function(opts) {
        var settings = JSON.parse(JSON.stringify(defaults));
        for (var setting in opts) {
          if (opts.hasOwnProperty(setting)) {
            settings[setting] = opts[setting];
          }
        }
        Array.prototype.forEach.call(group, function(input) {
          input.addEventListener('change', function(event) {

            if (input.checked && settings.allowInvalidity === false) {

              checked.push(input);
              if (checked.length > settings.maxChoices) {
                checked[settings.fifo === true ? 'shift' : 'pop']().checked = false;
              }

            } else if (input.checked && settings.allowInvalidity === true) {
              checked.push(input)
            } else {
              if (checked.indexOf(input) > -1) {
                checked.splice(checked.indexOf(input), 1);
              }
            }
            Array.prototype.forEach.call(group, function(input) {
              if (!input.checked || checked.length <= settings.maxChoices) {
                input.parentNode.classList.remove(settings.parentErrorClass);
              } else if (input.checked && checked.length > settings.maxChoices) {
                input.parentNode.classList.add(settings.parentErrorClass);
              }
            });

          });
        });
      }
    };
  };
})();

new Limit('table input[type=checkbox]').nOnly({
  'maxChoices': 1
});
<table>
  <tr>
    <td>row 1</td>
    <td>
      <input type="checkbox" />
    </td>
  </tr>
  <tr>
    <td>row 2</td>
    <td>
      <input type="checkbox" />
    </td>
  </tr>
  <tr>
    <td>row 3</td>
    <td>
      <input type="checkbox" />
    </td>
  </tr>
  <tr>
    <td>row 4</td>
    <td>
      <input type="checkbox" />
    </td>
  </tr>
  <tr>
    <td>row 5</td>
    <td>
      <input type="checkbox" />
    </td>
  </tr>
  <tr>
    <td>row 6</td>
    <td>
      <input type="checkbox" />
    </td>
  </tr>
  <tr>
    <td>row 7</td>
    <td>
      <input type="checkbox" />
    </td>
  </tr>
  <tr>
    <td>row 8</td>
    <td>
      <input type="checkbox" />
    </td>
  </tr>
  <tr>
    <td>row 9</td>
    <td>
      <input type="checkbox" />
    </td>
  </tr>
  <tr>
    <td>row 10</td>
    <td>
      <input type="checkbox" />
    </td>
  </tr>
</table>

External JS Fiddle demo, for experimentation.

This is, obviously, a representative demonstration since you neglected to provide the relevant (mcve) HTML, however since it relies only on an appropriate selector it should be easily applicable to your situation.

References:

Upvotes: 0

Jan M&#246;ller
Jan M&#246;ller

Reputation: 321

You can use jQuery:

$('.cb').change(function(){
   $('.cb').prop('checked',false);
   $(this).prop('checked',true); 
});

This adds a change-listener to all checkboxes with the "cb" class-Attribute. Place that code-fragment into the jquery-ready-function.

Example: JSFiddle

UPDATE1: If you also want to enable, that the user can uncheck all:

$('.cb').change(function(){
    var checkState = $(this).prop('checked');
    $('.cb').prop('checked',false);
    $(this).prop('checked', checkState);
});

Example: JSFiddle2

But: better use radiobuttons

Upvotes: 1

Zee
Zee

Reputation: 8488

Try this code. Add an onchange event to each input checkbox.

<input class="cb" id="txtdurum_<%=counter%>" name="txtdurum" type="checkbox" onchange="check(this)"/>

JS:

function check(element){
    if(element.checked){
      var checkboxes = document.getElementsByClassName('cb');
        for(var i=0;i<checkboxes.length;i++){
           if(checkboxes[i]!=element)
             checkboxes[i].checked = false;
        }
    }
}

Example Fiddle.

Upvotes: 1

Related Questions