Я пытаюсь найти способ связать массив объектов в Vue select-element. Дело в следующем:

data: {
  ideas: [
    { id: 1, code: "01A", text: "option 1", props: [] }, 
    { id: 2, code: "02A", text: "option 2 , props: [{ details: "something" }]}
  ]},
  currentForm: {
    something: "foo",
    else: "bar",
    ideaCode: "01A",
    text: "option 1"
  }
];

... и в HTML ...

<select v-model="currentForm.ideaCode" @change="setCodeAndLabelForForm(???)">
  <option v-for="i in ideas" value="i">{{ i.text }}<option>
</select>

По сути, мне нужно иметь возможность отслеживать, какой объект выбирает пользователь, запускать мое собственное событие изменения, все время имея привязку с одним ключом от другого объекта ... выбранное значение / опорный ключ должно быть отделен от выбранной пользователем опции / объекта. Примечание. currentForm не относится к тому же типу объекта, что и опция! Он содержит только некоторые из тех свойств, которые у опции есть, и которые я пытаюсь передать опциям, вызывая событие изменения для выбора пользователя.

Проблема в том, что я не понял, как передать текущее выбранное значение для функции ИЛИ как написать что-то вроде:

<select v-model="selectedIdea" @change="setCodeAndLabelForForm" :track-by="currentForm.ideaCode">
  <option v-for="i in ideas" value="i">{{ i.text }}<option>
</select>

Один из возможных (и работающих) подходов:

<select v-model="currentForm.ideaCode" @change="setCodeAndLabelForForm">
  <option v-for="i in ideas" value="i.ideaCode">{{ i.text }}<option>
</select>

setCodeAndLabelForForm: function() {
    var me = this;
    this.ideas.forEach(function(i) {
        if(i.ideaCode == me.currentForm.ideaCode) {
            me.currentForm.ideaCode = i.selectedIdea.ideaCode;
            me.currentForm.text = i.text;
            ... do stuff & run callbacks ...
        }
    });
}

... но это просто кажется ужасным. Есть лучшие предложения?

4
Janne 28 Фев 2018 в 12:09

5 ответов

Я не знаю, является ли это лучшим решением, но я решаю эту проблему, используя вычисляемые свойства, например:

В файле JavaScript (ES6):

data () {
    return {
        options: [
            { id: 1, text: "option 1" },
            { id: 2, text: "option 2" }
        ],
        selectedOptionId: 1
    }
},
computed: {
    selectedOption () {
        return _.find(this.options, (option) => {
            return option.id === this.selectedOptionId
        });
    }
}

В файле HTML:

<select v-model="selectedOptionId">
  <option v-for="option in options" :value="option.id" :key="option.id">{{ option.text }}<option>
</select>

Символ '_' - это общая библиотека JavaScript, называемая Lodash, и я настоятельно рекомендую ее использовать. Это может заставить вас сэкономить драгоценное время.

0
Augusto Escobar 28 Фев 2018 в 10:32

Немного лучший обходной путь: используйте индекс в v-for

<select v-model="selIdeaIndex" @change="setCodeAndLabelForForm">
  <option v-for="(i,idx) in ideas" value="idx">{{ i.text }}<option>
</select>

Для JS:

data: {
  selIdeaIndex:null,
  ideas: [
    { id: 1, code: "01A", text: "option 1", props: [] }, 
    { id: 2, code: "02A", text: "option 2 , props: [{ details: "something" }]}
  ]
},
methods:{
    setCodeAndLabelForForm: function() {
        var selIdea = this.ideas[this.selIdeaIndex];
        //Do whatever you wanna do with this selIdea.
    }
}
0
Fandi Susanto 8 Апр 2020 в 10:50

Скромный способ - использовать $ref.

Есть решение с использованием $ref и @change.

Vue.js получает выбранный вариант необработанного объекта

0
feng zhang 15 Ноя 2019 в 09:30

Если вы знаете, что ваши option будут получены только из этих v-for="i in ideas", то индексы <option> будут такими же, как и item.

Таким образом, <select>.selectedIndex будет индексом выбранного this.item.

new Vue({
  el: '#app',
  data: {
    ideas: [
      { id: 1, code: "01A", text: "option 1", props: [] }, 
      { id: 2, code: "02A", text: "option 2" , props: [{ details: "something" }]}
    ],
    currentForm: {ideaCode: "01A", text: "option 1"}
  },
  methods: {
    setCodeAndLabelForForm: function(selectedIndex) {
      var selectedIdea = this.ideas[selectedIndex];
      this.currentForm = {ideaCode: selectedIdea.code, text: selectedIdea.text};
    }
  }
})
<script src="https://unpkg.com/vue@2.5.13/dist/vue.js"></script>

<div id="app">
  <select v-model="currentForm.ideaCode" @change="setCodeAndLabelForForm($event.target.selectedIndex)">
    <option v-for="i in ideas" :value="i.code">{{ i.text }}</option>
  </select>
  <br> currentForm: {{ currentForm }}
</div>

Отличия от ваших: @change="setCodeAndLabelForForm($event.target.selectedIndex)" и реализация setCodeAndLabelForForm.

0
acdcjunior 28 Фев 2018 в 10:56

Вы можете реализовать так:

Создайте пустые данные объекта для отслеживания выбранного значения:

currentForm: {}

Наблюдайте currentForm на модели и передавайте выбранный объект:

<select v-model="currentForm" @change="setCodeAndLabelForForm(currentForm)">

Передайте выбранное значение в option: (вы делали это правильно на этом шаге, но я просто изменил i на idea, поскольку это немного запутывает индекс зацикливания)

<option v-for="idea in ideas" :value="idea">{{ idea.text }}<option>

Примените свой метод:

setCodeAndLabelForForm(selected) {
  // Now, you have the user selected object
}
2
Bhojendra Rauniyar 28 Фев 2018 в 10:21