Home > database >  V-If not updating
V-If not updating

Time:05-19

I used a v-if/else statement in my html. These depend on a watcher. In my watcher I also used a setTimeout() function to clone an api call. When I try to set the isLoading data property to false in my setTimeout() function, the dom is not updated and so the v-if stays true.

Watch:

watch: {
    selectedConfederations(newValue) {
      alert(newValue.length);
      if (newValue.length > 0) {
        this.showStepper = false;
        this.isLoading = true;
        setTimeout(function() {
          this.isLoading = false; /* This.isLoading will be false but DOM does not update and v-if stays on true and spinner will still be showing */
        }, 3000);
      } else {
        this.showStepper = true;
        this.isLoading = false;
      }
    },
  },

Data:

data() {
    return {
      showStepper: true,
      isLoading: false,
    }
}

Html:

<div v-if="isLoading">
          <v-layout row justify-center>
            <v-progress-circular
              :size="70"
              :width="7"
              color="primary"
              indeterminate
            ></v-progress-circular>
          </v-layout>
        </div>
        <div v-else>
          <v-layout row mt-2>
            <v-flex xs3>
              <v-card style="position:fixed" max-width="400">
                <v-toolbar row color="primary" dark>
                  <v-flex xs4>
                    <v-toolbar-title>
                      <v-icon dark>filter_alt</v-icon> Filter</v-toolbar-title
                    >
                  </v-flex>
                  <v-flex xs8 style="padding-left: 50%;">
                    <v-tooltip bottom>
                      <template v-slot:activator="{ on, attrs }">
                        <v-btn
                          style=""
                          color="white"
                          outline
                          small
                          fab
                          v-bind="attrs"
                          v-on="on"
                        >
                          <v-icon dark>autorenew</v-icon>
                        </v-btn>
                      </template>
                      <span>Reset filter</span>
                    </v-tooltip>
                  </v-flex>
                </v-toolbar>
                <v-card-text style="border-bottom: 1px solid lightgrey;">
                  <v-checkbox
                    label="Include girls"
                    color="primary"
                    hide-details
                  ></v-checkbox>
                  <v-checkbox
                    disabled
                    label="Include professional clubs only"
                    color="primary"
                    hide-details
                  ></v-checkbox>
                </v-card-text>
                <v-card-text style="border-bottom: 1px solid lightgrey;">
                  <h2 >
                    Budget of clubs
                  </h2>
                  <v-chip
                    v-for="tag in filterItems.budgets"
                    :key="tag.id"
                    @click="() => selectedBudgetOption(tag)"
                    :outline="tag.selected ? false : true"
                    color="primary"
                  >
                    {{ tag.name }}
                  </v-chip>
                </v-card-text>
                <v-card-text style="border-bottom: 1px solid lightgrey;">
                  <h2 >
                    Amount of players inside clubs
                  </h2>
                  <v-chip
                    v-for="tag in filterItems.playersizes"
                    :key="tag.id"
                    @click="() => selectedBudgetOption(tag)"
                    :outline="tag.selected ? false : true"
                    color="primary"
                  >
                    {{ tag.name }}
                  </v-chip>
                </v-card-text>
                <v-card-text>
                  <h2 >
                    Teams available
                  </h2>
                  <v-chip
                    v-for="tag in filterItems.agegroups"
                    :key="tag.id"
                    @click="() => selectedBudgetOption(tag)"
                    :outline="tag.selected ? false : true"
                    color="primary"
                  >
                    {{ tag.name }}
                  </v-chip>
                </v-card-text>
              </v-card>
            </v-flex>
            <v-flex xs9>
              <v-layout>
                <RadarChart
                  :name="dimensionChart"
                  :title="dimensionChartTitle"
                />
              </v-layout>
            </v-flex>
          </v-layout>
          <v-layout row>
            <v-flex xs3> </v-flex>
            <v-flex xs9>
              <v-layout>
                <RadarChart
                  :name="internationalStandardChart"
                  :title="internationalStandardChartTitle"
                />
              </v-layout>
            </v-flex>
          </v-layout>
        </div>

I think the problem is that the DOM is not being updated even when the watcher detects changes. The watcher is based on a v-model that is connected to a v-dropdown. All help is welcome and is much appreciated!

CodePudding user response:

The isLoading is never returning to false because this in your setTimeout function is not referencing to the vue instance but to his own scope.

Making it an arrow function will fix this :

setTimeout(() => {
   this.isLoading = false;
}, 3000);

CodePudding user response:

That doesn't work because of this code :

setTimeout(function() {
  this.isLoading = false; 
}, 3000);

In the code above, the value of this is different because you used a function which has a dynamic execution context (this).

--

To solve this problem you can store the value of this and then use it in the function :

const that = this
setTimeout(() => {
  that.isLoading = false;
}, 3000)

You can also directly bind this of the method :

setTimeout(function () {
  this.isLoading = false;
}.bind(this), 3000)

Finally, the more convenient solution is to use an arrow function (which does not define its own this):

setTimeout(() => {
  this.isLoading = false;
}, 3000)
  • Related