Prevent input label animation from async data



  • Hi,

    I’m trying to make a page where data should be loaded from an axios call first before displaying any components.

    Everything is working so far, but I’m getting some unexpected animation from an input label. To my understanding, when you set an input’s v-model with existing data, its label should automatically be above the field (so it looks like the input is already focused). The issue I’m having is after resolving an axios call and updating data(), the input field animates the label transition and I don’t want this.

    Is there any way to fix this? At the moment I’ve got an async created() and tried looking at $nextTick() but to no avail. I have a mock example at https://jsfiddle.net/skvc304y/ but you may need to click Run to see the animation I’m talking about. If that is not accessible, a copy of the code is available below:

    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/@quasar/extras/material-icons/material-icons.css">
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/quasar/dist/quasar.min.css">
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar/dist/quasar.umd.min.js"></script>
    
    <div id="q-app">
      <div class="q-ma-md">
        <q-input label="Input" v-model="inputData"></q-input>
      </div>
    
      <div class="q-ma-md">
        Running Quasar v{{ version }}
      </div>
    </div>
    
    new Vue({
      el: '#q-app',
      data: function () {
        return {
          version: Quasar.version,
          inputData: ''
        }
      },
      async created() {
          // Mock axios call
          const res = await new Promise(resolve => 
              setTimeout(() => resolve('test'), 0)
          );
          this.inputData = res
        
          // The above should behave like the following:
          // this.inputData = 'test'
      }
    })
    


  • Managed to solve it and I think I’ve over-analysed this! Simply put I’ve set a boolean flag to be true once created() has finished and a v-if on the component to wait for the flag.

    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/@quasar/extras/material-icons/material-icons.css">
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/quasar/dist/quasar.min.css">
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar/dist/quasar.umd.min.js"></script>
    
    <div id="q-app">
      <div class="q-ma-md">
        <q-input v-if="ready" label="Input" v-model="inputData"></q-input>
      </div>
    
      <div class="q-ma-md">
        Running Quasar v{{ version }}
      </div>
    </div>
    
    new Vue({
      el: '#q-app',
      data: function () {
        return {
          version: Quasar.version,
          ready: false,
          inputData: ''
        }
      },
      async created() {
        // Mock axios call
        const res = await new Promise(resolve => 
          setTimeout(() => resolve('test'), 0)
        );
        this.inputData = res
        this.ready = true
      }
    })
    

    When I was testing I could see inputData appear before the component rendering, so I assumed there was something wrong with it. Instead I was mishandling Promises!


Log in to reply