I have vuejs component for modal window. When user fill all the data in the fields I want:
- To send data to server.
- Set timeout to visualize for user that data is sending (apply fa-spin class to button).
- Close modal window.
- Receive answer from server (php controller with success message).
- Show alert-block to user that message is sent.
Now I have problems with points 2, 4 and 5. Timeout is not working and modal window is closed immediately. Response data from php script is not available in ROOT Vue instance. I can see server response only inside component, but I don't know how to pass it to 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">×</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">×</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
},
},
});
Instead I have errors in console
[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>