I am trying to get the value from a data controlled by v-model within a component.
The data changes in the app and in Vue dev tools but if I console log that data I always get the previous value.
Vue App
Here is the data I'm passing to the components
new Vue({
el: "#app",
data: {
"children": {
"haveAnyOtherDependents": 'yes',
"havePets": 'no',
},
},
})
Vue Component
Here I pass the data I need from the app
// button-group component
Vue.component('button-group', {
props: {
title: {
type: String
},
name: {
type: String
},
content: {
type: String
},
dataSource: {
type: String
}
},
data: function () {
return {
myTitle: this.title,
myName: this.name,
myContent: ''
}
},
created(){
this.myContent = this.setMyContent
},
methods: {
sendData: function(){
console.log('data: ', this.myContent, 'source', this.dataSource);
}
},
computed: {
setMyContent: function(){
return this.content
}
},
template: `
<div class="form-group row mb-1">
<br>
<div class="col-sm-6 pt-1 text-md" v-text="myTitle + ' = ' + myContent"></div>
<div class="col-sm-6 text-right">
<div class="btn-group m-0">
<label class="btn mr-05 p-0 rounded-left">
<input type="radio" :name="myName" value="no" v-model="myContent" #click="sendData()">
<span class="d-block p-1 px-3 text-sm rounded-left">
<i class="fas fa-check mr-1 text-xs"></i>No
</span>
</label>
<label class="btn p-0 rounded-right">
<input type="radio" :name="myName" value="yes" v-model="myContent" #click="sendData()">
<span class="d-block p-1 px-3 text-sm rounded-right">
<i class="fas fa-check mr-1 text-xs"></i>Yes
</span>
</label>
<label class="d-none btn p-0">
<input class="d-none" type="radio" :name="myName" value="unknown" v-model="myContent" #click="sendData()" checked>
<span class="d-block p-1 px-3 text-sm">
<i class="fas fa-check d-none mr-1 text-xs"></i>Unknown
</span>
</label>
</div>
</div>
</div>
`
});
// end button-group
HTML
<div id="app" class="container">
<button-group title="Other Dependants" name="other_dependents"
:content="children.haveAnyOtherDependents" data-source="children.haveAnyOtherDependents"></button-group>
<button-group title="Pets" name="pets" :content="children.havePets" data-source="children.havePets"></button-group>
</div>
Here is a fiddle, https://jsfiddle.net/yktoL8oz/
As answered in the comments by #Bert
The click event fires before the model is updated. Use a different event like change"
I changed the #click="sendData()" to #change="sendData()" and that solved the issue.
Related
I have a navbar and login components in vue. So my target is when if the user login, on the dropdown in navbar, I want to show Profile as an item, and if the user is not login I want to show Sign In/Register item as an item. So I want to manipulate the dropdown that you see on the picture below:
And here is my Navbar component:
<template>
<nav class="navbar navbar-expand-lg shadow">
<div class="container navbar-container">
<div class="navbar navbar-profile">
<div class="dropdown">
<button class="btn dropdown-toggle" type="button" id="dropdownProfile" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<i class="fa fa-fw fa-user"></i>
</button>
<ul class="dropdown-menu dropdown-menu-left">
<!-- User is not authenticated so show login/register-->
<li v-if="authenticated"><router-link :to="{ name: 'login' }">Login/Register</router-link></li>
<!-- User is authenticated so show profile-->
<li v-if="authenticated"><router-link :to="{ name: 'profile' }">Profile</router-link></li>
</ul>
</div>
</div>
</div>
</nav>
</template>
<script>
export default {
data() {
return {
authenticated: false,
authenticationFailed: false,
};
},
};
</script>
So in the code I didnt make anything with the authenticated/authenticationFailed values because I dont know how can I check it from the Login component. And here is my login component:
<template>
<div id="login" class="card-container">
<div class="card col-lg-6 col-md-6 col-sm-12 col-xs-12">
<div class="headers">
<h3 class="card-header text-center active">LOGIN</h3>
<router-link :to="{name: 'register'}"><h4 class="card-header text-center non-active">REGISTER</h4></router-link>
</div>
<div class="card-body">
<div class="form-row">
<div class="form-group">
<input type="text" class="form-control" v-model="email" placeholder="Email" id="email" #keyup.enter="signIn" >
</div>
<div class="form-group">
<input type="password" class="form-control" v-model="password" placeholder="Password" id="password" #keyup.enter="signIn">
</div>
<div class="form-group form-check">
<input type="checkbox" id="rememberMeSignIn" class="form-check-input">
<label class="form-check-label" for="rememberMeSignIn">Remember Me</label>
</div>
<div class="form-group links">
<router-link :to="{name: 'forget-password'}">Forget Password?</router-link>
</div>
</div>
<div class="button-area">
<button v-on:click="signIn()" type="submit" class="btn button">Sign In</button>
</div>
</div>
</div>
</div>
</template>
<script>
import authHelper from "../helpers/authHelper";
import GENERAL_APP_CONSTANTS from "../constants/GeneralAppConstants";
export default {
name: 'Login',
beforeMount() {
this.authenticated = authHelper.validAuthentication();
},
mounted() {
EventBus.$on(GENERAL_APP_CONSTANTS.Events.CheckAuthentication, () => {
this.authenticated = authHelper.validAuthentication();
if (this.authenticated) {
this.email = this.password = "";
this.authenticationFailed = false;
}
});
EventBus.$on(GENERAL_APP_CONSTANTS.Events.LoginFailed, () => {
this.authenticationFailed = true
});
},
data () {
return {
authenticated: false,
authenticationFailed: false,
email: '',
password: '',
rememberMe: false,
}
},
methods: {
signIn: function () {
authHelper.signIn(this.email, this.password, () => {
this.$router.push({name: 'home'});
});
}
}
}
</script>
I tried to make it as simple as possible and if you can help me with this , I would be really glad.
PS: this is my index.vue that you can see the relation between Navbar and Login page and my login component is displaying when router-view changed:
<div id="app">
<Topnav/>
<Navbar/>
<router-view></router-view>
<Footer/>
</div>
<template>
<b-form #submit.prevent="Submit" class="mb-5">
<div class="inputArea" v-for="input in inputs" :key="input.id">
<b-form-group label-cols-sm="2" label="Solution (EN)">
<ckeditor :editor="ckeditor" v-model="form.body.en" :config="ckeditorConfig"></ckeditor>
<div v-if="errors['body.en']">
<div v-for="err in errors['body.en']" :key="err">
<small class="text-danger">{{ err }}</small>
</div>
</div>
</b-form-group>
<b-form-group label-cols-sm="2" label="Body (FR)">
<ckeditor :editor="ckeditor" v-model="form.body.np" :config="ckeditorConfig"></ckeditor>
<div v-if="errors['body.np']">
<div v-for="err in errors['body.np']" :key="err">
<small class="text-danger">{{ err }}</small>
</div>
</div>
</b-form-group>
<b-form-group label-cols-sm="2" label="Body (IT)">
<ckeditor :editor="ckeditor" v-model="form.body.in" :config="ckeditorConfig"></ckeditor>
<div v-if="errors['body.in']">
<div v-for="err in errors['body.in']" :key="err">
<small class="text-danger">{{ err }}</small>
</div>
</div>
</b-form-group>
</div>
<b-form-group label="" label-cols-sm="2">
<b-button type="button" class="text-white" variant="dark" #click="addRow">Add row</b-button>
</b-form-group>
<b-form-group label="" label-cols-sm="2">
<b-button type="submit" class="text-white" variant="dark">Submit</b-button>
</b-form-group>
</b-form>
</template>
<style lang="scss">
</style>
<script>
import CKEditor from '#ckeditor/ckeditor5-vue2'
import ClassicEditor from '#ckeditor/ckeditor5-build-classic'
export default {
name: 'Interaction',
components: {
ckeditor: CKEditor.component
},
data(){
return{
counter: 0,
inputs: [
{
en: '',
np: '',
in: '',
}],
form: {
body: [
{
en: '',
np: '',
in: '',
}
],
},
errors: {},
ckeditorData: '<p></p>',
ckeditorConfig: {
// The configuration of the editor
},
ckeditor: ClassicEditor
}
},
methods: {
Submit(){
this.storing = true
this.errors = {}
var self = this
axios.post('/this-is-a-post-url', this.form)
.then(function(response){
console.log(response)
})
},
addRow() {
this.inputs.push({
en: '',
it: '',
fr: '',
id: `${++this.counter}`,
value: '',
});
}
}
}
</script>
I will have array coming in the body name so I am trying to to clone the clone body on a click of a button which has a function AddRow. I want to clone the three fields en,np,in and I want it work like normal html works in this. Example when we clone html form it create input field like so <input name="body['en'][0]"> and when we clone another time it creates something like this <input name="body['en'][1]">.
I have the above code, it clones the body but it also clones the added text before cloning. I want to add an empty field while cloning and also want to update v-model. How can I do that?
Refer below example:
https://codepen.io/telen/pen/OeNZVV
<main class="container">
<form id="app" data-apartments='[{ "price": "23000", "rooms": "12" }, { "price": "42000", "rooms": "32" }]'>
<h1>
Dynamic apartment forms
</h1>
<hr>
<div class="row">
<div class="col-xs-2">
<button type="button" v-on:click="addNewApartment" class="btn btn-block btn-success">
Add +
</button>
</div>
<div class="col-xs-10">
Would you like add more apartments?
</div>
</div>
<div v-for="(apartment, index) in apartments">
<div class="row">
<div class="col-xs-2">
<label> </label>
<button type="button" v-on:click="removeApartment(index)" class="btn btn-block btn-danger">
Rem -
</button>
</div>
<div class="form-group col-xs-5">
<label>Price (HUF)</label>
<input v-model="apartment.price" type="number"
name="apartments[][price]" class="form-control" placeholder="Price">
</div>
<div class="form-group col-xs-5">
<label>Rooms (PCS)</label>
<input v-model="apartment.rooms" type="number"
name="apartments[][rooms]" class="form-control" placeholder="Rooms">
</div>
</div>
</div>
<div class="row">
<div class="col-xs-2">
<button type="submit" v-on:click.prevent="sumbitForm" class="btn btn-block btn-primary">
Submit
</button>
</div>
<div class="col-xs-10">
Open the console (F12) and see the result
</div>
</div>
<hr>
<pre>{{ $data }}</pre>
</form>
JS:
window.app = new Vue({
el: '#app',
data: {
apartment: {
price: '',
rooms: ''
},
apartments: [],
},
mounted: function () {
/*
* The "data-apartments" could come from serverside (already saved apartments)
*/
this.apartments = JSON.parse(this.$el.dataset.apartments)
},
methods: {
addNewApartment: function () {
this.apartments.push(Vue.util.extend({}, this.apartment))
},
removeApartment: function (index) {
Vue.delete(this.apartments, index);
},
sumbitForm: function () {
/*
* You can remove or replace the "submitForm" method.
* Remove: if you handle form sumission on server side.
* Replace: for example you need an AJAX submission.
*/
console.info('<< Form Submitted >>')
console.info('Vue.js apartments object:', this.apartments)
window.testSumbit()
}
}
})
/*
* This is not Vue.js code, just a bit of jQuery to test what data would be submitted.
*/
window.testSumbit = function () {
if (!window.jQuery) {
console.warn('jQuery not present!')
return false
}
console.info('Submitted (serverside) array:', jQuery('form').serializeJSON())
}
I want to access my user details stored in the state when visiting a dynamic (_id.vue) page. I have set the id of the page like this after using the link to the page:
data() {
return {
selectedTutor: null,
id: this.$route.params.id,
}
},
But now I need to define the selectedTutor by searching the id within the data in the vuex state. I was trying to do something like this:
created() {
this.selectedTutor = this.$store.state.tutors.find((tutor) => tutor.id === this.id)
},
But everything stays undefined. So when id equals to the id within the object, that object needs to be set as selectedTutor so I can access all the necessary data to be displayed on the page.
Here you can see the Vuex state
EDIT
_id.vue page
<template>
<div>
<section>
<div>
<h3>
{{ id }}
</h3>
</div>
</section>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'TutorPage',
/* eslint-disable vue/require-prop-types */
layout: 'app',
props: ['id'],
middleware: 'auth',
data() {
return {
selectedTutor: null,
}
},
computed: {
...mapState(['tutors']),
},
created() {
this.selectedTutor = this.$store.state.tutors.find(
(tutor) => tutor.id === this.id
)
},
}
</script>
MainResult Page
<base-grid>
<ul id="tutors" class="grid grid-cols-2 gap-6">
<tutor-item
v-for="tutor in tutors"
:id="tutor.id"
:key="tutor.id"
:name="tutor.attributes.name"
:rate="student.hourlyRate"
:subject="student.subject"
:description="student.biography"
:profile-image="student.imageUrl"
:image-alt="student.imageAlt"
:age="student.age"
:rating="student.rating"
:total-reviews="student.reviewCount"
class="overflow-hidden bg-white border rounded-lg shadow-md"
>
</tutor-item>
</ul>
</base-grid>
Tutor Item (the resultcard)
<template>
<div>
<li>
<div class="flex">
<div class="w-2/3">
<img
class="flex-shrink-0 object-cover w-full h-64 mx-auto bg-gray-200"
:src="profileImage"
:alt="imageAlt"
/>
</div>
<div class="p-6">
<div
class="text-xs font-semibold leading-snug tracking-wide text-gray-500 uppercase"
>
{{ subject }} • {{ age }} jaar
</div>
<NuxtLink :to="'/tutors/' + id">
<h4 class="text-lg font-semibold leading-5 tracking-wide">
{{ name }}
</h4>
</NuxtLink>
<div class="mt-2">
{{ rate }}€
<span class="text-sm text-gray-600">per uur</span>
</div>
<div class="mt-2">
<span class="font-semibold text-light-blue-800"
>{{ rating }}/5 sterren</span
>
<span class="text-sm text-gray-600 truncate">
(na {{ totalReviews }} reviews)
</span>
</div>
<div class="mt-2">{{ description }}</div>
<div>
<div class="mt-4 text-sm font-semibold text-gray-600">
<span>MA</span>
<span
class="inline-block leading-7 text-center text-gray-100 bg-yellow-400 bg-opacity-50 w-7 h-7 rounded-xl"
>DI</span
>
<span>WO</span>
<span
class="inline-block leading-7 text-center text-gray-100 bg-yellow-400 bg-opacity-50 w-7 h-7 rounded-xl"
>DO</span
>
<span
class="inline-block leading-7 text-center text-gray-100 bg-yellow-400 bg-opacity-50 w-7 h-7 rounded-xl"
>VR</span
>
<span>ZA</span>
<span>ZO</span>
</div>
</div>
</div>
</div>
</li>
</div>
</template>
<script>
export default {
/* eslint-disable vue/require-prop-types */
name: 'TutorItem',
props: [
'id',
'firstName',
'lastName',
'name',
'rate',
'subject',
'age',
'rating',
'totalReviews',
'description',
'profileImage',
'imageAlt',
],
computed: {
fullName() {
return this.firstName + ' ' + this.lastName
},
tutorsDetailsLink() {
return this.$route.path + '/' + this.id
},
},
}
</script>
<style></style>
EDIT
Whoops, what a mistake. It was returning the id as a string but I needed a number. This is why it returned undefined. It is solved now! Thanks
I am working on Vue.JS and I tried to use local-storage with it to save data. In my code, I can store and retrieve all data with local-storage except line-through effect. Here, I am trying to store actual boolean value of line-through effect in local-storage and want to retrieve that value on to-do list app.
<title>To Do List</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js'></script>
<style>
.taskDone {
text-decoration: line-through;
}
</style>
</head>
<body>
<div id="todo-list" class="container">
<div class="container col-sm-8 col-sm-offset-2">
<h1 class="text-center"> <big><b> To Do List </b> </big></h1>
<h5 class="text-center"> <span v-show="itemsTodo.length"> ({{ itemsTodo.length }} pending) </span></h5>
<div class="col-md-8">
<button v-if="state === 'default'" class="btn btn-primary" #click="changeState('edit') ">Add Item</button>
<button v-else class="btn btn-info" #click="changeState('default')">Cancel</button>
</div>
<br>
<br>
<div v-if="state === 'edit'" >
<div class="col-sm-4">
<input class='form-control' v-model="newItem" type="text" placeholder="Type here" #keyup.enter="saveItem" >
</div>
<div class="col-sm-4">
<input class="form-control" v-model="newdate" type="date" type="text"/>
</div>
<div class="col-sm-4">
<button class='btn btn-primary btn-block' v-bind:disabled="newItem.length === 0"#click= "saveItem">Save Item</button>
</div>
</div>
<br>
<br>
<ul type="none" class="list-group">
<li class="list-group-item" v-for="(item,index,date) in items" :class="{taskDone : item.completed}" >
<h4>
<input type="checkbox" v-model="item.completed" #click="item.completed = !item.completed">
<button class="btn btn-primary " #click.stop="removeitems(index)">× </button>
<b><i> {{ item.label }} {{ item.date }} </i></b></h4>
</li>
</ul>
<h2 v-if="items.length === 0">Nice Job! Nothing in TO DO LIST</h2>
<div class="col-sm-4">
<button class="btn btn-warning btn-block" #click="clearcompleted"> Clear Completed</button>
</div>
<div class="col-sm-4">
<button class="btn btn-danger btn-block" #click="clearAll"> Clear All</button>
</div>
</div>
</div>
2. Vue.JS code
<script src="https://unpkg.com/vue" ></script>
<script>
var todolist = new Vue({
el: '#todo-list',
data : {
state : 'edit',
header: 'To Do List',
newItem: '',
newdate: '',
items: [
{
label:'coffee',
completed:false,
date:'2019-06-20' ,
},
{
label:'tea',
completed:false,
date:'2019-06-19' ,
},
{
label:'milk',
completed:false,
date:'2019-06-19' ,
},
]
},
computed:{
itemsDone(){
return this.items.filter(items => items.completed)
},
itemsTodo(){
return this.items.filter(items =>! items.completed)
},
},
methods:{
saveItem: function(){
if (this.newItem != ''){
this.items.push({
label:this.newItem,
completed: false,
date : this.newdate,
});
this.newItem = '';
this.newdate = '';
}},
changeState: function(newState){
this.state = newState;
this.newItem = '';
this.newdate = '';
},
removeitems(index){
this.items.splice(index,1);
},
clearcompleted (){
this.items = this.itemsTodo;
},
clearAll: function(){
this.items = [ ];
},
},
mounted(){
console.log('App Mounted!');
if (localStorage.getItem('items')) this.items = JSON.parse(localStorage.getItem('items'));
},
watch: {
items:{
handler(){
localStorage.setItem('items',JSON.stringify(this.items));
},
},
},
});
</script>
I expect correct boolean value of line-through effect to be stored in local-storage. So that, appropriate effect will show on browser.
You are just watching items. If you change something in a item (in your case completed) the handler will not be called and your change is not stored.
You could use a "deep" watcher but i suggest to call your save logic whenever you changed something.
My modal box is inside of a vue component. When the data is submitted, I want the component to send back the response data to the parent so I can append it to the root element.
The component
<template>
<div v-if="value.startsWith('new')">
<!-- Create Client Modal -->
<div class="modal show" id="modal-create-client" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button " class="close" data-dismiss="modal" aria-hidden="true" #click.prevent="close">×</button>
<h4 class="modal-title">Details</h4>
</div>
<div class="modal-body">
<!-- Form Errors -->
<div class="alert alert-danger" v-if="createForm.errors.length > 0">
<p><strong>Whoops!</strong> Something went wrong!</p>
<br>
<ul>
<li v-for="error in createForm.errors">
{{ error }}
</li>
</ul>
</div>
<!-- Create Client Form -->
<form class="form-horizontal" role="form">
<!-- Name -->
<div class="form-group">
<label class="col-md-3 control-label">First Name</label>
<div class="col-md-7">
<input id="create-client-name" type="text" class="form-control" #keyup.enter="store" v-model="createForm.first">
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">Last Name</label>
<div class="col-md-7">
<input type="text" class="form-control" name="last" #keyup.enter="store" v-model="createForm.last">
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">Email</label>
<div class="col-md-7">
<input type="text" class="form-control" name="organization" #keyup.enter="store" v-model="createForm.email">
<span class="help-block">Email is required for invoices</span>
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">Organization</label>
<div class="col-md-7">
<input type="text" class="form-control" name="organization" #keyup.enter="store" v-model="createForm.organization">
</div>
</div>
</form>
</div>
<!-- Modal Actions -->
<div class="modal-footer" v-if="value == 'newClient'">
<button type="button" class="btn btn-default" data-dismiss="modal" #click.prevent="close">Close</button>
<button type="button" class="btn btn-primary" #click="storeClient">Create</button>
</div>
<div class="modal-footer" v-else-if="value == 'newLead'">
<button type="button" class="btn btn-default" data-dismiss="modal" #click.prevent="close">Close</button>
<button type="button" class="btn btn-primary" #click="storeLead">Create</button>
</div>
<div class="modal-footer" v-else-if="value == 'newContact'">
<button type="button" class="btn btn-default" data-dismiss="modal" #click.prevent="close">Close</button>
<button type="button" class="btn btn-primary" #click="storeContact">Create</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
createForm: {
errors: [],
first: '',
last: '',
email: '',
organization: ''
},
};
},
props: ['value'],
/**
* Prepare the component (Vue 1.x).
*/
ready() {
this.prepareComponent();
},
/**
* Prepare the component (Vue 2.x).
*/
mounted() {
var vm = this
this.prepareComponent();
},
methods: {
/**
* Prepare the component.
*/
prepareComponent() {
$('#modal-create-client').on('shown.bs.modal', () => {
$('#create-client-name').focus();
});
$("#modal-create-client").on("hide.bs.modal", function(e) {
$(this).removeData('bs.modal');
});
},
close() {
$('#modal-create-client').removeClass('show');
},
/**
* Create a new client for the user.
**/
storeClient() {
this.persistClient(
'post', './clients/add',
this.createForm, '#modal-create-client'
);
},
storeLead() {
this.persistClient(
'post', './leads/add',
this.createForm, '#modal-create-client'
);
},
storeContact() {
this.persistClient(
'post', './contacts/add',
this.createForm, '#modal-create-client'
);
},
/**
* Persist the client to storage using the given form.
*/
persistClient(method, uri, form, modal) {
form.errors = [];
this.$http[method](uri, form).then(response => {
location.reload();
$(modal).modal('hide');
}).catch(response => {
if (typeof response.data === 'object') {
form.errors = _.flatten(_.toArray(response.data));
} else {
form.errors = ['Something went wrong. Please try again.'];
}
});
},
watch: {
value: function (value) {
// update value
$(this.$el).val(value)
},
}
}
}
</script>
The root Element
var MyComponent = Vue.component('my-ajax-component',
require('./components/Toolbar.vue') );
new Vue({
el: '#select',
data: {
selected: ''
},
components: {
// <my-component> will only be available in parent's template
'my-ajax-component': MyComponent
}
});
and my view
<div class="form-group clearfix">
<div class="col-xs-12" id="select">
{!! Form::label('client_id', 'Choose Client:', ['class' => 'control-label']) !!}
{!! Form::select('client_id', ['newClient' => 'New Client', $clients], null, ['title' => 'Select Client', 'class' => 'form-control selectpicker', 'v-model' => 'selected', 'data-live-search' => 'true']) !!}
<br>
<my-ajax-component v-bind:value="selected"></my-ajax-component>
</div>
</div>
Instead of location reload I want to append the response data to the select element which is my roo
I changed my root element to
new Vue({
el: '#select',
data: {
selected: '',
data: ''
},
components: {
// <my-component> will only be available in parent's template
'my-ajax-component': MyComponent
},
methods: {
handler: function(data) {
console.log('this is my data' + data)
}
}
my component now has
this.$emit('data-received',response)
and put v-on in the child component
<my-ajax-component v-bind:value="selected" v-on:data-received='handler(data)'></my-ajax-component>
I get data undefined or nothing
I can see the data returned in the post .. it's the id of my object ...should I json encode it
The easiest way can be to emit the event with data in child component when you get the response.
In child:
this.$emit('data-received',response)
In parrent:
<child-component v-on:data-received='handler(data)'>
In handler function in parrent, do whatever you want with data.
UPDATED:
Your backend should return JSON to follow REST Api standards.
Every endpoint of API should return JSON, even if it is simple string.
Instead of
In parrent:
<child-component v-on:data-received='handler(data)'>
I used In parrent:
<child-component v-on:data-received='handler'>