Search code examples
angulardevextremedevextreme-angular

how can I make a devextreme dx-autocomplete to be number only


I initially had a dxNumberBox that restricts the input to numbers only but I had to convert it into dx-autocomplete to be able to feed it a datasource and make autocomplete available

How can I make the dx-autocomplete accept number only?

Original NumberBox:

<dx-number-box [(ngModel)]="jobNo"                         
            value=""            
            placeholder="JobNo..."
            stylingMode="outlined">
        </dx-number-box>     

dx-autocomplete:

          <dx-autocomplete [(ngModel)]="jobNo"                              
              searchMode="startswith"
              [dataSource]="storedJobNumbers"                                             
              placeholder="JobNo..."
              stylingMode="outlined">                  
          </dx-autocomplete>          

I have experimented with elementAttr, inputAttr, type etc with no luck so far. Maybe I am just using it incorrectly.


Solution

  • First of all, make sure your dataSource is an array of string (even if those strings represent number, because <dx-autocomplete> doesn't support array of numbers. i.e; use this:

    ["1", "564", "9001", "154", ...]
    

    as opposed to this:

    [1, 564, 9001, 154, ...]
    

    Then to restrict the user input, I don't believe there is an option out of the box, but here's the method I use more or less:

    <dx-autocomplete 
      (onPaste)="paste($event)" 
      (onKeyPress)="keyPress($event)" 
      [dataSource]="source">
    </dx-autocomplete>
    

    Use the onPaste and onKeyPress events, and in your bind function, check the input and act accordingly. A simple checking can look like this (but you can make it a more thorough checkingif you need):

    /*Stops the event from occurring if the data being paste isn't a number*/
    paste(e) {
      if(isNaN(e.event.clipboardData.getData('text'))){
        e.event.preventDefault();
      }
    }
    /*Stops the event from occurring if the key pressed isn't a number*/
    keyPress(e) {
      if(isNaN(+e.event.key)||e.key === " ") {
        e.event.preventDefault();
      }
    }
    

    Note that you could also use the onInput event to cover both keypress and paste in one event, but it works slightly differently (the autocomplete's value will be changed on keypress/paste/..., but you can trim it if what has been entered isn't a number)

    Let me know if this works for you :)


    Update: Adding the checking for drop event

    Devextreme doesn't have its own onDrop event, but the regular browser drop event works just fine like so:

    <dx-autocomplete ...
    (drop)="drop($event)"></dx-autocomplete>
    
    drop(e) {
        if(isNaN(e.dataTransfer.getData('text'))){
          e.preventDefault()
        }
      }
    

    As a precaution, you should always assume the user managed to put an unexpected input somehow before using that data.

    In your specific scenario it's alright because all the field does is try to autocomplete the input (meaning a wrong input just wont give any prefilled answer, which isn't awful), but if the data is used for something more crucial (backend API calls), you should always check the input to see if it isn't malformed.