Как отключить / включить параметры выбора между формами или несколькими элементами формы? - PullRequest
2 голосов
/ 05 мая 2019

Я работаю над базовой концепцией для выбора нескольких групп, где некоторые параметры ввода отключены, потому что они обычно недоступны в данный момент, а другие отключены, потому что они уже были выбраны в другом месте. Это может быть две или более форм или несколько элементов в одной форме, как в примере. Мне нужно связать числовой вывод выборок и отключить / включить опции между отдельными элементами.

Мы используем PHP для генерации списка опций в алфавитном порядке через php include на стороне сервера. Я оставил часть php за то, что у меня только статический html для тестирования.

В примере показаны два ввода формы множественного выбора. Члены команды идентифицируются по номеру на заднем плане и с человеческими именами в UX. Обычно скрытый числовой вывод теперь доступен для тестирования под каждой командой.

Я хотел просто предварительно проверить уже выбранные значения из скрытого числового вывода onBlur и onFocus при выборе следующей команды. Тем не менее, так как элементы формы перехвачены multi.js, больше нет событий Focus и Blur, срабатывающих.

CSS на основе multi.min.css Фабиана Линдфорса:

/* basic styling */
body { font-family: Avenir,sans-serif; }
.container { box-sizing: border-box; margin: 0 auto; max-width: 500px; padding: 0 20px; width: 100%; }
.developer { color:#999; font-size: small; margin-bottom:20px }
/* form and selection styling */
label{ margin-left:20px; color: #666; font-weight:bolder }
.multi-wrapper{ border: 1px solid #999; border-radius: 8px; width: 450px; margin:10px 0 10px 0 }
.multi-wrapper .non-selected-wrapper,.multi-wrapper .selected-wrapper{ box-sizing: border-box; display: inline-block; height: 150px; overflow-y: scroll; padding: 10px; vertical-align: top; width: 50% }
.multi-wrapper .non-selected-wrapper{ background: #fafafa; border-radius: 0 0 0 8px; border-right: 1px solid #ccc }
.multi-wrapper .selected-wrapper{ background: #FFF; border-radius: 0 0 8px 0 }
.multi-wrapper .header{ color: #4f4f4f; cursor: default; font-weight: 700; margin-bottom: 5px; padding: 5px 10px }
.multi-wrapper .item{ cursor: pointer; display: block; padding: 5px 10px }
.multi-wrapper .item: hover{ background: #ececec; border-radius: 2px }
.multi-wrapper .item-group{ padding: 5px 10px }
.multi-wrapper .item-group .group-label{ display: block; font-size: .875rem; opacity: .5; padding: 5px 0 }
.multi-wrapper .search-input{ border: 0; border-bottom: 1px solid #ccc; border-radius: 8px 8px 0 0; display: block; font-size: 1em; margin: 0; outline: 0; padding: 10px 20px; width: 100%; box-sizing: border-box }
.multi-wrapper .non-selected-wrapper .item.selected{ display:  none; opacity: .5 }
.multi-wrapper .non-selected-wrapper .item.disabled,.multi-wrapper .selected-wrapper .item.disabled{ opacity: .5; text-decoration: line-through }
.multi-wrapper .non-selected-wrapper .item.disabled: hover,.multi-wrapper .selected-wrapper .item.disabled: hover{ background: inherit; cursor: inherit}

HTML-форма:

<div class="container">
    <h1>team selection demo</h1>
    <form>
        <label for="team_1">Select members for day shift</label>
        <select onChange="reportUpdatedValues(this,this.name);" 
            multiple="multiple"
            name="team_1"
            id="team_1_select">
        <option value="13" disabled="disabled">Alex</option>
        <option value="1">Bob</option>
        <option value="8">Diana</option>
        <option value="5">Frank</option>
        <option value="9">Fred</option>
        <option value="11">Helen</option>
        <option value="10">Jeanne</option>
        <option value="4">Linda</option>
        <option value="3">Mary</option>
        <option value="2" disabled="disabled">Max</option>
        <option value="7">Mo</option>
        <option value="6">Paul</option>
        <option value="12">Sara</option>
        </select>
        <span class="developer" style="display:inherit; padding:10px 0 10px 20px">
            normally hidden digital output:
        <input id="output_team_1" type="text" style="float:right">
        </span>
        <label for="team_2">Select members for night shift</label>
        <select onChange="reportUpdatedValues(this,this.name);" 
            multiple="multiple"
            name="team_2"
            id="team_2_select">
        <option value="13" disabled="disabled">Alex</option>
        <option value="1">Bob</option>
        <option value="8">Diana</option>
        <option value="5">Frank</option>
        <option value="9">Fred</option>
        <option value="11">Helen</option>
        <option value="10">Jeanne</option>
        <option value="4">Linda</option>
        <option value="3">Mary</option>
        <option value="2" disabled="disabled">Max</option>
        <option value="7">Mo</option>
        <option value="6">Paul</option>
        <option value="12">Sara</option>
        </select>
    </form>
    <span class="developer" style="display:inherit; padding:10px 0 10px 20px">
        normally hidden digital output:
        <input id="output_team_2" type="text" style="float:right">
    </span>
</div>

JavaScript

// initialise multi, set headers for group 1
       var select = document.getElementById("team_1_select");
       multi(select, {
           non_selected_header: "Candidates",
           selected_header: "Team 1"
       });

// initialise multi, set headers for group 2
       var select = document.getElementById("team_2_select");
       multi(select, {
           non_selected_header: "Candidates",
           selected_header: "Team 2"
       });

function reportUpdatedValues(element,team){
// Return an array of the selected options in element
      var result = [];
      var options = element && element.options;
      var opt;

      for (var i=0, iLen=options.length; i<iLen; i++) {
        opt = options[i];

        if (opt.selected) {
          result.push(opt.value || opt.text);
        }
      }
      // for development purpose only we display the result in the team output
      document.getElementById('output_'+team).value = result;
      return result;
}

/*! multi.min.js version 03-12-2018 by Fabian Lindfors */
var multi=function(){var e=function(e,t,n){var a=e.options[t.target.getAttribute("multi-index")];if(!a.disabled){a.selected=!a.selected;var i,d,r,l=n.limit;if(l>-1){for(var s=0,o=0;o<e.options.length;o++)e.options[o].selected&&s++;if(s===l){this.disabled_limit=!0,"function"==typeof n.limit_reached&&n.limit_reached();for(o=0;o<e.options.length;o++){(c=e.options[o]).selected||c.setAttribute("disabled",!0)}}else if(this.disabled_limit){for(o=0;o<e.options.length;o++){var c;"false"===(c=e.options[o]).getAttribute("data-origin-disabled")&&c.removeAttribute("disabled")}this.disabled_limit=!1}}i="change",d=e,(r=document.createEvent("HTMLEvents")).initEvent(i,!1,!0),d.dispatchEvent(r)}},t=function(e,t){if(e.wrapper.selected.innerHTML="",e.wrapper.non_selected.innerHTML="",t.non_selected_header&&t.selected_header){var n=document.createElement("div"),a=document.createElement("div");n.className="header",a.className="header",n.innerText=t.non_selected_header,a.innerText=t.selected_header,e.wrapper.non_selected.appendChild(n),e.wrapper.selected.appendChild(a)}if(e.wrapper.search)var i=e.wrapper.search.value;for(var d=null,r=null,l=0;l<e.options.length;l++){var s=e.options[l],o=s.value,c=s.textContent||s.innerText,p=document.createElement("a");if(p.tabIndex=0,p.className="item",p.innerHTML=c,p.setAttribute("role","button"),p.setAttribute("data-value",o),p.setAttribute("multi-index",l),s.disabled&&(p.className+=" disabled"),s.selected){p.className+=" selected";var u=p.cloneNode(!0);e.wrapper.selected.appendChild(u)}if("OPTGROUP"==s.parentNode.nodeName&&s.parentNode!=r){if(r=s.parentNode,(d=document.createElement("div")).className="item-group",s.parentNode.label){var m=document.createElement("span");m.innerHTML=s.parentNode.label,m.className="group-label",d.appendChild(m)}e.wrapper.non_selected.appendChild(d)}s.parentNode==e&&(d=null,r=null),(!i||i&&c.toLowerCase().indexOf(i.toLowerCase())>-1)&&(null!=d?d.appendChild(p):e.wrapper.non_selected.appendChild(p))}};return function(n,a){if((a=void 0!==a?a:{}).enable_search=void 0===a.enable_search||a.enable_search,a.search_placeholder=void 0!==a.search_placeholder?a.search_placeholder:"Search...",a.non_selected_header=void 0!==a.non_selected_header?a.non_selected_header:null,a.selected_header=void 0!==a.selected_header?a.selected_header:null,a.limit=void 0!==a.limit?parseInt(a.limit):-1,isNaN(a.limit)&&(a.limit=-1),null==n.dataset.multijs&&"SELECT"==n.nodeName&&n.multiple){n.style.display="none",n.setAttribute("data-multijs",!0);var i=document.createElement("div");if(i.className="multi-wrapper",a.enable_search){var d=document.createElement("input");d.className="search-input",d.type="text",d.setAttribute("placeholder",a.search_placeholder),d.addEventListener("input",function(){t(n,a)}),i.appendChild(d),i.search=d}var r=document.createElement("div");r.className="non-selected-wrapper";var l=document.createElement("div");l.className="selected-wrapper",i.addEventListener("click",function(t){t.target.getAttribute("multi-index")&&e(n,t,a)}),i.addEventListener("keypress",function(t){var i=32===t.keyCode||13===t.keyCode;t.target.getAttribute("multi-index")&&i&&(t.preventDefault(),e(n,t,a))}),i.appendChild(r),i.appendChild(l),i.non_selected=r,i.selected=l,n.wrapper=i,n.parentNode.insertBefore(i,n.nextSibling);for(var s=0;s<n.options.length;s++){var o=n.options[s];o.setAttribute("data-origin-disabled",o.disabled)}t(n,a),n.addEventListener("change",function(){t(n,a)})}}}();"undefined"!=typeof jQuery&&function(e){e.fn.multi=function(t){return t=void 0!==t?t:{},this.each(function(){var n=e(this);multi(n.get(0),t)})}}(jQuery);

В этом примере имена Алекс и Макс находятся в отпуске, и поэтому PHP уже сделал их, как правило, недоступными для всех команд. Теперь, если Диана (числовой элемент 8) выбрана для Команды 1, опция Диана должна быть отключена или скрыта для Команды 2, Команды 3, Команды 4 и так далее. Общее количество команд может варьироваться в зависимости от случая.

Ответы [ 2 ]

0 голосов
/ 08 мая 2019

Приемлемый обходной путь, найденный fardhana на GitHub, заставляющий multi.js обновляться через dispatchEvent().

Поэтому я добавил таймер, чтобы настраиваемый пользовательский интерфейс обновлялся каждые 800 миллисекунд.Теперь элемент select может быть принят за multi.js, и программно измененные значения в элементе появятся пользователю с приемлемой минимальной задержкой.

// initialise multi, set headers for group 1 and add auto refresh timer
var team1 = document.getElementById('team_1_select');
multi(team1, {
  non_selected_header: "Candidates",
  selected_header: "Team A"
});
var timer1 = function() {
  team1.dispatchEvent(new Event('change'));
};
setInterval(timer1, 800);
// initialise multi, set headers for group 2 and add auto refresh timer
var team2 = document.getElementById('team_2_select');
multi(team2, {
  non_selected_header: "Candidates",
  selected_header: "Team B"
});
var timer2 = function() {
  team2.dispatchEvent(new Event('change'));
};
setInterval(timer2, 800);

ПРИМЕЧАНИЕ: это решениена основании этой проблемы .

0 голосов
/ 07 мая 2019

Я добавил следующие js-функции старой школы, чтобы решить хотя бы часть проблемы, и сейчас я удалил инициализацию UX multi.js, чтобы упростить задачу. Таким образом, теперь участники, отобранные в Команде 1, станут недоступными для выбора в Команде 2 и наоборот, не включив тех, кто обычно был отключен в начале.

И все же остаётся вопрос, как объект при использовании multi.js может прослушивать изменения других объектов. Это еще не решено.

Также это не центральный обработчик, поэтому он не заслуживает первого приза за красивое решение.

Добавлен JavaScript:

resize_textarea(document.getElementById('team_1_select'));
resize_textarea(document.getElementById('team_2_select'));

function disableOptionsForElement(array, element) {
  // convert to Array if argument 1 is not array
  if (Array.isArray(array) == false) {
    array = array.split(",");
  }
  // loop through values in array
  for (var i = 0, iLen = array.length; i < iLen; i++) {
    // look for first option in element with current value
    var opt = getOptionByValue(element, array[i]);
    if (opt) {
      // only disable option on target if value exists
      opt.disabled = true;
      opt.selected = false;
    }
  }
}

function enableOptionsForElement(array, element) {
  // convert to Array if argument 1 is not array
  if (Array.isArray(array) == false) {
    array = array.split(",");
  }
  // loop through values in array
  for (var i = 0, iLen = array.length; i < iLen; i++) {
    // look for first option in element with current value
    var opt = getOptionByValue(element, array[i]);
    if (opt) {
      // only enable option on target if value exists
      opt.disabled = false;
    }
  }
}

function parseSelectedValues(element, target) {
  // Return an array of the selected options in element
  // target is optional DOMElement for output
  var result = [];
  var options = element && element.options;
  var opt;
  for (var i = 0, iLen = options.length; i < iLen; i++) {
    var opt = options[i];
    if (opt.selected) {
      result.push(opt.value || opt.text);
    }
  }
  if ((typeof target === "object") && (target !== null)) {
    target.value = result;
  }
  return result;
}

function parseEnabledValues(element) {
  // Return an array of the selected options in element
  var result = [];
  var options = element && element.options;
  var opt;
  for (var i = 0, iLen = options.length; i < iLen; i++) {
    var opt = options[i];
    if (opt.disabled == false) {
      result.push(opt.value || opt.text);
    }
  }
  return result;
}

function getOptionByValue(element, val) {
  // Return only a menu option element that has the requested value
  var options = element && element.options;
  var opt;
  for (var i = 0, iLen = options.length; i < iLen; i++) {
    opt = options[i];
    if (opt.value === val) {
      return opt;
    }
  }
  return false;
}

function resize_textarea(area) {
  //auto expand textarea to fit new number of lines
  area.style.height = (6 + area.scrollHeight) + "px";
}

HTML изменился соответственно

<div class="container">
  <h2>team selection demo</h2>
  <form><label for="team_1">Pick your team</label>
    <select class="multi-wrapper" id="team_1_select" multiple="multiple" name="team_1" onchange="this.form.output1.value = parseSelectedValues(this); enableOptionsForElement ( parseEnabledValues( this ) , this.form.team_2_select ); disableOptionsForElement( parseSelectedValues( this ) , this.form.team_2_select );">
      <option disabled="disabled" value="13">Alex</option>
      <option value="1">Bob</option>
      <option value="8">Diana</option>
      <option value="5">Frank</option>
      <option value="9">Fred</option>
      <option value="11">Helen</option>
      <option value="10">Jeanne</option>
      <option value="4">Linda</option>
      <option value="3">Mary</option>
      <option disabled="disabled" value="2">Max</option>
      <option value="7">Mo</option>
      <option value="6">Paul</option>
      <option value="12">Sara</option>
    </select> <span class="developer" style="display:inherit; padding:10px 0 10px 20px">normally hidden digital output: <input id="output1" readonly style="float:right" type="text" value=""></span>
    <!-- end of Team 1 -->
    <label for="team_2">Pick the other team</label>
    <select class="multi-wrapper" id="team_2_select" multiple="multiple" name="team_2" onchange="parseSelectedValues(this, this.form.output2); enableOptionsForElement ( parseEnabledValues( this ) , this.form.team_1_select ); disableOptionsForElement( parseSelectedValues( this ) , this.form.team_1_select );">
      <option disabled="disabled" value="13">Alex</option>
      <option value="1">Bob</option>
      <option value="8">Diana</option>
      <option value="5">Frank</option>
      <option value="9">Fred</option>
      <option value="11">Helen</option>
      <option value="10">Jeanne</option>
      <option value="4">Linda</option>
      <option value="3">Mary</option>
      <option disabled="disabled" value="2">Max</option>
      <option value="7">Mo</option>
      <option value="6">Paul</option>
      <option value="12">Sara</option>
    </select> <span class="developer" style="display:inherit; padding:10px 0 10px 20px">normally hidden digital output: <input id="output2" readonly style="float:right" type="text" value=""></span>
    <!-- end of Team 2 -->
  </form>
</div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...