Vue управление состоянием редактирования формы, шаблонный код

В моем приложении есть приличное количество форм, в которых пользователь может редактировать, возвращать или сохранять изменения объекта, которые в конечном итоге сохраняются в серверной части.

Очень похоже на это: (код найден в другом вопросе)
https://jsfiddle.net/k5j6zj9t/22/

var app = new Vue({
      el: '#app',
      data: {
        isEditing: false,
        user: {
          firstName: 'John',
          lastName: 'Smith',
        }
      },
      mounted() {
        this.cachedUser = Object.assign({}, this.user);
      },
      methods: {
        save() {
          this.cachedUser = Object.assign({}, this.user);
          this.isEditing = false;
        },
        cancel() {
          this.user = Object.assign({}, this.cachedUser);
          this.isEditing = false;
        }
      }
    })

Поскольку привязка v-model немедленно изменяет базовый объект, я должен сначала создать клон объекта. Также мне нужно сохранить элемент данных, находится ли объект в состоянии редактирования. Умножьте этот код, чтобы получить больше форм и полей, и я получу слишком много членов данных и много шаблонного кода.

В серверных фреймворках, таких как django, модель находится во «временном состоянии» до тех пор, пока не будет сохранена, поэтому я могу редактировать вот так

user.first_name = 'aa' # temporary object in memory
user.save() # saved to the db

Мой вопрос, есть ли компонент / шаблон модели для vue, чтобы лучше справиться с этой задачей?
Что-то, что будет содержать состояние модели, например, isEditing, автоматически клонировать объект для редактирования формы, отменить изменения и т. д. Значит, мне не придется писать такой код для такого количества объектов?

Я бы использовал для этого миксин. Таким образом, вы сможете написать всего 1 миксин и использовать его везде, где у вас есть такие формы.

Brissy 18.06.2018 22:13

@Brissy Можете уточнить? Я ищу часами и не нашел решения

user3599803 18.06.2018 22:15

Решает ли это вашу проблему?

Brissy 18.06.2018 22:27

Не совсем, у меня есть экземпляр vue, привязанный к нескольким формам.

user3599803 18.06.2018 22:31

И почему мы не можем переместить каждую форму в отдельный компонент и расширить его с помощью миксина? Боюсь, потому что все у вас разные формы, вы не можете их объединить :(

Brissy 19.06.2018 00:07

Я хочу создать компонент формы. но как я могу передать объект компоненту формы, чтобы он обрабатывал клонирование объекта и установку v моделей? Вот как я думал, что это должно быть сделано, но я не могу придумать реализацию

user3599803 19.06.2018 07:35

Существует простой компонент формы для объектов только строковых полей jsfiddle, вам нужно что-то вроде этого? Или вы хотите встроить редактировать объекты без модальных окон / всплывающих окон?

Max Sinev 21.06.2018 11:23
JS - События опций формы
JS - События опций формы
В продолжение предыдущей статьи CSS - стили, связанные с вводом формы , в этой статье мы будем использовать JS для взаимодействия с формами, на этот...
CSS - Стили, связанные с вводом формы
CSS - Стили, связанные с вводом формы
Общими стилями ввода для форм являются Input (включая Text, Radio, checkbox), Select и Textarea, из которых Input относительно прост, поэтому в этой...
Создание многостраничной формы заявления о приеме на работу с помощью Angular
Создание многостраничной формы заявления о приеме на работу с помощью Angular
Наличие на корпоративном сайте форм заявлений о приеме на работу, или "трудовых анкет", экономит время и деньги как для соискателей, так и для...
2
7
724
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Использование Слоты с ограниченным доступом может соответствовать вашим требованиям.

Мое решение:

  1. Создайте один компонент с одним слотом

  2. Затем этот слот свяжет значения с clonedValues (если closeMode ложно, clondedValues = values)

  3. наконец, в родительском компоненте сгенерируйте свой шаблон со свойствами слота с заданной областью действия, а затем передайте его в слот.

Как показано ниже, демо:

Vue.component('child', {
  template: `
  <div>
    <div>
      <slot v-bind:values = "clonedValues"></slot>
    </div>
    <p>
      <button @click = "saveAction(clonedValues)">Save</button>
      <button @click = "resetAction()">Reset</button>
    </p>
  </div>`,
  props: {
    'cloneMode': {
      type: Boolean,
      default: true
    },
    'values': {
      type: Object,
      default: () => { return new Object() }
    }, 
    'saveAction': {
      type: Function,
      default: function (newValues) {
        this.$emit('save', newValues)
      }
    }, 
    'resetAction': {
      type: Function,
      default: function () {
        this.syncValues(this.values)
      }
    }
  },
  data() {
    return {
      clonedValues: {}
    }
  },
  created: function () {
    this.syncValues(this.values)
  },
  watch: {
    values: {
      handler: function (newVal) {
        this.syncValues(newVal)
      },
      deep: true
    },
    cloneMode: function () {
      this.syncValues(this.values)
    }
  },
  methods: {
    syncValues: function (newVal) {
      this.clonedValues = this.cloneMode ? Object.assign({}, newVal) : newVal // if you'd like to support nested object, you have to deep clone
    }
  }
})

Vue.config.productionTip = false

app = new Vue({
  el: "#app",
  data: {
    mode: true,
    labels: ['id', 'name'],
    childForm: {
      'id': 1,
      'name': 'test'
    }
  },
  methods: {
    saveForm: function (ev) {
      Object.keys(this.childForm).forEach((item) => {
        this.childForm[item] = ev[item]
      })
      // call backend to update the data
    },
    changeCurrentValue: function () {
      this.childForm.id += '#'
      this.childForm.name += '@'
    }
  }
})
<script src = "https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id = "app">
  <p><button @click = "mode=!mode">Mode: {{mode}}</button></p>
  <p>Current: {{childForm}}  --<button @click = "changeCurrentValue()">Change Current</button></p>
  <child :values = "childForm" @save = "saveForm($event)" :clone-mode = "mode">
    <template slot-scope = "slotProps">
      <p>ID: <input v-model = "slotProps.values['id']"/></p>
      <p>Name: <input v-model = "slotProps.values['name']"/></p>
    </template>
  </child>
</div>

Запрошено изменение для OP:

  1. измените слот по умолчанию на именованный slot = редактировать, затем создайте один слот = Посмотреть

  2. добавлено свойство данных = редактирование, если true, показать слот «Edit», если false, показать слот «View».

  3. в родительском компоненте создайте шаблон для slot = Посмотреть.

Как показано ниже, демо:

Vue.component('child', {
  template: `
  <div>
    <div v-show = "editing">
      <slot name = "edit" v-bind:values = "clonedValues"></slot>
      <button @click = "saveForm(clonedValues)">Save</button>
      <button @click = "resetAction()">Reset</button>
    </div>
    <div v-show = "!editing">
      <slot name = "view"></slot>
      <button @click = "editing = true">Edit</button>
    </div>
  </div>`,
  props: {
    'values': {
      type: Object,
      default: () => { return new Object() }
    }, 
    'saveAction': {
      type: Function,
      default: function (newValues) {
        this.$emit('save', newValues)
      }
    }, 
    'resetAction': {
      type: Function,
      default: function () {
        this.syncValues(this.values)
      }
    }
  },
  data() {
    return {
      editing: false,
      clonedValues: {}
    }
  },
  created: function () {
    this.syncValues(this.values)
  },
  watch: {
    editing: function (newVal) {
      if (newVal) this.syncValues(this.values)
    },
    values: {
      handler: function (newVal) {
        if (this.editing) this.syncValues(newVal) //comment out this if don't want to sync latest props=values
      },
      deep:true
    }
  },
  methods: {
    syncValues: function (newVal) {
      this.clonedValues = Object.assign({}, newVal) // if you'd like to support nested object, you have to deep clone
    },
    saveForm: function (values) {
      this.saveAction(values)
      this.editing = false
    }
  }
})

Vue.config.productionTip = false

app = new Vue({
  el: "#app",
  data: {
    childForm: {
      'id': 1,
      'name': 'test'
    }
  },
  methods: {
    saveForm: function (ev) {
      Object.keys(this.childForm).forEach((item) => {
        this.childForm[item] = ev[item]
      })
      // call backend to update the data
    },
    changeCurrentValue: function () {
      this.childForm.id += '#'
      this.childForm.name += '@'
    }
  }
})
<script src = "https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id = "app">
  <p>Current: {{childForm}}  --<button @click = "changeCurrentValue()">Change Current</button></p>
  <child :values = "childForm" @save = "saveForm($event)">
    <template slot-scope = "slotProps" slot = "edit">
      <h3>---Edit---</h3>
      <p>ID: <input v-model = "slotProps.values['id']"/></p>
      <p>Name: <input v-model = "slotProps.values['name']"/></p>
    </template>
    <template slot = "view">
      <h3>---View---</h3>
      <p>ID: <span>{{childForm['id']}}</span></p>
      <p>Name: <span>{{childForm['name']}}</span></p>
    </template>
  </child>
</div>

Спасибо. Возможно ли иметь слот-область на корневом компонентном элементе (<form>)? вместо обертки div. Кроме того, является ли срезанная область видимости единственным способом для компонента экспортировать методы? И я не вижу здесь опции редактирования, я думал, что клонирую объект только при редактировании, а не при инициализации, возможно ли реализовать это в этом компоненте? Также мне не нужен cloneMode, мне всегда нужно клонировать при редактировании

user3599803 22.06.2018 16:59

@ user3599803 обновил ответ (добавлено свойство данных = редактирование). Отвечая на ваш первый вопрос, вы имеете в виду изменить корневой элемент дочернего компонента с div на form?

Sphinx 22.06.2018 18:52

Я собираюсь изменить корневой элемент на form, я имею в виду, можно ли пропустить элемент <template>, что кажется несколько странным. Таким образом, область видимости слота будет привязана к компоненту корневого элемента (<child>). Несмотря на то, что это решение выполняет свою работу, я думаю, можно ли его реализовать без слота с заданной областью действия, возможно, с миксином, который выполняет клонирование и добавляет логическое значение редактирования. Я буду признателен за любые указатели здесь

user3599803 23.06.2018 22:21

Другие вопросы по теме