3

I'm trying to create a model to be able to edit existing data? How would I go about doing that?

I'm using a <el-form> to create a new entry in this case I'm creating questions, I want to reuse this for the edit and have the data from the entry added into the form.

This is my form right now

<el-dialog title="Nuevo" :loading="loading" :visible="dialogFormVisible" :visible.sync="dialogFormVisible">

    <el-form label-position="top" ref="form" :model="form" :rules="rules">
        <el-row>
            <el-form-item label="Pregunta" prop="question">
                <el-input v-model="form.question"></el-input>
            </el-form-item>
        </el-row>
        <el-row>
            <el-col :span="8">
                <el-form-item label="Seccion" prop="survey_section_id">
                    <el-select v-model="form.survey_section_id" placeholder="Selecionar">
                        <el-option v-for="section in survey_section" :key="section.id" :label="section.title"
                            :value="section.id">
                        </el-option>
                    </el-select>
                </el-form-item>
            </el-col>
            <el-col :span="8">
                <el-form-item label="Tipo de Respuesta" prop="response_type">
                    <el-select v-model="form.response_type_id" placeholder="Selecionar">
                        <el-option v-for="type in response_type" :key="type.id" :label="type.type" :value="type.id">
                        </el-option>
                    </el-select>
                </el-form-item>
            </el-col>
            <el-col :span="4">
                <el-form-item label="Opcional" prop="optional">
                    <el-switch v-model="form.optional"></el-switch>
                </el-form-item>
            </el-col>
        </el-row>
    </el-form>
    <span slot="footer">
        <el-button type="info" @click="dialogFormVisible = false">Cancelar
        </el-button>
        <el-button type="primary" :loading="loading" @click="submit('form')">Guardar
        </el-button>
    </span>
</el-dialog>

What do I need to do to turn this into a modal and use it for my editing as well?

Ask me anything, I can provide any code that I have that is needed. Thanks

Vince
  • 3,207
  • 1
  • 17
  • 28
Nancy
  • 1,021
  • 4
  • 23
  • 45

1 Answers1

3

This is a common problem. Of course, a lot of these things come down to personal preference or opinion, but here are a few things to consider:

  1. Usually when solving this problem, you display all of your existing models in some way (ie. a list), with an "edit" button. When I am doing this, I use an object that maps model IDs to their corresponding model objects as the underlying data model for this list. This makes it easy to replace a model with an updated version (models[model.id] = model).

  2. Binding the model to the form directly (eg. :model="the model you want to edit") is usually a bad implementation. This is because any changes that are made during editing would be immediately written to the model. The problem with that is, if your save() function fails, then you have to change everything back. A better implementation is to clone the model, and bind that object to the form.

  3. You can use a computed property for the modal's title/header. I usually have a data property called mode, which will be either "Create" or "Edit", and then I have a computed property that returns mode + ' Model', where 'Model' is the name of the model – in your case, "Pregunta".

  4. Since the create and update functions are usually use different API endpoints (and HTTP methods), your "Save / Update" button needs to call the right one. Again, I use the mode property to handle this (eg. <button @click="mode == 'edit' ? update : save">)


The following code should give you a good starting point for having a modal you can use for both creating & editing models, as well as the basic structure for most CRUD components.

<template>
  <div>
    <template v-for="model in modelsArray">
      ... <!-- Display your existing models however you want -->
      <a href="" @click.prevent="edit(model)">Edit</a>
    </template>
    <button @click="create">Create New Model</button>
    <el-dialog
      :title="modalTitle"
      :loading="loading"
      :visible.sync="dialogFormVisible"
    >
      <el-form :model="formModel">
        ...
      </el-form>
      <span slot="footer">
        <el-button type="info" @click="cancel">Cancelar</el-button>
        <el-button
          type="primary"
          :loading="loading"
          @click="mode == 'edit' ? update : save"
        >
          {{ mode }}
        </el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
export default {
  data() {
    mode: '',
    dialogFormVisible: false,
    loading: false,
    formModel: {},
    models: {            // an object mapping your existing model IDs
      1: { id: 1, ...},  // to their corresponding model objects
      2: { id: 2, ...},
      3: { id: 3, ...},
      ...
    }
  },
  ...,
  computed: {
    modelsArray() {
      return Object.values(this.models);
    },
    modalTitle() {
      return `${ this.mode } Model`;
    }
  },
  methods: {
    create() {
      this.mode = 'Create';
      this.dialogFormVisible = true;
    },
    edit(model) {
      this.mode = 'Edit';     
      this.formModel = _.cloneDeep(model); // See note below
      this.dialogFormVisible = true;
    },
    save() {
      // POST the new model (this.formModel) to your server using your ajax library of choice     
      // after the ajax call returns, do the following:
      this.models.push(the newly created model); // usually returned from the server as part of this ajax call
      this.reset();
    },
    update() {
      // PUT the new model (this.formModel) to your server using your ajax library of choice
      // After the ajax call returns, replace the updated model in the `models` object, and reset the form:
      this.models[this.formModel.id] = _.cloneDeep(this.formModel);
      this.reset();
    },
    reset() {
      this.dialogFormVisible = false;
      this.loading = false;
      this.formModel = {
        ... // put default form values here
      };
    }
  },
  mounted() {
    this.reset();
  }
}
</script

NOTE: _.cloneDeep is from lodash. If you're not using lodash, you can use one of these methods to clone the model.

Vince
  • 3,207
  • 1
  • 17
  • 28
  • I'm displaying the questions in a table that has an edit button on each row, so each question has a different edit button. I'm using element-ui for display the table of questions, I'm not sure how to send a picture so I can show you how everything looks – Nancy Oct 07 '19 at 17:27
  • Yeah, that's fine – that is essentially what I have in my answer. Each model (question) is displayed with an edit link. – Vince Oct 07 '19 at 17:29
  • What if I only have one model per page, like the create modal be the original and then an edit. I have other pages but I was thinking that each page had it's own model. My question is for the models array, if I just want one what needs to go there? – Nancy Oct 07 '19 at 17:51
  • I don't think I follow... But if you are hoping to ***reduce*** complexity by creating a separate page for each model, I'm sorry to say, but that won't make the solution simpler. I think your current setup is fine. But it might be helpful if you can explain exactly what you are trying to do, and what your ideal solution would look like. – Vince Oct 07 '19 at 17:55
  • well in my project I have different things set up like the one I displayed, for example this one is about questions, but I also have surveys, classes, careers, semesters, users, it's like a school system for creating surveys for the students or teachers, so I'm thinking I need a separate form to create all those things on their respective pages, so do I need a different model for each one of those pages? I would create those all on different pages – Nancy Oct 07 '19 at 18:00
  • Ok, I see. Yes. I think having a separate page for each model is a good implementation. Each of those pages can follow the structure I have outlined above. On each page, you have your table of existing models (each with an "edit" button). The edit buttons trigger a modal (in "edit" mode) for editing the model. In addition to the table, you have a "create" button which triggers the modal (in "create" mode) for creating a new model. Does that sound right? – Vince Oct 07 '19 at 18:04
  • yes, that I exactly how I have it set up, I have changed my code to try and set it up like you have shown me, I have another question, in your code inside data() there is an array for models and like there is a list, if I only want one on this specific page do I need that or what should I put inside there? – Nancy Oct 07 '19 at 18:11
  • If you only have one, rather than a list, you would want to change the `models` object inside `data()` to just `model`. Of course, this has implications for the way the rest of the code works as well. Essentially, you would need to update everything to singularize the code that was written with a list in mind. – Vince Oct 07 '19 at 18:16
  • just _model: ' '_ ? also the code I have currently to submit or save the question is different and when i edit and save it creates a new question, how can I fix this? This is my [code](https://www.codepile.net/pile/b5QDxD3d) – Nancy Oct 07 '19 at 18:23
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/200522/discussion-between-vince-and-nancy-gomez). – Vince Oct 07 '19 at 18:38