Про vue.js и рендергинг v-for

Какое-то время пилю некоторое приложение на Laravel. На этот раз, для разнообразия, решил попробовать прилагающийся по умолчанию фронт-энд. На Vue.js который.

Не могу сказать, что обрел уже просветление и стал гурой, понимание предмета пока еще несколько клиповое. Но в целом после привычного ангуляра диким зверем фреймворк не выглядит, получается достаточно стройно и понятно. Хотя какие-то вещи и могут казаться странными.

В процессе освоения и использования, набрёл на любопытный хак. Захотелось мне, значит, сделать множество полей с автодополнением, примерно так (упрощенно):

<ol>
    <li v-if="people" v-for="(person, index) in people">
        <autocomplete
            url="/people/search_by_name"
            anchor="name"
            label="email"
            :initValue="person.name"
            :onInput="autocompleteNameChanged"
            :onSelect="autocompleteGetData"></autocomplete>
        <button type="button" v-on:click="removePerson($event, index)" class="btn btn-default"><span class="fa fa-times"></span></button>
    </li>
</ol>

Это поле автодополнения, а справа у каждого экземпляра кнопка для удаления с простым обработчиком:

removePerson: function (event, index) {
    event.preventDefault();

    this.people.splice(index, 1);
},

Проблема в том, что по нажатии на удаление визуально удаляется не выбранный элемент, а последний. Вот так:

1

Под капотом-то всё правильно происходит, если сохранить форму — удаленным окажется именно выбранный элемент. Но визуально это совсем не очевидно.

Вообще, во Vue.js есть такой атрибут :key. Судя по описанию — то что надо. Но вот незадача: если у person еще нет уникального id, потому что мы работаем с формой создания, ничего не выйдет. Если в :key поместить просто index, то есть, порядковый номер — результат будет такой же, как на гифке выше.

Побродив по форумам в попытках обнаружить решение, наткнулся на занятный совет. Изменение атрибута :key заставит Vue перерендерить список. То есть можно задать автодополнениям одно какое-то значение (не забудьте проинициализировать):

<autocomplete
    ...
    :key="update_component_key"
    ...
    :onSelect="autocompleteGetData"></autocomplete>

И обновлять его каждый раз, когда массив people изменился и нужно перерендерить поля:

removePerson: function (event, index) {
    event.preventDefault();

    this.people.splice(index, 1);
    this.update_component_key ++;
}

Так — работает:

1

В следующий раз можно посмотреть, например, как работают сами поля автодополнений (на основе существующего компонента, не самописные).

Комментарии