admin管理员组

文章数量:1333201

I'm using Vue 2 for a small blog project. I have a separate ponent for post's form and one of the form inputs is a select (for post's category). The select gets populated after the categories are fetched from DB. The ponent also gets a post object from parent ponent, that is also fetched from the db (see props: ['post']).

Here's the code:

// HTML
...
<select class="form-control" v-model="post.category_id">
    <option 
        v-for="cat in categories" 
        v-bind:value="cat.id">
        {{ cat.name }}
    </option>
</select>
...

// JS
module.exports = {
    props: ['post', 'url'],
    name: 'postForm',
    created: function() {
        this.syncCats()
    },
    methods: {
        syncCats: function() {
            this.$http.get("/api/categories")
            .then(function(res) {
                this.categories = res.data 
            })
        }
    },
    data: function() {
        return {
            categories: {}
        }
    }
}

The problem I'm having is that none of the options is selected by default. It looks like this. But when I open the select I see both categories from my db like this.

I want to select the correct (post.category_id == cat.id) value by default. How would I do this?

I've tried <select ... :v-bind:selected="post.category_id == cat.id"> but same happened.

Edit

Okay so now I've tried dumping both post.category_id and cat.id like this:

<div class="form-group">
  <label>Category</label>
  <select class="form-control" v-model="post.category_id">
    <option 
        v-for="cat in categories" 
        :value="cat.id"
        :selected="cat.id == post.category_id">
        {{ cat.name }} {{ cat.id }} {{ post.category_id }}
    </option>
  </select>
</div>

And the result before I select any option is this - only cat.id gets printed, post.category_id does not. However after I select some option I post.category_id appears as well, like this. Notice how the "1" at the end only appears in 2nd screenshot, after I've selected one of the options, which is the {{ post.category_id }}.

This implies that the post is loaded after the categories and that I should somehow reinitialize the select after it's loaded. How would I do this? For reference this is the parent ponent that fetches the post.

<template>
    <span id="home">
        <postForm :post="post" :url="url"></postForm>
    </span>
</template>
<script>
var postForm = require('../forms/post.vue')

module.exports = {
    name: 'postEdit',
    created: function() {
        this.$http.get('api/posts/slug/' + this.$route.params.slug)
        .then(function(response) {
            if(response.status == 200) {
                this.post = response.data
                this.url = "/api/posts/slug/" + response.data.slug
            }
        })
    },
    data: function() {
        return {
            post: {},
            url: ""
        }
    },
    ponents: {
        postForm
    }
}
</script>

I'm using Vue 2 for a small blog project. I have a separate ponent for post's form and one of the form inputs is a select (for post's category). The select gets populated after the categories are fetched from DB. The ponent also gets a post object from parent ponent, that is also fetched from the db (see props: ['post']).

Here's the code:

// HTML
...
<select class="form-control" v-model="post.category_id">
    <option 
        v-for="cat in categories" 
        v-bind:value="cat.id">
        {{ cat.name }}
    </option>
</select>
...

// JS
module.exports = {
    props: ['post', 'url'],
    name: 'postForm',
    created: function() {
        this.syncCats()
    },
    methods: {
        syncCats: function() {
            this.$http.get("/api/categories")
            .then(function(res) {
                this.categories = res.data 
            })
        }
    },
    data: function() {
        return {
            categories: {}
        }
    }
}

The problem I'm having is that none of the options is selected by default. It looks like this. But when I open the select I see both categories from my db like this.

I want to select the correct (post.category_id == cat.id) value by default. How would I do this?

I've tried <select ... :v-bind:selected="post.category_id == cat.id"> but same happened.

Edit

Okay so now I've tried dumping both post.category_id and cat.id like this:

<div class="form-group">
  <label>Category</label>
  <select class="form-control" v-model="post.category_id">
    <option 
        v-for="cat in categories" 
        :value="cat.id"
        :selected="cat.id == post.category_id">
        {{ cat.name }} {{ cat.id }} {{ post.category_id }}
    </option>
  </select>
</div>

And the result before I select any option is this - only cat.id gets printed, post.category_id does not. However after I select some option I post.category_id appears as well, like this. Notice how the "1" at the end only appears in 2nd screenshot, after I've selected one of the options, which is the {{ post.category_id }}.

This implies that the post is loaded after the categories and that I should somehow reinitialize the select after it's loaded. How would I do this? For reference this is the parent ponent that fetches the post.

<template>
    <span id="home">
        <postForm :post="post" :url="url"></postForm>
    </span>
</template>
<script>
var postForm = require('../forms/post.vue')

module.exports = {
    name: 'postEdit',
    created: function() {
        this.$http.get('api/posts/slug/' + this.$route.params.slug)
        .then(function(response) {
            if(response.status == 200) {
                this.post = response.data
                this.url = "/api/posts/slug/" + response.data.slug
            }
        })
    },
    data: function() {
        return {
            post: {},
            url: ""
        }
    },
    ponents: {
        postForm
    }
}
</script>
Share Improve this question edited Jan 20, 2017 at 1:18 DevK asked Jan 19, 2017 at 23:16 DevKDevK 9,9622 gold badges31 silver badges50 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 3

You'll need to set the selected attribute on the appropriate <option> and adhere to Vue's one-way data flow paradigm.

You can even add some extra usability sugar by disabling the <select> until both the post and categories are loaded...

<select class="form-control" 
        :disabled="!(post.category_id && categories.length)"
        @input="setCategoryId($event.target.value)">
  <option v-for="cat in categories"
          :value="cat.id"
          :selected="cat.id == post.category_id">
    {{cat.name}}
  </option>
</select>

and

methods: {
  setCategoryId(categoryId) {
    this.$emit('input', parseInt(categoryId))
  }
}

Then, in the Vue instance / ponent that includes the above one, simply use

<post-form :post="post" :url="url"
           v-model="post.category_id"></post-form> 

See Components - Form Input Components using Custom Events for more information.

JSFiddle demo ~ https://jsfiddle/1oqjojjx/267/


FYI, I'd also initialise categories to an array, not an object...

data () {
  return {
    categories: []
  }
}

You should be able to do something like following:

methods: {
    syncCats: function() {
        this.$http.get("/api/categories")
        .then(function(res) {
            this.categories = res.data 
            if(!this.post.category_id) { 
               this.post.category_id = this.categories[0].id
            }
        })
    }
},

本文标签: javascriptVue 2How to select the correct ltselectgt option after the data is fetched from dbStack Overflow