Home > Back-end >  How can I solve Computed property "search" was assigned to but it has no setter?
How can I solve Computed property "search" was assigned to but it has no setter?

Time:08-21

I use vue js version 2

My child component like this :

<template>
    ...
        <div >
            <b-input placeholder="Search"  @input="(val) => searchChange(val)" />
        </div>
    ...
</template>
<script>

export default {
  props: [
    "searchChange",
  ]
};
</script>

When search, it will call method in parent component

The parent component like this :

<template>
  ...
      <page-heading
        :searchChange="searchChange"
      ></page-heading>
  ...
</template>

<script>
import { mapActions, mapGetters } from "vuex";
import PageHeading from "@/views/app/reports/PageHeading";

export default {
  components: {
    "page-heading": PageHeading,
  },
  methods: {
    ...mapActions(["getReports"]),
    searchChange(val) {
      this.search = val;
      this.page = 1;
    },
    changePage(pageNum) {
      this.page = pageNum;
    },
  },
  computed: {
    ...mapGetters({
      page: "reportPage",
      search: "reportSearch",
    }),
  },
  watch: {
    search() {
      this.page = 1;
    },
  },
  mounted() {
    this.getReports();
  }
};
</script>

I use vuex store. It's like this :

import axios from 'axios'

const state = {
  page: 1,
  search: "",
}

const getters = {
  reportSearch: state => state.search,
  reportPage: state => state.page,
}

const mutations = {
  getReportSuccess (state, res) {
    state.total = res.data.length;
    state.perPage = res.perPage;
  },
}

const actions = {
  getReports ({ commit }) {
    axios
      ...
  }
}

export default {
  state,
  getters,
  mutations,
  actions
}

When I try to search there exist error like this :

[Vue warn]: Computed property "page" was assigned to but it has no setter.

How can I solve this problem?

Please help. Thank you very much

CodePudding user response:

I see two things

  • a mapped getter for page and search
      ...mapGetters({
        page: "reportPage",
        search: "reportSearch",
      }),
    
  • and a mutation of the getters
      searchChange(val) {
        this.search = val;
        this.page = 1;
      },
    

vuex getters don't have setters, you have to invoke a mutation manually

to get around that, you need to invoke the vuex action to update the state

const mutations = {
  getReportSuccess (state, res) {
    state.total = res.data.length;
    state.perPage = res.perPage;
  },
  setReportPage(state, page) {
    state.reportPage = page;
  },
  setReportSearch(state, search) {
    state.reportSearch = search;
  },
}

const actions = {
  getReports ({ commit }) {
    axios
      ...
  },
  setPage({commit}, page) {
    commit('setReportPage', page);
  },
  setSearch({commit}, search) {
    commit('setReportSearch', search);
  },
}

this will add the actions and mutations needed to update individually

then instead of these methods:

  methods: {
    ...mapActions(["getReports"]),
    searchChange(val) {
      this.search = val;
      this.page = 1;
    },
    changePage(pageNum) {
      this.page = pageNum;
    },
  },

you would have

  methods: {
    ...mapActions(["getReports", "setPage", "setSearch"]),
    searchChange(val) {
      this.setSearch(val);
      this.setPage(1);
    },
    changePage(pageNum) {
      this.setPage(pageNum);
    },
  },

and the watch can be

  watch: {
    search() {
      this.setPage(1);
    },
  },

alternatively...

you could use a computed with a set and get like

  computed: {
    ...mapGetters("reportPage","reportSearch"]),
    page: 
      get: function () {
        return this.reportPage;
      },
      set: function (value) {
        this.setPage(value)
      },
    search: 
      // or if you don't map getters and actions ...
      get: function () {
        return this.$store.getter.reportSearch;
      },
      set: function (value) {
        this.$store.commit("setSearch", value);
        this.$store.commit("setPage", 1); // optional if you want to remove use of `searchChange`
      },
  },

this approach would allow you to map the v-model

<b-input placeholder="Search" v-model="search" />
  • Related