javascripthtmlinputhtml-datalist

How to reset an input type=number element when the user clicks it using JavaScript


I'm experimenting with the <input type="number" ...> list option to create a numeric input field that displays a set of predefined 'favorite' values, but still allow other values to be typed in by the user.

Here is what I have, so far:

<label>
  Zoom(%)
  <input type="number"
         min="50" step="50" value="100"
         list="favorites"
         title="Please enter or choose a zoom value." />
  <datalist id="favorites">
    <option value="100" />
    <option value="150" />
    <option value="200" />
    <option value="250" />
    <option value="300" />
  </datalist>
</label>

Problems:

There are two problems:

  1. After the first time selecting/entering a value and exiting the field, the next time the field had the focus, the drop-down list only shows some of options that sort of match the current input value, and
  2. The input element must be cleared and clicked twice in order to display the full list of options.

Goal:

How do I get the full list of options to show everytime the drop-down list shows?

I tried adding an inline onclick="this.value = '';" code segment to the input element in order to reset the input element each time the user clicks the input element, but while sometimes this seems to work, it doesn't always work, even in the same browser, so this isn't a cross-browser issue.

Is there a way to reset an input element, like a form reset does, without actually using an enclosing form element?

My issue about using a form is that when I'm using a form element to enclose the input field and reset the parent form, I can't nest forms to isolate just the one input element and resetting the parent form resets all of the input elements, which I don't want.

Here is a CodePen examples showing my test case and others. The last example in the CodePen example shows an alternate to the input type number, but without the list attribute. This separates the list feature from the input element so that the drop-down-list doesn't show until the user presses the down-triangle list button, next to the input element. When before the list actually displays, the options in the list are filters with anything that the user may have typed into the input field and supports partial matches. The initial/default value of the input field is not used as a filter, so that the whole list is displayed until something is typed into the field or after the clear button is clicked.


Solution

  • Here is an example that combines a number input and a down-list to achieve a better solution than using the number input with its data list option.

    div {
      display: inline-block;
      vertical-align: top;
      padding-right: 10px;
    }
    
    span.h {
      font-weight: 900;
      font-size: x-large;
    }
    
    button.blacktriangledown {
      position: relative;
      top: -1px;
      margin-left: -5px;
      padding: 0;
      height: 21px;
      width: 20px;
      outline: none;
    }
    button.blacktriangledown > div {
      position: relative;
      top: -7px;
      left: -3px;
      font-size: 26px;
    }
    
    button.times {
      outline: none;
      padding: 0;
      height: 20px;
      width: 20px;
    }
    button.times > div {
      position: relative;
      top: -8px;
      font-size: 26px;
    }
    
    datalist {
      display: none;
      position: absolute;
      top: 20px;
      left: 0px;
      border: thin solid black;
      background-color: white;
      cursor: pointer;
    }
    
    datalist > option:hover {
      border: thin solid black;
      background-color: lightskyblue;
    }
    <div>
      <p>
        <span class="h">Input-7</span><br />
        <b><u>with</u> an inline reset inline code segment and list and clear buttons</b>
      </p>
      <label>
        Zoom(%)
        <div style="position: relative;">
          <input type="number" id="input7" min="50" step="50" filter="" value="100"
                 datalist="favorites7"
                 title="Please enter or choose a zoom value."
                 oninput="this.setAttribute( 'filter', this.value );" />
          <button class="blacktriangledown" onclick="listButton( this );">
            <div>&blacktriangledown;</div>
          </button>
          <button class="times" onclick="clearButton( this );">
            <div>&times;</div>
          </button>
          <script>
            function listButton( This ) {
              var input   = This.parentElement.querySelector( 'input' );
              var filter  = input.getAttribute( 'filter' );
              var value   = input.value;
              var list    = This.parentElement.querySelector( 'datalist' );
              var options = list.options;
    
              var option;
    
              for( var i = 0, l = options.length; i < l; ++i ) {
    
                option                       = options[ i ];
    
                option.style.backgroundColor = ( ( option.value === value )
                                                 ? 'lightblue'
                                                 : 'inherit' );
    
                if( filter !== '' )
                  option.hidden = ( option.value.indexOf( filter ) === -1 );
    
              }
    
              list.style.display = ( ( list.style.display === 'inline' )
                                     ? 'none'
                                     : 'inline' );
    
            }
    
            function clearButton( This ) {
              var input   = This.parentElement.querySelector( 'input' );
              var list    = This.parentElement.querySelector( 'datalist' );
              var options = list.options;
    
              list.style.display = 'none';
    
              for( var i = 0, l = options.length; i < l; ++i )
                options[ i ].hidden = false;
    
              input.setAttribute( 'filter', '' );
    
              input.value = input.defaultValue;
              input.focus();
            }
          </script>
          <datalist id="favorites7">
            <option value="50">50%&nbsp;(half-size)</option>
            <option value="100">100%&nbsp;(full-size)</option>
            <option value="150">150%</option>
            <option value="200">200%</option>
            <option value="250">250%</option>
            <option value="300">300%</option>
          </datalist>
          <script>
            ( function() {
                var lists   = document.querySelectorAll( 'datalist' );
                var list    = lists[ lists.length - 1 ];
                var options = list.options;
    
                list.value          =
                list.selectedOption = null;
                list.selectedIndex  = -1;
                list.length         = list.length;
    
                for( var i = 0, l = options.length; i < l; ++i ) {
    
                  options[ i ].index = i;
                  options[ i ]
                  .addEventListener( 'click',
                                     function() {
                                       var list            = this.parentElement;
    
                                       list.style.display  = 'none';
                                       list.value          = this.value;
                                       list.selectedOption = this;
                                       list.selectedIndex  = this.index;
    
                                       list.parentElement
                                           .querySelector( 'input' )
                                           .value          = this.value ;
    
                                     } );
    
                }
    
              } )();
          </script>
        </div>
      </label><br />
      <span id="span7"></span>
    </div>