Vue3 Button not functioning - undefined property

Viewed 50

I'm having issues with a non-functioning button on the screenshot below, hopefully you can help.

Button functionality

The button itself doesn't click, yet I can successfully submit the data by pressing Enter. Inspect shows an error 'Cannot read propertises of undefined (reading 'forEach'). The code for these is below, there's only 2 instances - this is the instance on line 255:

      getData() {
    const data = {
      questions: [],
      answers: []
    }

    this.questions.forEach(question => {
      if (question.title) {
        let answer = question.answer
        if (Array.isArray(answer)) {
          answer = answer.join(', ')
        }

        data.questions.push(question.title)
        data.answers.push(answer)
      }
    })

    return data
  }

and at line 220:

onSendData(questionList) {
    // Set `submitted` to true so the form knows not to allow back/forward
    // navigation anymore.

    const QuestionsArray = []

    questionList.forEach(question => {
      QuestionsArray.push(question.answer)
    })

    this.$refs.flowform.submitted = true

    this.submitted = false

The code for the button itself:

 <template v-slot:completeButton>
     <div class="f-submit" v-if="!submitted">
         <button class="o-btn-action"
                 ref="button"
                 type="submit"
                 href="#"
                 v-on:click="onSendData(questionList)"
                 aria-label="Press to submit">
             <span>{{ language.submitText }}</span>
         </button>
         <a class="f-enter-desc"
            href="#"
            v-on:click="onSendData(questionList)"
            v-html="language.formatString(language.pressEnter)">
         </a>
     </div>

     <p class="text-success" v-if="submitted">Submitted succesfully.</p>
 </template>
</flow-form>

Funnily enough, I can only replicate this issue when using this Vue repo with another in the same stack, when I deploy it standalone, it works fine!

Full code:

    <template>
  <div>
    <header class="vff-header">
      <div class="f-container">
       <!-- Add custom logo here -->
        <svg class="f-logo" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMid meet" viewBox="0 0 35.606 11.211">
          <path d="M.134.837H3.21V8.01h4.203v2.18H.134V.837z"/>
          <path d="M11.875.59c1.48 0 2.668.448 3.567 1.344s1.35 2.052 1.35 3.47c0 1.48-.445 2.7-1.336 3.632S13.38 10.45 11.9 10.45c-1.678 0-2.954-.54-3.827-1.622-.717-.9-1.08-2.022-1.09-3.397-.01-1.36.39-2.484 1.193-3.374C9.06 1.08 10.292.59 11.875.59zm0 2.283c-.563 0-1.003.222-1.323.662-.338.467-.507 1.124-.507 1.972 0 .865.162 1.524.487 1.978a1.58 1.58 0 0 0 1.369.682c.588 0 1.04-.223 1.355-.668s.474-1.07.474-1.875c0-1.834-.62-2.75-1.855-2.75z"/>
          <path d="M21.565 7.078V5.055h4.217v5.163h-1.986l-.13-.908c-.693.76-1.617 1.142-2.777 1.142-1.383 0-2.488-.437-3.313-1.3s-1.243-2.03-1.252-3.464c-.01-1.462.385-2.65 1.18-3.567.875-1.012 2.11-1.518 3.7-1.518 1.21 0 2.207.303 3 .907s1.264 1.457 1.447 2.556h-2.92c-.207-.787-.73-1.182-1.57-1.182-.553 0-.988.236-1.303.707s-.475 1.153-.475 2.043c0 1.695.652 2.542 1.96 2.542.363 0 .695-.103.998-.306a1.29 1.29 0 0 0 .572-.784h-1.35v.002z"/>
          <path d="M30.556.59c1.48 0 2.668.448 3.568 1.344s1.348 2.052 1.348 3.47c0 1.48-.443 2.7-1.336 3.632S32.06 10.45 30.58 10.45c-1.678 0-2.953-.54-3.826-1.622-.72-.892-1.082-2.022-1.1-3.398-.008-1.357.39-2.48 1.193-3.372C27.74 1.08 28.974.59 30.556.59zm0 2.283c-.563 0-1.002.222-1.322.662-.336.467-.506 1.125-.506 1.972 0 .865.162 1.524.486 1.978s.78.682 1.37.682 1.04-.223 1.355-.668.475-1.07.475-1.875c-.002-1.834-.62-2.75-1.857-2.75z"/>
        </svg>
      </div>
    </header>

    <flow-form
      ref="flowform"
      v-on:complete="onComplete"
      v-on:submit="onSubmit"
      v-bind:questions="questions"
      v-bind:language="language"
      v-bind:standalone="true"
    >
    <!-- Custom content for the Complete/Submit screen slots in the FlowForm component -->
      <!-- We've overriden the default "complete" slot content -->
     <template v-slot:complete>
        <div class="f-section-wrap">
          <p>
            <span class="fh2">Thank you. </span>
            <span class="f-section-text">
              Great work, the survey is completed, and our mint is done. You can review your answers or press submit.
            </span>
          </p>
          <p class="f-description">Note: No data will be saved and/or sent in this demo.</p>
        </div>  
      </template>

      <!-- We've overriden the default "completeButton" slot content -->
     <template v-slot:completeButton>
         <div class="f-submit" v-if="!submitted">
             <button class="o-btn-action"
                     ref="button"
                     type="submit"
                     href="#"
                     v-on:click="onSendData(questionList)"
                     aria-label="Press to submit">
                 <span>{{ language.submitText }}</span>
             </button>
             <a class="f-enter-desc"
                href="#"
                v-on:click="onSendData(questionList)"
                v-html="language.formatString(language.pressEnter)">
             </a>
         </div>

         <p class="text-success" v-if="submitted">Submitted succesfully.</p>
     </template>
    </flow-form>
  </div>
</template>

<script>
  /*
    Copyright (c) 2020 - present, DITDOT Ltd. - MIT Licence
    https://www.ditdot.hr/en
  */

  // Import necessary components and classes
  import FlowForm from '../../src/components/FlowForm.vue'
  import QuestionModel, { QuestionType, ChoiceOption, LinkOption } from '../../src/models/QuestionModel'
  import LanguageModel from '../../src/models/LanguageModel'
  // If using the npm package, use the following line instead of the ones above.
  // import FlowForm, { QuestionModel, QuestionType, ChoiceOption, LanguageModel } from '@ditdot-dev/vue-flow-form'

  export default {
    name: 'example',

    components: {
      FlowForm
    },

    data() {
      return {
        submitted: false,
        completed: false,
        language: new LanguageModel(),
        // Create question list with QuestionModel instances
        questions: [
          new QuestionModel({
            id: 'MC1',
            tagline: 'First MC question',
            title: 'Interests, select all relevant:',
            helpTextShow: false,
            type: QuestionType.MultipleChoice,
            multiple: true,
            allowOther: true,
            required: true,
            options: [
              new ChoiceOption({
                label: 'Cars'
              }),
              new ChoiceOption({
                label: 'Sports'
               }),
              new ChoiceOption({
                label: 'Animals'
              })
            ]
          }),
          new QuestionModel({
            id: 'MC2',
            title: 'Colours now:',
            type: QuestionType.MultipleChoice,
            multiple: true,
            helpText: 'Select all that you like. ',
            required: true,
            options: [
              new ChoiceOption({
                label: 'Blue'
              }),
              new ChoiceOption({
                label: 'Red'
              }),
              new ChoiceOption({
                label: 'Green'
              }),
              new ChoiceOption({
                label: 'Yellow'
              })
            ]
          }),
                    new QuestionModel({
                        id: 'choose_path',
                        tagline: 'Where would you like answer on hobbies? ',
                        title: 'Hobby choice:',
                        type: QuestionType.Dropdown,
                        multiple: false,
                        placeholder: 'Select',
                        inline: true,
                        required: true,
                        options: [
                            new ChoiceOption({
                                label: 'No more questions',
                                value: 'path_a'
                            }),
                            new ChoiceOption({
                                label: 'Go to Hobbies',
                                value: 'path_b'
                            })
                        ],
                        jump: {
                            path_b: 'path_b'
                        }
                    }),
                    new QuestionModel({
                        id: 'path_a',
                        title: 'Fine, lets finish! ',
                        content: 'Press enter or use the continue button for the final submit screen.',
                        type: QuestionType.SectionBreak,
                        jump: {
                            _other: '_submit'
                        }
                    }),
                    new QuestionModel({
                        id: 'path_b',
                        tagline: 'Hobbies',
                        title: 'Do you like the below?',
                        helpTextshow: false,
                        type: QuestionType.MultipleChoice,
                        multiple: false,
                        required: true,
                        options: [
                            new ChoiceOption({
                                label: 'Snooker',
                            }),
                            new ChoiceOption({
                                label: 'Fishing'
                            })
                        ],
                        jump: {
                            path_a: 'path_a'
                        }
                    })
                ]
            }
        },

    mounted() {
      document.addEventListener('keyup', this.onKeyListener)
    },

    beforeUnmount() {
      document.removeEventListener('keyup', this.onKeyListener)
    },

    methods: {
      onKeyListener($event) {
        // We've overriden the default "complete" slot so
        // we need to implement the "keyup" listener manually.

        if ($event.key === 'Enter' && this.completed && !this.submitted) {
          this.onSendData(questionList)
        }
      },

      /* eslint-disable-next-line no-unused-vars */
      onComplete(completed, questionList) {
        // This method is called whenever the "completed" status is changed.
        this.completed = completed
      },

      /* eslint-disable-next-line no-unused-vars */
      onSubmit(questionList) {
        // This method will only be called if you don't override the
        // completeButton slot.

        this.onSendData(questionList)
      },
      
      onSendData(questionList) {
        // Set `submitted` to true so the form knows not to allow back/forward
        // navigation anymore.

        const QuestionsArray = []

        questionList.forEach(question => {
          QuestionsArray.push(question.answer)
        })

        this.$refs.flowform.submitted = true

        this.submitted = false

        /* eslint-disable-next-line no-unused-vars */
        const data = this.getData()
        //console.log(email)

          fetch('https://auth-32463-default-rtdb.europe-west1.firebasedatabase.app/test.json', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            Q1: QuestionsArray[0],
            Q2: QuestionsArray[1],
            Q3: QuestionsArray[2],
            Q4: QuestionsArray[3],

          })
        });
        },

      getData() {
        const data = {
          questions: [],
          answers: []
        }

        this.questions.forEach(question => {
          if (question.title) {
            let answer = question.answer
            if (Array.isArray(answer)) {
              answer = answer.join(', ')
            }

            data.questions.push(question.title)
            data.answers.push(answer)
          }
        })

        return data
      }
    }
  }
</script>

<style lang="css">
  @import '../../src/assets/css/themes/theme-minimal.css';
  /* If using the npm package, use the following lines instead of the one above */
  /* @import '~@ditdot-dev/vue-flow-form/dist/vue-flow-form.css'; */
  /* @import '~@ditdot-dev/vue-flow-form/dist/vue-flow-form.theme-minimal.css'; */
</style>
1 Answers

I think there is a problem on your onKeyListener when you call the this.onSendData function you're only passing questionList you need to use this.questionList. And on the onSubmit function check if you're receiving the list correctly too.

Related