Uploaded image for project: 'ZK'
  1. ZK
  2. ZK-2548

Initial keyboard selection causes combobox constraint error

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: Normal Normal
    • 7.0.5
    • 7.0.3
    • None
    • Security Level: Jimmy

      Problem Description:

      Combobox has null value initially. Pressing down arrow key fires an onSelect event, but not onChange event. While servicing the onSelect event, the server-side will perform constraint validation on the current combobox's value. Since the value is null, it is coerced to an empty string, and violates the "no empty" constraint.

      Steps to reproduce:

      1. Set focus on the first combobox's text input box
      2. Press "down arrow" key to change its selection
      -> error message shows the violation of "no empty" constraint
      3. Press "tab" to set focus on the second combobox
      -> model, dependent on the first combobox's value, is not set

      <zk>
          <zscript><![CDATA[
          ListModelList items = new ListModelList();
          items.add("d1");
          items.add("d2");
          items.add("d3");
          
          ListModelList otherItems = null;
          
          ListModelList sub1 = new ListModelList();
          sub1.add("d1s1");
          sub1.add("d1s2");
          sub1.add("d1s3");
          
          ListModelList sub2 = new ListModelList();
          sub2.add("d2s1");
          sub2.add("d2s2");
          sub2.add("d2s3");
      
          ListModelList sub3 = new ListModelList();
          sub3.add("d3s1");
          sub3.add("d3s2");
          sub3.add("d3s3");
      
          void doSelect(String value) {
              System.out.println("doSelect: " + value);
              if ("d1".equals(value))
                  secondCombo.setModel(sub1);
              else if ("d2".equals(value))
                  secondCombo.setModel(sub2);
              else
                  secondCombo.setModel(sub3);
          }
          ]]></zscript>
          <combobox id="firstCombo"
              model="${items}"
              onSelect="doSelect(self.value)"
              constraint="no empty"/>
          <combobox id="secondCombo"
              constraint="no empty"/>
      </zk>
      

      Workaround:

      Apply the following script

          zk.afterLoad('zul.inp', function() {
              var _Combobox = {};
              zk.override(zul.inp.Combobox.prototype, _Combobox, {
                  _updnSel: function (evt, bUp) {
                      var inp = this.getInputNode(),
                          val = inp.value, sel, looseSel;
                      // ZK-2200: the empty combo item should work
                      if (val || this._sel) {
                          val = val.toLowerCase();
                          var beg = this._sel,
                              last = this._next(null, bUp);
                          if (!beg || beg.parent != this){
                              beg = this._next(null, !bUp);
                          }
                          if (!beg) {
                              evt.stop();
                              return; //ignore it
                          }
          
                          //Note: we always assume strict when handling up/dn
                          for (var item = beg;;) {
                              if (!item.isDisabled() && item.isVisible()) {
                                  var label = item.getLabel().toLowerCase();
                                  if (val == label) {
                                      sel = item;
                                      break;
                                  } else if (!looseSel && label.startsWith(val)) {
                                      looseSel = item;
                                      break;
                                  }
                              }
                              var nextitem = this._next(item, bUp);
                              if( item == nextitem ) break;  //prevent infinite loop
                              if ((item = nextitem) == beg)
                                  break;
                          }
          
                          if (!sel)
                              sel = looseSel;
          
                          if (sel) { //exact match
                              var ofs = zk(inp).getSelectionRange();
                              if (ofs[0] == 0 && ofs[1] == val.length){ //full selected
                                  sel = this._next(sel, bUp); //next
                              }
                          } else{
                              sel = this._next(null, !bUp);
                          }
                      } else{
                          sel = this._next(null, true);
                      }
          
                      if (sel)
                          zk(sel).scrollIntoView(this.$n('pp'));
                      
                      if (!val && sel)
                          this.fire('onChange', { value: sel._label });
          
                      this._select(sel, {sendOnSelect:true});
                      evt.stop();
                  }
              });
          });
      

            ChunfuChang ChunfuChang
            neillee neillee
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved: