What could be causing the input event not to be triggered consistently when I select or highlight text?

I have implemented a 4-digit pin field with a specific behavior: when a field is filled, the focus automatically shifts to the next field (the cursor moves to the next input field). If text in a field is deleted, the text in that field is also removed and the cursor moves back to the previous pin field.

However, there seems to be an issue where sometimes, if a field with text is highlighted and overwritten by typing another key (e.g., to correct a mistake), the input event is not triggered, causing the cursor to remain in the same field instead of moving to the next one. This inconsistency can lead to a poor user experience, and I need to find a way to ensure that the cursor always switches pin fields when highlighted text is overwritten.

Below are the relevant parts of the code:

data() {
  return {
    focusIndex: 1,
    inputOne: '',
    inputTwo: '',
    inputThree: '',
    inputFour: '',
    numberOfPinFields: 4,
  };
},

mounted() {
// this highlights the first pin field
  this.$refs[this.focusIndex].focus();
},

methods: {
  handlePinFieldDeletion() {
    if (this.focusIndex > 1) {
      this.focusIndex -= 1;
    }
  },
  
  handlePinFieldInput(value, maxNumberOfFields) {
    this.$nextTick(() => {
     // after the focus index from the input field watch below is updated, increase the focusIndex value
       if (value.length === 1 && this.focusIndex < maxNumberOfFields) {
          this.focusIndex += 1;
        }
      });
    },
  ensurePinFieldHasOneInput(value) {
    return value.slice(0, 1);
  },
  highlightOnFocus(e, focusIndex) {
    // highlight the text
    e.target.select();
    // set the new focus index
    this.focusIndex = focusIndex;
  },
 }
 
 watch: {
  focusIndex(newValue) {
    this.$refs[newValue].focus();
  },
  inputOne(newValue) {
    // set focus index of first otp input field to 1 when it changes.
    // This will help with situations where the user doesn't use the input fields in numerical order
    this.focusIndex = 1;
    this.inputOne = this.ensurePinFieldHasOneInput(newValue);
  },

  inputTwo(newValue) {
  // set focus index of first otp input field to 2 when it changes.
  // This will help with situations where the user doesn't use the input fields in numerical order
    this.focusIndex = 2;
    this.inputTwo = this.ensurePinFieldHasOneInput(newValue);
  },

  inputThree(newValue) {
  // set focus index of first otp input field to 3 when it changes.
  // This will help with situations where the user doesn't use the input fields in numerical order
    this.focusIndex = 3;
    this.inputThree = this.ensurePinFieldHasOneInput(newValue);
  },
  inputFour(newValue) {
    // set focus index of first otp input field to 4 when it changes.
    // This will help with situations where the user doesn't use the input fields in numerical order
    this.focusIndex = 4;
    this.inputFour = this.ensurePinFieldHasOneInput(newValue);
  },
  }
<form>
  ...
  <q-input
    type="password"
    input-class="text-center"
    maxlength="1"
    @keyup.delete="handlePinFieldDeletion"
    @input="handlePinFieldInput($event, numberOfPinFields)"
    v-number-only
    @focus="highlightOnFocus($event, 1)"
    borderless
    ref="1"
    v-model="inputOne"
  />
  <q-input
        type="password"
        input-class="text-center"
        maxlength="1"
        v-number-only
        @focus="highlightOnFocus($event, 2)"
        @keyup.delete="handlePinFieldDeletion"
        @input="handlePinFieldInput($event, numberOfPinFields)"
        borderless
        ref="2"
        v-model="inputTwo"
      />
      <q-input
        type="password"
        input-class="text-center"
        maxlength="1"
        v-number-only
        @focus="highlightOnFocus($event, 3)"
        @keyup.delete="handlePinFieldDeletion"
        @input="handlePinFieldInput($event, numberOfPinFields)"
        borderless
        ref="3"
        v-model="inputThree"
      />
      <q-input
        type="password"
        input-class="text-center"
        v-number-only
        @focus="highlightOnFocus($event, 4)"
        maxlength="1"
        @keyup.delete="handlePinFieldDeletion"
        @input="handlePinFieldInput($event, numberOfPinFields)"
        borderless
        ref="4"
        v-model="inputFour"
      />
  ...
</form>

Answer №1

After conducting several tests, I have identified the issue within the watch function when it comes to overwriting with the same value. For example, if field 1 was previously highlighted and updated by 5, and then updated by another 5.

Code snippet:

 watch: {
  focusIndex(newValue) {
    this.$refs[newValue].focus();
  },
  inputOne(newValue) {
    this.$q.notify({
        message: 'inputOne changed',
        caption: 'moments ago',
        color: 'secondary'
      })

Answer №2

The maxLength attribute has an interesting behavior where it does not trigger an input event when the input field reaches its maximum limit.

I found that the pin field sometimes worked and sometimes didn't after the highlighted value was overwritten. This inconsistency seemed to be due to the fact that if the user entered the same value as before (thus overwriting it with no actual change), the input event wouldn't fire. However, if a different value was used to overwrite the previous one, the event would trigger.

This discovery was made through trial and error, as I couldn't find confirmation of this behavior anywhere else. To resolve the issue, I removed the maxLength attribute and refactored the code, leading to success. The updated code can be seen below.

<script>
const generatePinInputs = (numberOfPinFields) => {
  const objectOfPinFields = {};
  // create an array of values for the number of pin fields
  Array(numberOfPinFields).fill('').forEach((field, index) => {
    objectOfPinFields[index + 1] = field;
  });
  return objectOfPinFields;
};
export default {
  name: 'app-pin',
  props: {
    numberOfPinFields: {
      type: Number,
      default: 4,
    },

  },
  mounted() {
    // switched from quasar's q-input to input because of error thrown about v-model mutating prop value
    this.$nextTick(() => {
      // After all asynchronous actions (including dialog popup showing pin fields), focus on the first input
      this.$refs[1][0].focus();
    });
  },
  data() {
    return {
      pinInputs: generatePinInputs(this.numberOfPinFields),
    };
  },


// rest of the code is unchanged...

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How to use RegExp to locate the final return statement within a JavaScript code string

Take a look at this code snippet: cont x = 10; function foo() { return x; // ;; end of function ;; // /* here is a some text here too */ } function bar() { return 10 } return foo() + bar(); // ;;done;; // /* yolo yolo */ This string cont ...

Using a variable as a key for a JavaScript object literal with a string value

Is there a way to achieve this? objPrefix = btn.attr('data-objprefix'); //<button data-objPrefix="foo"> var sendData = {objPrefix : {"bar":"ccccc"}}; My desired outcome is {"foo" : {"bar":"ccccc"}}; however, the current result shows { ...

Ajax updates to an element are not reflected until the for loop has completed

I am looking for a way to print a series of numbers sequentially using AJAX. Here is an example of what I want to achieve: (each new line represents an update of the previous line!) Output is: 1 12 123 1234 12345 123456 ... I ...

I am trying to access a value saved in a service in Angular 8 component and use it in other services. Can anyone help

Setting a value through a component export class UniqueComponent { constructor(service:UniqueService){ } count =0 ; onRefresh(){ this.service.count = 1; } } Using the value in the service UniqueService{ count:any; doSomething(){ //using count ...

AngularJS ng-map defines the view position using rectangular coordinates

Is there a way to set the position of ng-map view using the ng-map directive not as the center value of [40.74, -74.18], but instead as a rectangle defined by the corner values of the map view (north, south, east, west)? Currently, I have this code: < ...

Interested in integrating Mockjax with QUnit for testing?

I recently came across this example in the Mockjax documentation: $.mockjax({ url: "/rest", data: function ( json ) { assert.deepEqual( JSON.parse(json), expected ); // QUnit example. return true; } }); However, I'm a bit confused abou ...

Is the bearer terminology used for the authentication token or is it meant for a separate token?

In my MEVN application, I am incorporating JWT tokens and currently exploring how to transmit authentication tokens via axios. It is common practice to add "Bearer " before the token and have the server strip off "Bearer " to access the token's conten ...

Implementing one-to-many relationships using Knex.js and Bookshelf.js in an ExpressJS/Postgres environment

When a user registers, I want to create a record on two tables simultaneously. user.js const db = require('../database'); const User = db.Model.extend({ tableName: 'login_user', hasSecurePassword: true, hasTimestamps: true, t ...

Saving an array within the Yii framework

The view contains the following form: <form method="POST" action="<?php echo Yii::$app->request->baseUrl;?>/telephone/addnow/" role="form" enctype="multipart/form-data"> <label>Upload your photo:</label><input type="fi ...

JavaScript, detecting repeated characters

I need to create a script that checks an input box (password) for the occurrence of the same character appearing twice. This script should work alongside existing regex validation. I believe I will need to use a loop to check if any character appears twice ...

Problem with Jsdom retrieving document

I am struggling to utilize jsdom for loading a local HTML file. Here is the code snippet: var config = { file: "filename", scripts: ["node_modules/jquery/dist/jquery.min.js"], done: function(err, window){ con ...

Using AJAX autocomplete with Sys.Serialization.JavaScriptSerializer

I implemented an ajax autocomplete feature in ASP.NET where a method from a web service is called to fetch postal codes. public string[] GetNames(string prefixText, int count, String contextKey) { prefixText = prefixText.Trim(); XmlNodeList list; ...

Error Received While Attempting to Log in using Ajax

Having an issue with logging in using ajax and php. I am able to log in successfully, but when trying to display an alert message and refresh the page upon login, it gives me an error without refreshing. However, upon manually refreshing the page, I can se ...

Nextjs couldn't locate the requested page

After creating a new Next.js application, I haven't made any changes to the code yet. However, when I try to run "npm run dev," it shows me the message "ready started server on [::]:3000, url: http://localhost:3000." But when I attempt to access it, I ...

transforming JSON information within an angularJS framework into an array and displaying it visually with a C3 chart

Looking to create an x-y plot using AngularJS with a JSON data feed. The JSON data displays EQ magnitude VS time. How do I convert this data into an array format and plot it in a c3 chart? (similar to the one in this link ) Appreciate any assistance you c ...

Obtain the dimensions (width and height) of a collection of images using Angular and TypeScript

Currently, I am facing an issue with my image upload functionality. My goal is to retrieve the width and height of each image before uploading them. However, I've encountered a problem where my function only provides the dimensions for the first image ...

Condensed JQuery condition code for "if" statement

This piece of code is designed to sequentially display 10 questions and control the visibility of each question using the CSS class .hideme. It also sends metrics data to Google Analytics. Although it functions properly, I feel like the code is too leng ...

Chronological Overview (Highcharts)

Can you customize a timeline in Highcharts to resemble the image? I have a functional example of the timeline I desire, but the color coding and filtering aspects are challenging for me. I am attempting to apply a filter that will decrease the opacity of ...

What is the best way to upgrade Angular from version 10 to 12?

Currently tackling an Angular project migration from version 10 to version 12. Unfortunately, the project seems to be encountering issues post-migration and is not running as expected. ...

Customizing the formatting of Angular's ui-select2 NoMatches message within a directive

I have a multiple select in a directive template and I want to customize the message that appears when no matches are found. The documentation on suggests overriding the formatNoMatches method for this purpose. This is the select element in my directive& ...