1

I have an error in the console that is saying:

Instead, use a data or computed property based on the prop's value. Prop being mutated: "sortType"

My root file contains an api and a filter function. I am sending that data to components. Everything was fine 'til I added some sorting in filterList().

This is how I am receiving the sortType:

<div id="toprow">
       // slider codes...
        <select id="sortBox" v-model="sortData" v-on:change="filterList">
            <option value="">sorting</option>
            <option value="price">cheapest</option>
            <option value="created_at">newest</option>
        </select>
</div>


props:["filterList", "slider", "sliderX", "sortType"],
components: {
    vueSlider,
},
data() {
    return {
        sortData: this.sortType
    }
},
methods: {
    filterList(newType){
        this.$emit('update:type', newType)
    }
}

Below, my root file...

<app-toprow v-on:update:type="sortType = $event" :filterList="filterList" :slider="slider" :sliderX="sliderX" :sortType="sortType"></app-toprow>


data(){
    return {
        api: [],
        sortType:"",
    }
},
mounted(){
    axios.get("ajax").then(response => {
        this.api = response.data
    })
},
methods: {

},
computed: {
    filterList: function () {
        let filteredStates = this.api.filter((estate) => {
            return (this.keyword.length === 0 || estate.address.includes(this.keyword)) &&
            (this.rooms.length === 0 || this.rooms.includes(estate.rooms)) &&
            (this.regions.length === 0 || this.regions.includes(estate.region))});

            if(this.sortType == 'price') {
                filteredStates = filteredStates.sort((prev, curr) => prev.price - curr.price);
            }
            if(this.sortType == 'created_at') {
                filteredStates = filteredStates.sort((prev, curr) => Date.parse(curr.created_at) - Date.parse(prev.created_at));
            }

            return filteredStates;
    },
}
}

Okay, am I doing something wrong when I receiving the sortType?

ProgrammerPer
  • 1,125
  • 1
  • 11
  • 26

3 Answers3

1

You pass sortType as a prop into the child component and simultaneously mutate it using the v-model in select, thus receiving this error.

Your child component should be something like:

<div id="toprow">
// slider codes...
    <select id="sortBox" v-model="selectedSort" v-on:change="filterList">
        <option value="">sorting</option>
        <option value="price">cheapest</option>
        <option value="created_at">newest</option>
     </select>
</div>


export default {
    data() => ({
        selectedSort: this.sortType
    })
    props:["filterList", "slider", "sliderX", "sortType"],
    components: {
        vueSlider,
    },
    methods: {
        filterList(newType){
            this.$emit('update:type', newType)
        }
    }
}

Now on the v-on:change=filterList you should emit a custom event on the parent that notifies him that the sorting has changed.

And something like this on the parent:

<app-toprow v-on:update:type="sortType = $event" :filterList="filterList" :slider="slider" :sliderX="sliderX" :sortType="sortType"></app-toprow>

Relevant SO question: https://stackoverflow.com/a/51722100/7482509 Relevant docs: https://v2.vuejs.org/v2/guide/components-custom-events.html, https://v2.vuejs.org/v2/guide/components-props.html#One-Way-Data-Flow

tony19
  • 125,647
  • 18
  • 229
  • 307
Bill Souvas
  • 46
  • 2
  • 6
  • thank you for answering. the only thing I didn't understand here. this part. `filterList(newType){ this.$emit('update:type', newType) }` where should I insert this inside my filterList() ? –  Apr 20 '19 at 04:18
  • why don't u put that snippet into `export default { ... }` just below `components:`? – SuperStar518 Apr 20 '19 at 08:04
  • you mean in child component make a `computed: {` and use that snippet inside? But I already using filterList() and receving that filterList() from parent. just check the question... So... it doesn't make sense... @AliD. –  Apr 20 '19 at 08:18
  • i updated my answer. The filterList should go into the child component's methods. – Bill Souvas Apr 20 '19 at 13:08
  • thank you for update. But I already tried that. you see in the question `filterList()` is the function in the parent and I am receiving that too... that's why when I recreate in child. of course I get error. I need `filterList()` in the parent that how I do sorting/filtering... That's why I am having this error: `Method "filterList" has already been defined as a prop.` By the way updated the question with the latest code. –  Apr 20 '19 at 14:30
0

FIX FOR CLONED[i].apply

Vue 2 - Uncaught TypeError: cloned[i].apply is not a function at HTMLInputElement.invoker (vue.esm.js?65d7:1810) error

basically you should just change the prop name filterList to something else

NEW ANSWER

here's an update answer, prop filterList is the same name as in method I do think that is conflict. also i do think that you don't need to send filterList method from parent to children because you are already listening on if via update:type

methods: {
    filterList(event){
        // use the v-model reactive feature..
        this.$emit('update:type', this.sortData)
        // if you don't like this.sortData -> uncomment below
        // this.$emit('update:type', event.target.value)
    }
}

OLD

why don't you use mounted() for initializing sortData: this.sortType...

data() {
    return {
        sortData: null
    }
},
mounted() {
  this.sortData = this.sortType
}

P.S.

Just my theory... I could not explain clearly why this is happening but I do think that this is because vue is reactive and all data values should not have a value directly from prop. because if you think about it if it came from prop DIRECTLY therefor editing it should also edit the prop..

but I don't really know why it's doing that, better ask that another time.

Sean Reyes
  • 1,636
  • 11
  • 19
  • I also tried that in the mounted hook like this `this.sortData = this.sortType` but having this error. `cloned[i].apply is not a function` by the way assuming `:` is a syntax error in your mounted code –  Apr 20 '19 at 14:49
  • Sorry about the syntax-error... but where are you calling ```cloned[i].apply``` ? – Sean Reyes Apr 20 '19 at 15:02
  • I do need to send `filterList()` because inside that `filterList()` not just `sortType` also has other filters I want all filters connected. That's why sending it... for example my slider filter works fine... But my sortType is not running... –  Apr 20 '19 at 15:24
  • and by the way. that `filterList()` has include sortType filter too.. if you look closely... –  Apr 20 '19 at 15:27
  • i would like to suggest to install vue-devtools (browser extension) for better Debugging.. ;) – Sean Reyes Apr 20 '19 at 15:31
0

does the select option didn't has default value (the value is always sorting on page load)? if yes you don't have to use v-model

if it has default value, try use :value instead of v-model, and use the props sortType as the value.

also you can't use same name on filterList, try using different variable for the function.

<div id="toprow">
       // slider codes...
        <select id="sortBox" :value="sortType" v-on:change="change">
            <option value="">sorting</option>
            <option value="price">cheapest</option>
            <option value="created_at">newest</option>
        </select>
</div>

on the change Function

export default {
    methods: {
        change(e){
            this.$emit('update:type', e.target.value)
        }
    }
}

on your parent component

<app-toprow v-on:update:type="sortType = $event" :filterList="filterList" :slider="slider" :sliderX="sliderX" :sortType="sortType"></app-toprow>
imste
  • 360
  • 3
  • 7
  • and this is the best answer. thank you so much. it's working like a magic now. the thing I don't understand. How `change()` knows data and interreact with `filterList()` because my filter code inside filterList() in parent. but change() function knows that and interreact with it. Although I did't mention `filterList()` in `select` like before... –  Apr 21 '19 at 13:37
  • 1
    you are welcome! . when you change the select option, it will trigger `change` method, the `change` method then pass / emit the value to the parent. it modify the `sortType` variable. And since `sortType` variable is used in the `filterList`, and `filterList` is a computed property, the computed property will triggered when any variable used in that property is changed – imste Apr 22 '19 at 05:22