首页 > 解决方案 > How to create a html/javascript table that automatically selects radiobuttons?

问题描述

I have only very basic html/javascript understanding.

I am trying to make what is probably only a slight modification to an existing code. Below is, first the original code, and then how I'd like to change it.

Original code: A table gives the user a choice between left and right for several rows. The table enforces at most a single switch point from left to right going down the table, meaning that if the user chooses right at some row, the table automatically selects right for all rows below, and if the user chooses left at a given row, the table automatically selects left for all rows above. No switch point at all is allowed (meaning left is selected for all rows, or right is selected for all rows). A selection is required for each row (the app checks for this by default already).

{{ block content }}

    <table class="table table-striped">
        <colgroup>
            <col width="45%">
            <col width="10%">
            <col width="45%">
        </colgroup>
        <tr>
            <td align="right"><b>Option A</b></td>
            <td></td>
            <td align="left"><b>Option B</b></td>
        </tr>
        {{ for amount in player.right_side_amounts }}
            <tr>
                <td align="right">
                    <b>{{ player.left_side_amount }}</b> now
                <td align="middle">
                    <input type="radio"
                           value="left"
                           name="{{ amount|json }}"
                           required>&nbsp;&nbsp;
                    <input type="radio"
                           name="{{ amount|json }}"
                           value="right" data-amount="{{ amount|json }}"
                           required>
                </td>
                <td align="left">
                    <b>{{ amount }} </b> next month
            </tr>
        {{ endfor }}
    </table>

    {{ formfield_errors 'switching_point' }}
    <input type="hidden" name="switching_point" id="id_switching_point"
           value="9999">

    {{ next_button }}

{{ endblock }}


{{ block scripts }}
    <script>
        $(document).ready(function () {
            $('input[type=radio]').change(
                function () {
                    var clickedRadio = this;
                    var afterClickedRadio = false;


                    var radios = document.querySelectorAll('input[type=radio]');
                    for (i = 0; i < radios.length; ++i) {
                        var radio = radios[i];
                        if (radio === clickedRadio) {
                            afterClickedRadio = true;
                            continue;
                        }
                        if (!afterClickedRadio && clickedRadio.value === 'left' && radio.value === 'left') {
                            radio.checked = true;
                        }
                        if (afterClickedRadio && clickedRadio.value === 'right' && radio.value === 'right') {
                            radio.checked = true;
                        }
                    }
                }
            );

            $('.otree-btn-next').click(function () {
                var radios = document.querySelectorAll('input[type=radio]');


                for (i = 0; i < radios.length; ++i) {
                    var radio = radios[i];
                    if (radio.value === 'right' && radio.checked) {
                        $('#id_switching_point').val(radio.dataset.amount);
                        break;
                    } else {
                        $('#id_switching_point').val(9999);
                    }
                }
            });
        });
    </script>

{{ endblock }}

This is how the original table looks: original table

Modification: Just as in the original, I'd like to have the table with a left/right choice, and enforce at most a single switch point. But, I'd like user to have the possibility to express indifference between the left and right choice at the switch point.

In other words, at the row the user chooses to switch from option A to option B, he could choose either "I prefer B" or "I am exactly indifferent between A and B".

I envision a table with three radio buttons per row, where the center button means “I am indifferent”. At whichever row the user chooses to switch ($17 in this image: what I envision) the user could select either the center button (which would express exact indifference) or the right button (which would express preference for option B). Regardless of whether the user chooses center or right button, all rows above would get checked for A, and all rows below would get checked for B. The center button can be selected at most once, since all rows below would be automatically selected right, and all rows above would be automatically selected left.

I think a second variable would need to be created relative to the original code, to record not just the switching point, but also whether the switching point occurred with indifference or strict preference.

Thank you so much for any help.

标签: javascripthtmlcss

解决方案


这个怎么样?如果我理解正确,那么规则是:

  1. 选择 A 检查所有 A 输入
  2. 选择 B 检查所有 B 输入
  3. 选择 X 将使 X 选择下方的所有输入与第一个选中的输入相反,并且 X 选择上方的所有内容都默认为第一个选中的输入选择。(如果是 A,那么在 X 之后是 B。如果是 B,那么在 X 之后是 A)
  4. 防止选择多个X。如果超过X,以最后选中的X为准,前一个X根据规则3变化。

除了这些规则之外,我还禁用了第一个和最后一个中间输入,因为您没有说明如果检查第一个或最后一个中间输入会发生什么。此外,我添加了逻辑,以防止用户在选择其他任何内容之前检查任何中间输入,因为您也没有说明在那种情况下会发生什么。

有一些我没有编写代码的极端情况,但这足以涵盖您的规则。

https://jsfiddle.net/j1vas2x8/

<table>
  <tr>
    <th>A</th>
    <th>X</th>
    <th>B</th>
  </tr>
  <tr>
    <td><input type="radio" name="r1[]" value="A"></td>
    <!-- if the first middle selection is not disabled, then which column is the opposite of it? -->
    <td><input type="radio" name="r1[]" value="X" disabled="disabled"></td>
    <td><input type="radio" name="r1[]" value="B"></td>
  </tr>
  <tr>
    <td><input type="radio" name="r2[]" value="A"></td>
    <td><input type="radio" name="r2[]" value="X"></td>
    <td><input type="radio" name="r2[]" value="B"></td>
  </tr>
  <tr>
    <td><input type="radio" name="r3[]" value="A"></td>
    <td><input type="radio" name="r3[]" value="X"></td>
    <td><input type="radio" name="r3[]" value="B"></td>
  </tr>
  <tr>
    <td><input type="radio" name="r4[]" value="A"></td>
    <td><input type="radio" name="r4[]" value="X"></td>
    <td><input type="radio" name="r4[]" value="B"></td>
  </tr>
  <tr>
    <td><input type="radio" name="r5[]" value="A"></td>
    <!-- if the last middle selection is not disabled, then what should should happen if it's selected last? -->
    <td><input type="radio" name="r5[]" value="X" disabled="disabled"></td>
    <td><input type="radio" name="r5[]" value="B"></td>
  </tr>
</table>
var header_row = document.querySelectorAll('table tr th');
var column = {
  'left': header_row[0].innerText,
  'middle': header_row[1].innerText,
  'right': header_row[2].innerText
};
var radios = document.querySelectorAll('input[type="radio"]');
var rows = document.querySelectorAll('table tr');
Array.from(radios).forEach(function(radio) {
  radio.addEventListener('click', function(event) {
    var is_more_than_one_middle_column_selected = document.querySelectorAll('input[type="radio"][value="' + column.middle + '"]:checked').length > 1;
    if (is_more_than_one_middle_column_selected === true) {
      // loops through all radio inputs with the middle column checked
      Array.from(document.querySelectorAll('input[type="radio"][value="' + column.middle + '"]:checked')).forEach(function(input) {
        if (input !== event.target) {input.checked = false;}
      });
    }
    var current_row_index = Array.from(rows).findIndex(function(row) {
      var current_input = Array.from(row.querySelectorAll('td input[type="radio"]')).find(function(input) {
        return input === event.target;
      });
      return !!current_input;
    });
    var middle_selected_input_row_index = Array.from(rows).findIndex(function(row) {
      return row.querySelector('input[type="radio"][value="' + column.middle + '"]')?.checked === true;
    });
    var is_middle_input_selected = middle_selected_input_row_index > -1;
    let first_input_column = rows[1].querySelector('input[type="radio"]:checked')?.value || '';
    // if the first input has not been checked but a middle input somewhere else has
    if (!first_input_column && is_middle_input_selected === true) {
      // uncheck the current input, and stop the script here; if script keeps going it will run into null errors
      return event.target.checked = false;
    }
    for (var row_index = 1; row_index < rows.length; row_index++) {
      // if the middle input is not checked yet
      if (is_middle_input_selected === false) {
        // whatever selection the current value, change all inputs to that
        rows[row_index].querySelector('input[type="radio"][value="' + event.target.value + '"]').checked = true;
      }
      else if (is_middle_input_selected === true && row_index < middle_selected_input_row_index) {
        // check the previous input to whatever the first checked input value was
        rows[row_index].querySelector('input[type="radio"][value="' + first_input_column + '"]').checked = true;
      }
      else if (is_middle_input_selected === true && row_index > middle_selected_input_row_index) {
        // check the previous input to whatever the first checked input value was
        rows[row_index].querySelector('input[type="radio"][value="' + (first_input_column === column.left ? column.right : column.left) + '"]').checked = true;
      }
      // if the current input checked was the input that triggered this logic, and a there was more than one middle input that was checked
      else if (row_index === current_row_index && is_more_than_one_middle_column_selected === true) {
        // get the first checked input value
        let first_input_column = rows[1].querySelector('input[type="radio"]:checked').value;
        // check the previous input to whatever the first checked input value was
        rows[row_index - 1].querySelector('input[type="radio"][value="' + first_input_column + '"]').checked = true;
      }
    }
  });
});

推荐阅读