#javascript #typescript #vue.js
#javascript #typescript #vue.js
Вопрос:
У меня небольшая проблема, я создал пакет для управления формами, все работало правильно, пока мне не понадобилось создать динамическую форму на основе ответа API.
Вот пакет: https://github.com/nulvem/js-form
Он может быть установлен с помощью npm:
npm install @nulvem/js-form
Вот мой компонент Vue, вызывающий Form
класс:
<script>
import {Form} from '@nulvem/js-form'
export default {
data() {
return {
form: new Form({
template: {
value: null,
validation: {
rules: 'required',
messages: {
required: 'You must select the type of report'
}
}
}
})
}
},
mounted() {
this.form.template = 'random-id'
// These data will be obtained from an API
let fields = [
'start_date',
'end_date',
'wallets',
]
fields.forEach((field) => {
let fieldData = {
value: null,
validation: {
rules: 'required',
messages: {
required: `You must enter the field ${field.description}`
}
}
}
this.form.$addField(field, fieldData)
})
// Here we can only see the getter/setter of the template property that was passed when instantiating the Form class
console.log(this.form)
}
}
</script>
Проблема в том: Поля, которые я передал форме во время создания new Form ({...})
экземпляра, являются реактивными, поскольку, когда я добавляю новые поля, вызывая this.form.$AddField()
функцию, поля не становятся реактивными.
Самое смешное, что construct
из Form
класса вызывается вызываемая функция this.form.$AddFields()
, которая вызывает this.form.$AddField()
функцию несколько раз.
Почему он работает внутри конструктора и не работает при вызове separated? Как исправить эту проблему?
Есть идеи, что может происходить? Это сводит меня с ума, я пытался найти проблему в течение нескольких часов, и я не могу ее найти.
Редактировать
В качестве быстрого исправления мы вносим изменения в пакет, в котором можно передавать Form
экземпляр в качестве третьего параметра $addFields
функции, поэтому атрибуты являются реактивными, однако мы хотели бы, чтобы это работало без необходимости передавать этот параметр.
Комментарии:
1. Vue 2 не обнаруживает добавление / удаление свойств объекта, поэтому вы должны использовать
Vue.set()
/Vue.delete()
для этого. Если вы только инициализируете формуmounted()
со всеми полями из API, я бы установилform = new Form()
mounted()
ее, как только у вас будут доступны все поля. Тогда вам не нужно было бы передавать контекст.2. Вы должны заменить
form
экземпляр на новый, содержащий поля. Я бы сказал, что самый простой способ — просто поместитьnull
заполнительdata: () => { form: null }
и установить экземпляр класса form, когда у вас есть все поля из API. Что означает реактивность Vue: все свойства заменяются на геттеры / сеттеры, но это происходит только на верхнем уровне, а не для каждого отдельного вложенного prop. Если вы не заменитеform
Vue, он не узнает об изменении. ИVue.set()
делает именно это. Он заменяет экземпляр в prop.
Ответ №1:
VueJS теряют реактивность свойств, которые добавляются к вам data
после рендеринга. Подробнее об этом можно прочитать здесь: https://br.vuejs.org/v2/guide/reactivity.html .
Быстрый способ попытаться решить эту проблему — добавлять this.$forceUpdate()
каждый раз, когда вы добавляете новое свойство, но это также может вызвать другие проблемы в зависимости от вашего контекста.
Или вы можете попробовать использовать Vue.set()
метод вместо вашего $addField
метода. Вы можете прочитать больше по той же ссылке выше.
Комментарии:
1. Мне нужно позвонить
$addField()
, потому что это разрешит мои правила проверки и сообщения внутри класса2. В любом случае, я думаю, вы можете попробовать использовать
Vue.set
, а также добавить свойства в свойform
.
Ответ №2:
удалите контекст и измените эту строку на реактивность:
this.$initialValues[field] = fieldDeclaration.value;
=>>>
this.$initialValues[field] = fieldDeclaration.value;
this.$initialValues = Object.assign({}, this.$initialValues);
Комментарии:
1. $initialValus является реактивным, проблема заключается в доступе к itens в экземпляре формы