Vue 2 - Как выбрать правильный вариант ‹select› после получения данных из базы данных

Я использую Vue 2 для небольшого блога. У меня есть отдельный компонент для формы сообщения, и один из входов формы - это select (для категории сообщения). Выбор заполняется после получения категорий из БД. Компонент также получает объект post от родительского компонента, который также извлекается из базы данных (см. props: ['post']).

Вот код:

// 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: {}
        }
    }
}

Проблема, с которой я столкнулся, заключается в том, что ни один из параметров не выбран по умолчанию. Похоже, это. Но когда я открываю выбор, я вижу обе категории из моей базы данных, например this.

Я хочу выбрать правильное (post.category_id == cat.id) значение по умолчанию. Как бы я это сделал?

Я пробовал <select ... :v-bind:selected="post.category_id == cat.id">, но случилось то же самое.

Изменить

Хорошо, теперь я попытался сбросить и post.category_id, и cat.id вот так:

<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>

И до того, как я выберу какой-либо вариант, результат будет this - печатается только cat.id, post.category_id - нет. Однако после того, как я выберу какой-либо вариант, также появится post.category_id, например this. Обратите внимание, что цифра «1» в конце появляется только на втором снимке экрана после того, как я выбрал один из вариантов - {{ post.category_id }}.

Это означает, что сообщение загружается после категорий и что я должен каким-то образом повторно инициализировать выбор после его загрузки. Как бы я это сделал? Для справки, это родительский компонент, который получает сообщение.

<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: ""
        }
    },
    components: {
        postForm
    }
}
</script>

person DevK    schedule 19.01.2017    source источник


Ответы (2)


Вам нужно установить атрибут selected на соответствующий <option> и придерживаться Vue односторонний поток данных.

Вы даже можете добавить немного сахара в удобство использования, отключив <select>, пока не загрузятся и post, и categories ...

<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>

а также

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

Затем в экземпляре / компоненте Vue, который включает указанный выше, просто используйте

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

См. Компоненты - компоненты ввода формы с использованием настраиваемых событий для получения дополнительной информации.

Демонстрация JSFiddle ~ https://jsfiddle.net/1oqjojjx/267/


К вашему сведению, я бы также инициализировал categories массивом, а не объектом ...

data () {
  return {
    categories: []
  }
}
person Phil    schedule 20.01.2017
comment
Да, это имеет смысл об инициализации в массив. Однако это не решило мою проблему. Я попытался сбросить и cat.id, и post.category_id во всех выбранных именах, и оказалось, что распечатывается только cat.id, пока я не выберу один из вариантов, а затем распечатывается и post.category_id. Так что я почти уверен, что мне нужно как-то переустановить выбор после получения сообщения. Как бы я это сделал? - person DevK; 20.01.2017
comment
@devk А, я думаю, это играет роль принципала Vue.js односторонний поток данных. Вероятно, вам не следует пытаться изменить category_id на post. Попробуйте использовать мой ответ, опуская v-model. Я сделаю несколько обновлений, чтобы проиллюстрировать - person Phil; 20.01.2017
comment
Спасибо, что остались со мной и помогли мне :). Попробую обновленный ответ вечером, когда буду дома. - person DevK; 20.01.2017

Вы должны уметь делать что-то вроде следующего:

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
            }
        })
    }
},
person Saurabh    schedule 20.01.2017
comment
Я не думаю, что это сработает, поскольку при первом рендеринге компонента не будет categories[0]. Кроме того, где находится документация для v-init? Нигде не вижу - person Phil; 20.01.2017
comment
Но я не хочу отменять post.category_id. У него уже есть значение (это форма редактирования). - person DevK; 20.01.2017
comment
если post.category_id уже имеет значение, оно должно быть выбрано по умолчанию, если вы используете это как в случае создания, так и в случае редактирования, вы можете присвоить значение this.post.category_id, когда оно не определено, и в противном случае использовать его как есть. Я обновлю это в ответ. возможно ли создать для этого скрипку. - person Saurabh; 20.01.2017
comment
У него уже есть ценность. Я обновил вопрос, добавив дополнительную информацию. Проблема в том, что выбираются категории, затем инициализируется select, а затем выбирается публикация, что, по-видимому, не повторно инициализирует выбор снова. Я опубликовал 2 скриншота, которые показывают действительно странное поведение - post.category_id отображается только после того, как я выберу один из вариантов. - person DevK; 20.01.2017
comment
Это нарушает парадигму одностороннего потока данных между компоненты - person Phil; 20.01.2017
comment
@Phil, вы абсолютно правы, и то же самое происходит, когда OP изменяет то же самое с помощью ввода выбора. - person Saurabh; 20.01.2017
comment
@Phil Vue для меня совершенно новый продукт. Какой хороший обходной путь для этого? Идея моей реализации заключается в том, что и edit.vue, и new.vue компоненты могут повторно использовать один и тот же postForm.vue компонент формы. Я бы хотел, чтобы это было так. - person DevK; 20.01.2017