0

I have a simple component that I use as a 'wrapper' for another component that displays a form for each object.

When I try to edit any of the forms, when I submit the form it's not picking up the values for the inputs.

Here is the wrapper component template:

<script id="evidenceFormsContainerTemplate" type="text/x-template">
  <div>
    <evidence-form
      v-for="(element, index) in evidence"
      ref="form"
      :shared-store="sharedStore"
      :element="element"
      :key = "element.id"
      :index="index"
      :subdomains="subdomains"
    >
    </evidence-form>
  </div>
</script>

Here is the evidenceFormTemplate:

<script type="text/x-template" id="evidenceFormTemplate">
    <div>
        <div class="mt-4 mb-4 row" :class="(sharedStore.state.activeForm != index) ? 'bg-white text-secondary border border-secondary rounded':'bg-light text-dark border border-primary rounded'">
            <form class="col" :id="'form'+element.id" v-on:submit.prevent="submitForm(element.absolute_url, sharedStore.state.evaluationId)">
                <fieldset :disabled="(sharedStore.state.activeForm != index && element.id)">
                    <input type="hidden" id="evidenceId" v-model="element.id">
                    <div class="form-row">
                        <div class="form-group col-sm-4">
                            <label class="" for="subdomain">Subdomain</label>
                            <select name="subdomain" id="subdomain" class="form-control" v-model="element.subdomain">
                                <option v-for="choice in subdomains" :value="choice.id" >{{ choice.character_code }}</option>
                            </select>
                        </div>
                        <div class="form-group col">
                            <label class="" for="comments">Comments</label>
                            <textarea id="comments" class="form-control" v-model="element.comments" rows="5"></textarea>
                        </div>
                    </div>
                    <div class="form-row mb-4">
                        <label class="sr-only" for="published">Publish Status</label>
                        <div class="btn-group btn-group-toggle" data-toggle="buttons">
                            <label :class="{ active: element.published,}" class="btn btn-outline-success form-check-label" for="publishedTrue">Published
                                <input v-model="element.published" :active='element.published' :class="{ active: element.published, 'form-check-input': true}" type="radio" name="published" id="publishedTrue" value="true"> </label>
                            <label :class="{ active: !element.published,}" class="btn btn-outline-secondary form-check-label" for="publishedFalse">Unpublished
                                <input v-model="element.published" :active='!element.published' :class="{ active: !element.published, 'form-check-input': true}" type="radio" name="published" id="publishedFalse" value="false"> </label>
                        </div>
                    </div>
                    <div class="form-row">Created By: {{ element.created_by_name }}</div>
                    <div class="form-row">Last Updated: {{ element.updated_at}} by {{ element.updated_by_name }}</div>
                </fieldset>
                <div v-show="!hideControls" class="form-row mt-4 mb-4">
                    <button type="button" v-if="!isEditing" class="btn btn-primary ml-2 mr-2 text-white" @click="editForm(element, sharedStore.state.activeForm, index)"> <i class="far fa-edit"></i> EDIT </button>
                    <div v-show="!hideControls && isEditing">
                        <button :id="'saveButton'+element.id" :disabled="(sharedStore.state.activeForm != null && sharedStore.state.activeForm != index)" class="btn btn-primary text-white ml-2 mr-2"> <i class="far fa-save"></i> SAVE </button>
                        <button type="button" class="btn bg-secondary text-white ml-2 mr-2" @click="cancelEdit(element, index)"> <i class="fas fa-minus"></i> CANCEL </button>
                    </div>
                </div>
            </form>
        </div>
    </div>
</script>

The component JS looks like this:

const evidenceFormComponent = Vue.component("evidence-form", {
    template: "#evidenceFormTemplate",
    props: [
        "element",
        "sharedStore",
        "index",
        "subdomains",
    ],
    data: function (element) {
        console.log('we are in data setup for : ' + element);
        return {
            isEditing: false,
            evaluation_id: null,
            subdomain: null,
            comments: '',
            published: null,
        };
    },
    created: function () {
        return {
        };
    },
    computed: {
        hideControls: function() {
            if (this.sharedStore.state.addingEvidence) {
                return true;
            }
            if ((this.sharedStore.state.activeForm != null) && !this.isEditing) {
                return true;
            } else {
                return false;
            }
        },
    },
    watch: {},
    methods: {
        editForm: function (element, activeForm, index) {
            this.sharedStore.setOriginalElement(element);
            this.sharedStore.setActiveForm(index);
            this.isEditing = true;
        },
        cancelEdit: function (element, index) {
            this.sharedStore.clearOriginalElement(element);
            this.sharedStore.clearActiveForm();
            this.isEditing = false;
        },

        submitForm: function(absolute_url, evaluationId) {
            var vm = this
            url = absolute_url + "?evaluation_id=" + evaluationId
            console.log($('#subdomain').val());
            console.log($('input[id="subdomain"]').val());
            $.ajax({
                url: url,
                type: 'PATCH',
                data: {
                    evaluation : evaluationId,
                    subdomain : $('#subdomain').val(),
                    comments : $('#comments').val(),
                    published: $('input[name=published]:checked').val(),
                    csrfmiddlewaretoken: vm.sharedStore.state.csrftoken,
                },
                beforeSend: function (xhr, settings) {
                    xhr.setRequestHeader("X-CSRFToken", vm.sharedStore.state.csrftoken);
                },
                success: function (element) {
                    console.log('SUCCESS! Update to element is good.');
                    vm.isEditing = false;
                    vm.sharedStore.clearOriginalElement(element);
                    vm.sharedStore.clearActiveForm();
                }
            })
        },
    },
});

When the template loads up - I see all the values displaying correctly with the right data. When I click 'edit', the form becomes editable as expected.

Once I click submit, there are no values being passed, but I'm using the v-model on the inputs.

Any idea why that would occur?

Hanny
  • 580
  • 3
  • 16
  • 44
  • I edited to include the submitForm method! Sorry, I forgot that! – Hanny Jun 16 '21 at 15:41
  • *I'm using the v-model on the inputs* then use the model in the ajax data, not `$('#subdomain').val()` etc as that's going to find first #subdomain, not the current one in the loop (if #subdomain actually exists, but from your code it doesn't), same with #comments – Lawrence Cherone Jun 16 '21 at 15:46
  • see: [Can multiple different HTML elements have the same ID if they're different elements?](https://stackoverflow.com/questions/5611963/can-multiple-different-html-elements-have-the-same-id-if-theyre-different-eleme) – Lawrence Cherone Jun 16 '21 at 15:48
  • `var vm = this` is horrid, use arrow functions or [bind(this)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind) to the function (better option if your not bundling and want to support IE) – Lawrence Cherone Jun 16 '21 at 15:52
  • Also, are there better explanations as to why to use arrow functions or bind(this) over just writing out 'this'? – Hanny Jun 16 '21 at 16:10

0 Answers0