Vue.js computed property fails to initiate

Why is the Vue JS computed property not triggered with this markup?

<!-- language: lang-html -->
<p>£{{plant_price}}</p>

    <div v-if="selected.plant.variations.length > 0 ">
      <select v-model="selected.plant.selected_variation" class="form-control">
        <!-- inline object literal -->
        <option v-for="(variation, i) in selected.plant.variations" :selected="variation.id == selected.plant.selected_variation ? 'selected' : ''":value="variation.id">
          {{variation.name}}
        </option>
      </select>
    </div>

<!-- language: lang-js -->
var app = new Vue({
  el: '#vueApp',
  data: {
    selected: {
      type: {a: '' , b: ''},
      vehicle: '',
      plant: {
      }
    },
  computed: {
plant_price: function() {
  if (this.selected.plant.variations.length > 0 ) {
      var variant = _.find(this.selected.plant.variations, {id: this.selected.plant.selected_variation });
      return variant.price;
  } else {
    return this.selected.plant.price;
  }
}
...

selected.plant is populated by clicking on a plant - triggering the updateSelected method.

<div class="col-sm-4" v-for="(plant, i) in step2.plants">
          <div v-on:click="updateSelected(plant)" ....

 methods: {
      updateSelected: function(plant) {
             this.selected.plant = plant; // selected plant
             if (this.selected.plant.variations.length > 0 ) {
                 this.selected.plant.selected_variation = this.selected.plant.variations[0].id; // set the selected ID to the 1st variation

I have checked through the debugger, and can see that all the correct properties are available.

selected:Object
    type:Object
    vehicle: "Truck"
    plant:Object
       id:26
       price:"52"
       regular_price:"100"
       selected_variation:421
       variations:Array[2]
          0:Object
              id:420
              name:"small"
              price:52000
              regular_price:52000
          1:Object
               etc...

I have a computed property, which should update the plant_price based on the value of

selected.plant.selected_variation
.

I grab

selected.plant.selected_variation
and search through the variations to retrieve the price. If no variation exists, then the plant price is given.

I have a method on each product to update the selected plant. Clicking the product populates the selected.plant and triggers the computed plant_price to update the price (as the value of selected.plant.selected_variation has changed).

However, the computed plant_price is not triggered by the select. Selecting a new variant does what its supposed to, it updates selected.plant.selected_variation. Yet my plant_price doesn't seem to be triggered by it.


So I refactored my code by un-nesting selected.plant.selected_variation. I now hang it off the data object as

data = {
    selected_variation: ''
    }

and alter my computer property to reference the data as this.selected_variation. My computed property now works??? This makes no sense to me?

Answer №1

The reactivity of selected.plant.selected_variation is currently not working as expected, causing the VM to not detect any modifications you make to it after the creation of the VM.

To resolve this issue, you can utilize Vue.set() to make it reactive.

After your AJAX request is complete, be sure to execute the following code:

Vue.set(selected, 'plant', {New Plant Object})

Answer №2

There are two approaches you can take to achieve this task. Since you are working with a nested object, if you want to notify others about the changes in selected, you need to use

this.$set(this.selected, 'plant', 'AJAX_RESULT')

In the code snippet, I used a setTimeout function within the created method to mimic an Ajax call.

Another method is to not make plant_price a computed property. Instead, you can watch for changes in the nested properties of selected using a watcher and update plant_price in the handler. You can refer to plant_price_from_watch in the provided snippet for more details.

Vue.component('v-select', VueSelect.VueSelect);

const app = new Vue({
  el: '#app',
  data: {
    plant_price_from_watch: 'not available',
    selected: {
      type: {a: '' , b: ''},
      vehicle: "Truck"
    }
  },
  computed: {
    plant_price() {
      return this.setPlantPrice();
    }
  },
  watch: {
    selected: {
      handler() {
        console.log('changed');
        this.plant_price_from_watch = this.setPlantPrice();
      },
      deep: true
    }
  },
  created() {
    setTimeout(() => {
      this.$set(this.selected, 'plant', {
        id: 26,
        price: '52',
        regular_price: '100',
        selected_variation: 421,
        variations: [
          {
            id: 420,
            name: "small",
            price: 52000,
            regular_price: 52000
          },
          {
            id: 421,
            name: "smallvvsvsfv",
            price: 22000,
            regular_price: 22000
          }
        ]
      })
    }, 3000);
  },
  methods: {
    setPlantPrice() {
      if (!this.selected.plant) {
        return 'not available'
      }
      if (this.selected.plant.variations.length > 0 ) {
          const variant = _.find(this.selected.plant.variations, {id: this.selected.plant.selected_variation });
          return variant.price;
      } else {
        return this.selected.plant.price;
      }
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<div id="app">
  <p>£{{plant_price}}</p>
  <p>£{{plant_price_from_watch}}</p>
  <div v-if="selected.plant && selected.plant.variations.length > 0 ">
    <select v-model="selected.plant.selected_variation" class="form-control">
      <!-- inline object literal -->
      <option v-for="(variation, i) in selected.plant.variations" :selected="variation.id == selected.plant.selected_variation ? 'selected' : ''":value="variation.id">
        {{variation.name}}
      </option>
    </select>
  </div>
</div>

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

What could be causing all the flickering in this presentation?

Check out the jQuery slideshow I uploaded on my blog at robertmarkbramprogrammer.blogspot.com/2010/09/jquery-slideshow.html The slideshow is flickering in Chrome but looks fine in IE, Firefox, and even the standalone version. You can view it here: Here i ...

Troubleshooting: AngularJS ng-options failing to populate the list of objects

Having trouble populating a combo box in AngularJS. Here is the controller code snippet: var app = angular.module('app'); app.controller('roadmap', function($rootScope, $scope, $http, $q, leFactory) { $rootScope.activityInfoList=[ ...

Guidance on establishing an Array data type for a field in GraphQL Type declarations

Hey there! Currently, I'm working on my Nodejs project and facing a little dilemma. Specifically, I am trying to specify the type for graphQL in the code snippet below. However, I seem to be struggling with defining a field that should have a Javascri ...

Encountered an issue retrieving tweets from the Twitter API 1.1

I recently completed an online tutorial from this site: However, I'm encountering an error message that simply says 'error: ' without any additional information. To start, here is my PHP script used to fetch the JSON output: <?php sess ...

Typescript subtraction operation may result in Undefined

I am a beginner in the world of TypeScript and I'm currently struggling with running this code snippet: class TestClass { public t: number = 10; constructor() { this.t = this.t - 1; console.log(this.t); } } var obj = new TestClass(); ...

Identifying the Operating System and Applying the Appropriate Stylesheet

I am trying to detect the Windows operating system and assign a specific stylesheet for Windows only. Below is the code snippet I have been using: $(function() { if (navigator.appVersion.indexOf("Win")!=-1) { $(document ...

The jQuery element selection feature is not functioning

Within my HTML file, there lies a table with an empty tbody that is dynamically filled by jQuery once the document is fully loaded. The content of the table body is generated using a PHP script, where jQuery fetches the data via a simple GET request. Belo ...

Utilize an AJAX call to fetch an array and incorporate it within your JavaScript code

Currently, I am in the process of building a live update chart feature. To access the necessary data, I created a separate file which contains the required information. Through AJAX, I sent a request from my main page to retrieve an Array and incorporate i ...

Issue detected in React Rollup: the specific module 'name' is not being exported from the node_modules directory

Currently in the process of creating a library or package from my component. The tech stack includes React, Typescript, and various other dependencies. Encountering an error while using Rollup to build the package: [!] Error: 'DisplayHint' is ...

Is it not possible to implement a "literal" component in SFC?

I'm attempting to create a straightforward "literal" component using MyComponent inside a single file component in Vue 3: <template> <MyComponent>aha</MyComponent> </template> <script> import { ref } from "vue"; const ...

Implementing multiple dropdown menus with Material UI in a navigation bar

I am currently working on designing a navigation bar that consists of multiple material UI dropdown menus. However, I have encountered an issue that has proven to be quite challenging for me to resolve. Whenever I click on a navigation bar item, all the dr ...

Comparing the map function and for loop in the Puppeteer package for Node.js

I experimented with the Puppeteer package in NodeJS and noticed a significant difference in functionality between using the map function versus a for loop. Here is an illustration of what I observed: Using the map function: data.map(async(info) =>{ ...

Having trouble with ReactJS: Why is this.setState not working?

Hello there, I am currently learning ReactJS and struggling with an issue where I keep getting the error message "this.setState is not a function". constructor() { super(); this.state = { visible: false, navLinesShow: true }; ...

Every time I enter npm start in the terminal, I consistently encounter this error

After developing a simple web app and posting it on my repository, I started encountering these persistent errors. npm ERR! code ELIFECYCLE – David 1 hour ago npm ERR! syscall spawn C:\Windows\system32\cmd.exe;C:\Users'usernam ...

What is the best way to manually decrease the speed of an object's rotation using javascript?

Can anyone assist me with slowing down the mouse-controlled rotation of a 3D object in javascript? The current rotation is too sensitive and difficult to control manually. Below is the code I am using: <html> <head> <script src="js/thr ...

Generate a compilation of products developed with the help of angularjs

I have a request to make a list of items using Directives and share them through controllers. Check out my code example on plunker: Code Example Below is the JavaScript code: var app = angular.module('app', []); app.controller("BrunchesCtrl", ...

Volar and vue-tsc are producing conflicting TypeScript error messages

During the development of my project using Vite, Vue 3, and TypeScript, I have set up vue-tsc to run in watch mode. I am utilizing VS Code along with Volar. This setup has been helpful as it displays all TypeScript errors in the console as expected, but I ...

Universal HTML form validation with a preference for jQuery

Is there a jQuery plugin available for form validation that follows the most common rules? Specifically, I need to validate based on the following criteria: All textboxes must not be empty If the 'Show License' checkbox is checked, then the &a ...

Guide on implementing tail.select in a VueJS project

As a newcomer to VueJS, I am facing issues with using the tail.select plugin in my VueJS project. Even though I have imported the plugin in my main.js file using import 'tail.select' When I try to call tail.select(".select") in the mounted hook ...

Obtain the CSRF token from a webpage using JavaScript

I am currently working on a project where I need to retrieve the csrf token from a web page built with Django using javascript. The structure of my HTML template is as follows: <div class = "debugging"> <p id = "csrf">{% csrf_token %}</p ...