Данные ответа из сценария php недоступны в экземпляре ROOT Vue - PullRequest
0 голосов
/ 12 января 2020

У меня есть vuejs компонент для модального окна. Когда пользователь заполняет все данные в полях, которые я хочу:

  1. Чтобы отправить данные на сервер.
  2. Установите время ожидания для визуализации для пользователя, что данные отправляются (примените класс fa-spin для кнопка).
  3. Закрыть модальное окно.
  4. Получить ответ от сервера (php контроллер с сообщением об успешном завершении).
  5. Показывать пользователю блок предупреждения о том, что сообщение отправлено.

Теперь у меня проблемы с пунктами 2, 4 и 5. Тайм-аут не работает, и модальное окно закрывается немедленно. Данные ответов из сценария php недоступны в экземпляре ROOT Vue. Я могу видеть ответ сервера только внутри компонента, но не знаю, как передать его в ROOT.

views \ layout.blade. php

                <div v-if="FreeZamerSent" class="alert alert-dismissible fade show" :class="class" role="alert">
                  @{{ message }}
                  <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                  </button>
                </div>


<freezamermodal v-if="showFreeZamerModal" @close="showFreeZamerModal = false" @sent="onFreeZamerSent(response)"></freezamermodal>

App \ Http \ Controllers \ MainController. php

    public function freezamer(Request $request) {

        request()->validate([
            'customer_name' => 'required',
            'customer_email' => 'required|email',
            'customer_phone' => 'required'
        ]);

        Mail::to( env('MAIL_TO_ADDRESS') )->send(new FreeZamer());

        return [
            'message' => 'Ваша заявка отправлена! В ближайшее время мы свяжемся с вами.', 
            'alertclass' => 'alert-success', 
                ];
    }

resources \ js \ components \ FreeZamerModal. vue

<template>

<div class="modal is-active" id="FreezamerModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  <div class="modal-dialog modal-dialog-centered" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h4 class="modal-title" id="myModalLabel">Заказать бесплатный замер</h4>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close" @click="$emit('close')">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
        <form method="POST" action="/freezamer" @submit.prevent="onSubmit">
          <input type="hidden" name="_token" :value="csrf">
          <div class="modal-body">
              <input type="hidden" class="form-control" name="formname" :value="formname">
              <input type="hidden" class="form-control" name="currentUrl" :value="currentUrl">
              <div class="error" v-if="!$v.customer_name.required">Введите имя</div>
              <div class="error" v-if="!$v.customer_name.minLength">Имя должно содержать минимум {{$v.customer_name.$params.minLength.min}} буквы.</div>
              <div class="error" v-if="!$v.customer_name.cyrillic">Имя должно состоять только из русских букв</div>
              <input type="text" class="form-control" name="customer_name" placeholder="Ваше имя" :class="{ 'form-control--error': $v.customer_name.$error }" v-model.trim="$v.customer_name.$model">

              <div class="error" v-if="!$v.customer_email.required">Введите email</div>
              <div class="error" v-if="!$v.customer_email.email">Введите существующий email</div>
              <input type="text" class="form-control" name="customer_email" placeholder="Ваш e-mail" :class="{ 'form-control--error': $v.customer_email.$error }" v-model.trim="$v.customer_email.$model">

              <div class="error" v-if="!$v.customer_phone.required">Введите номер телефона</div>
              <div class="error" v-if="!$v.customer_phone.minLength">Телефон должен содержать 11 цифр.</div>
              <input type="tel" class="form-control" name="customer_phone" placeholder="Ваш телефон" :class="{ 'form-control--error': $v.customer_phone.$error }" v-model.trim="$v.customer_phone.$model" v-mask="'+# (###) ###-##-##'">
          </div>
          <div class="modal-footer">

            <button class="button button_fill" type="submit" :disabled="$v.$invalid">
              <svg v-if="!success"><use xlink:href="#plan"></use></svg>
              <i class="fa fa-spinner fa-spin" v-if="success"></i>
              <span>Бесплатный замер</span>
            </button>

          </div>
        </form>
    </div>
  </div>
</div>

</template>

<script>
    import { alpha, email, helpers, maxLength, minLength, numeric, required } from 'vuelidate/lib/validators';
    import {mask} from 'vue-the-mask';
    export const cyrillic = helpers.regex('cyrillic', /^[А-Яа-яёЁ\s]+$/);

    export default {
        name: "FreeZamerModal",

        data: function () {
          return {
            currentUrl: window.location.pathname,
            csrf: document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
            formname: 'freezamer',
            customer_name: '',
            customer_email: '',
            customer_phone: '',
            success: false,
            errors: []
          }
        },

        directives: {mask},

        methods: {
          onSubmit () {
            axios.post('/freezamer', this.$data)
            .then(this.onSuccess)
            .catch(error => this.errors = error.response.data);
          },

          onSuccess (response) {
            this.success = true;
            setTimeout(5000);
            this.$emit('sent', response);
          },

        },

        mounted() {
           console.log('Freezamer component mounted.')
        },

        validations: {
          customer_name: {
            required,
            cyrillic,
            minLength: minLength(3)
          },
          customer_email: {
            required,
            email
          },
          customer_phone: {
            required,
            minLength: minLength(18),
            maxLength: maxLength(18)
          }

        }

    }
</script>

resources \ js \ app. js

Vue.component('freezamermodal', require('./components/FreeZamerModal.vue').default);


const app = new Vue({
    el: '#app',

    data: {
        showFreeZamerModal: false,
        FreeZamerSent: false,
        message: '',
        alertclass : '',
    },

    methods: {
        onFreeZamerSent (response) {
            this.showFreeZamerModal = false,
            this.FreeZamerSent = true,
            this.message = this.response.message,
            this.alertclass = this.response.alertclass
        },

    },



});

Вместо этого у меня есть ошибки в консоли

[Vue warn]: Property or method "response" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property.

[Vue warn]: Error in v-on handler: "TypeError: Cannot read property 'message' of undefined"

found in

---> <FreeZamerModal> at resources/js/components/FreeZamerModal.vue
       <Root>

1 Ответ

0 голосов
/ 12 января 2020

Шаг за шагом я нашел проблему с помощью vue -devtools. Следующий код this.$emit('sent', response) передает большой объект ответа в ROOT экземпляр и для доступа к response.data рабочее решение следующее. Единственный недостаток - я не могу понять, почему setTimeout не работает. Действие this.$emit('sent', response) запускается сразу, а не через 5 секунд. Через 5 секунд я вижу ошибку в консоли. Если время ожидания истекло, все работает.

resources \ js \ components \ FreeZamerModal. vue

          onSuccess (response) {
            this.success = true;
            setTimeout(this.$emit('sent', response), 5000);
          },

resources \ js \ app. js

    data: {
        showFreeZamerModal: false,
        FreeZamerSent: false,
        message: '',
        alertclass: ''
    },
    methods: {
        onFreeZamerSent (response) {
            this.showFreeZamerModal = false,
            this.FreeZamerSent = true,
            this.message = response.data.message,
            this.alertclass = response.data.alertclass
        },

blade. php

<freezamermodal v-if="showFreeZamerModal" @close="showFreeZamerModal = false" @sent="onFreeZamerSent"></freezamermodal>

ошибка в консоли, появляющаяся через 5 секунд

VM27172:1 Uncaught SyntaxError: Unexpected identifier
setTimeout (async)
onSuccess @ FreeZamerModal.vue?0b2e:81
Promise.then (async)
onSubmit @ FreeZamerModal.vue?0b2e:75
submit @ FreeZamerModal.vue?b9fb:63
invokeWithErrorHandling @ vue.common.dev.js?4650:1859
invoker @ vue.common.dev.js?4650:2184
original._wrapper @ vue.common.dev.js?4650:7543

...