Nick Jennings
Nick Jennings

Reputation: 4042

@Watch decorator not activating

I've got a simple Test component, the template looks like this:

<template>
  <div>
    <input type="text" v-model="name" class="form-control">
    <h5>{{ message }}</h5>
  </div>
</template>
<script src="./test.ts" lang="ts"></script>

and the component TypeScript looks like this:

declare var Vue: typeof Function;
declare var VueClassComponent: any;

import { Component, Inject, Model, Prop, Watch } from "vue-property-decorator";

@VueClassComponent.default({
  template: require("./test.vue"),
  style: require("./test.sass"),
  props: {
    name: String,
    num: Number
  }
})
export default class TestComponent extends Vue {
  name: string;
  num: number;
  message: string = "";

  @Watch("name")
  protected onNameChanged(newName: string, oldName: string): any {
    console.log("setting " + oldName + " to " + newName);
  }

  mounted(this: any): void {
    console.log("mounted called");
    this.message = "Hello " + this.name + " " + this.num;
  }
}

When I type in the input box, the @Watch("name") handler never fires, however I do get these errors in the console:

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "name" 

Once for every character entered in the input box. I have no idea where the name is being set, because I have not set it anywhere. Although that is my goal (to update name) I've been reading you can't just change the value directly, you need to set @Watch handlers, and then somewhere else set them (I still don't understand exactly how but can't even get that for right now.

Upvotes: 6

Views: 8978

Answers (2)

SteveC
SteveC

Reputation: 687

This was because the name variable is not initialised and so does not yet exist on 'this'. If it was initialised with any value then a proxyGetter would have been created for it and the watch would work.

For Vue 2 this is described here enter link description here

Upvotes: 0

Bert
Bert

Reputation: 82479

Based on our discussion, the root of the problem here was declaring name as a property. The intention was that name was an internal value that would simply be used to derive message. That being the case, a watch is unnecessary and a computed does the trick.

declare var Vue: typeof Function;
declare var VueClassComponent: any;

import { Component, Inject, Model, Prop, Watch } from "vue-property-decorator";

@VueClassComponent.default({
  template: require("./test.vue"),
  style: require("./test.sass"),
  props: {
    num: Number
  }
})
export default class TestComponent extends Vue {
  name: string;
  num: number;

  get message(){
      return "Hello " + this.name + " " + this.num;
  }
}

Upvotes: 3

Related Questions