Skip to content
Advertisement

Why can’t I access props within my component?

I’ve copied the Grid Component Example into a single-file component (Grid.vue). Within that component, I’m not able to access the columns prop. console.log(this.columns) always prints: [__ob__: Observer] to the log. Can someone tell me why? This works fine in their example on the page and in JSFiddle.

Here’s my Grid.vue file:

<script>
    export default {
        name: 'grid',
        
        props: {
            data: Array,
            columns: Array,
            filterKey: String
        },
        data: function() {
            var sortOrders = {}
            console.log(this.columns)
            this.columns.forEach((column) => {
                sortOrders[column] = 1
            });
            return {
                sortCol: '',
                sortOrders: sortOrders
            }
        },
        computed: {
            filteredData: function () {
                var sortCol = this.sortCol
                var filterKey = this.filterKey && this.filterKey.toLowerCase()
                var order = this.sortOrders[sortCol] || 1
                var data = this.data
                if (filterKey) {
                    data = data.filter((row) => {
                        return Object.keys(row).some((key) => {
                            return String(row[key]).toLowerCase().indexOf(filterKey) > -1
                        })
                    })
                }
                if (sortCol) {
                    data = data.slice().sort((a, b) => {
                        a = a[sortCol]
                        b = b[sortCol]
                        return (a === b ? 0 : a > b ? 1 : -1) * order
                    })
                }
                return data
            }
        },
        filters: {
            capitalize: function (str) {
                return str.charAt(0).toUpperCase() + str.slice(1)
            }
        },
        methods: {
            sortBy: function (key) {
                this.sortCol = key
                console.log(this.sortOrders[key])
                this.sortOrders[key] = this.sortOrders[key] * -1
                console.log(this.sortOrders[key])
            }
        },
        created() {
            
        },
        mounted() {
            // var app = this
        },
    }
</script>

I’m using this component within another component like so:

<template>
    <div>
        <form id="search">
            Search <input name="query" v-model="searchQuery">
        </form>
        <grid :data="things" :columns="thingColumns" :filterKey="searchQuery"></grid>
    </div>
</template>

<script>
    import Grid from './Grid.vue';

    export default {
        name: 'things-grid',
        
        data: function() {
            return {
                things: [],
                thingColumns: [],
                searchQuery: ''
            }
        },
        mounted() {
            var app = this

            app.things = [
                {id: 1, this: 'this 1', that: 'that 1', thing: 'thing 1'},
                {id: 2, this: 'this 2', that: 'that 2', thing: 'thing 2'},
                {id: 3, this: 'this 3', that: 'that 3', thing: 'thing 3'},
                {id: 4, this: 'this 4', that: 'that 4', thing: 'thing 4'},
                {id: 5, this: 'this 5', that: 'that 5', thing: 'thing 5'},
            ]

            app.thingColumns = [
                'this', 'that', 'thing'
            ]

            app.searchQuery = ''


        },
        components: { Grid }
    }
</script>

Advertisement

Answer

In:

<grid :data="things" :columns="thingColumns" :filterKey="searchQuery"></grid>

The value of this.thingColumns is passed as :columns when mounting.

Thus, the console.log(this.columns) inside Grid.vue/data() prints when it is mounting.

And when it is mounting, thingColumns is empty in the parent:

data: function() {
    return {
        things: [],
        thingColumns: [],              // initially empty
        searchQuery: ''
    }
},
mounted() {
    var app = this
    // ...
    app.thingColumns = [               // this code only runs after it is mounted
        'this', 'that', 'thing'
    ]
    // ...
},

Since the console.log(this.columns) inside Grid.vue/data() prints when it is mounting, that is, before it is mounted, it prints an empty array:

[__ob__: Observer]  // this is an empty array, the __ob__ thing is related to Vue internals

Because, well, parent’s thingColumns will only have data after the mounted() hook executes.

And since it is a reactive array, when you update it, it will update the child grid component as well.


Solution:

Move the property initalization code from mounted() to created():

created() {                            // was mounted()
    var app = this
    // ...
    app.thingColumns = [
        'this', 'that', 'thing'
    ]
    // ...
},

This will initialize the data sooner and make it available in time for the console.log() in the child to pick it up.

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement