Vue.js Component emit - vue.js

I have some problem about component $emit
This is my child component:
<template>
<div class="input-group mb-3 input-group-sm">
<input v-model="newCoupon" type="text" class="form-control" placeholder="code">
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="button" #click="addCoupon">comfirm</button>
</div>
</div>
</template>
<script>
export default {
props: ["couponcode"],
data() {
return {
newCoupon: this.couponcode
};
},
methods: {
addCoupon() {
this.$emit("add", this.newCoupon);
}
}
};
</script>
This is parent component
<template>
<div>
<cartData :couponcode="coupon_code" #add="addCoupon"></cartData>
</div>
</template>
<script>
import cartData from "../cartData";
export default {
components: {
cartData
},
data() {
return {
coupon_code: ""
}
},
methods:{
addCoupon() {
const api = `${process.env.API_PATH}/api/${
process.env.CUSTOM_PATH
}/coupon`;
const vm = this;
const coupon = {
code: vm.coupon_code
};
this.$http.post(api, { data: coupon }).then(response => {
console.log(response.data);
});
},
}
}
</script>
When I click the 'confirm' button,the console.log display 'can't find the coupon' 。 If I don't use the component,it will work 。
What is the problem? It's about emit?

addCoupon() {
this.$emit("add", this.newCoupon); // You emitted a param
}
// then you should use it in the listener
addCoupon(coupon) { // take the param
const api = `${process.env.API_PATH}/api/${
process.env.CUSTOM_PATH
}/coupon`;
const coupon = {
code: coupon // use it
};
this.$http.post(api, { data: coupon }).then(response => {
console.log(response.data);
});
},

Related

How can I use the method from other component

I want use the method 'pause()' in the component 'vue-count-to',but the webstorm tips Unresolved function or method pause() .How can I use the method in 'vue-count-to'?Thank you
<template>
<div>
<countTo ref="countTo1" :startVal='startVal' :endVal='endVal' :duration='3000'>
</countTo>
<input type="text" v-model="endVal">
<Button v-on:click="handleClick" >reset</Button>
</div>
</template>
<script>
import CountTox from 'vue-count-to';
export default {
components: {
countTo: CountTox},
data () {
return {
startVal: 0,
endVal: 2017,
autoplay: false
}
},
methods: {
handleClick() {
this.$refs.countTo1.pause();
}
}
}
</script>
you can use $root.$emit() and $root.$on()
const componentA = {
template: `
<button #click="callMethodInComponentB">
call method in component-b
</button>
`,
methods: {
callMethodInComponentB() {
this.$root.$emit('call-to-component-b', 2);
}
}
}
const componentB = {
template: `
<h1>Value: {{ value.toString() }}</h1>
`,
data(){
return {
value: 0
}
},
methods: {
plus(add) {
this.value += add
}
},
mounted() {
this.$root.$on('call-to-component-b', add => {
this.plus(add)
});
}
};
new Vue({
el: '#app',
components: {
componentA,
componentB
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<main id="app">
<component-a></component-a>
<component-b></component-b>
</main>
define the method in App.vue and access it from probs and emit

Why Vue doesn't refresh list using props?

On my App, on mounted() method, I call an API, which give to me a JSON with a list of items; than, I update the prop I've set in my target Homepage component:
Homepage.pages = resJSON.data.pages;
Here's the App code:
<template>
<div id="app">
<Homepage title="PWA Test"/>
</div>
</template>
<script>
import Homepage from './components/Homepage.vue'
export default {
name: 'App',
components: {
Homepage
},
mounted() {
let endpoint = "http://localhost:5000/api/graphql?query={pages(orderBy:{contentItemId:asc}){contentItemId,createdUtc,author,displayText,description%20}}";
fetch(endpoint, {
method:'GET',
headers: {
'Accept':'application/json',
'Content-Type':'application/json'
}
})
.then((response) => {
// check for HTTP failure
if (!response.ok) {
throw new Error("HTTP status " + response.status);
}
// read and parse the JSON
return response.json();
})
.then((res) => {
Homepage.pages = res.data.pages;
})
.catch((error) => {
console.log(error);
});
}
}
</script>
<style>
</style>
Here's the Homepage component:
<template>
<div id="homepage">
<h1>{{ title }}</h1>
<ul>
<li v-for="page in pages" :key="page.description">#{{ page.description }}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'Homepage',
props: {
title: String,
pages: []
}
}
</script>
<style scoped>
</style>
But the ul doesn't update after receiving the JSON and updating the props pages. Where's my error?
you need to get the response.json(); in a data property of the App and then pass it down to the Homepage component. So your code should you look like this,
App code:
<template>
<div id="app">
//binding page into data property
<Homepage title="PWA Test" :pages="pages"/>
</div>
</template>
<script>
import Homepage from './components/Homepage.vue'
export default {
name: 'App',
data: function () {
return {
//data propety
pages : []
}
},
components: {
Homepage
},
mounted() {
let endpoint = "http://localhost:5000/api/graphql?query={pages(orderBy:{contentItemId:asc}){contentItemId,createdUtc,author,displayText,description%20}}";
fetch(endpoint, {
method:'GET',
headers: {
'Accept':'application/json',
'Content-Type':'application/json'
}
})
.then((response) => {
if (!response.ok) {
throw new Error("HTTP status " + response.status);
}
// assign the result to the data property
this.page = response.json();
})
.then((res) => {
Homepage.pages = res.data.pages;
})
.catch((error) => {
console.log(error);
});
}
}
</script>
Do you pass the props in a template after this.pages = res.data.pages?
<Homepage :pages="pages" />
I think there are some mistakes that you have done in your code, if you want change update prop value then you have to initialized your props values in script.
<template>
<div id="homepage">
<h1>{{ title }}</h1>
<ul>
<li v-for="page in currentPages" :key="page.description">#{{ page.description }}
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'Homepage',
props: {
title: String,
pages: []
}
data: function () {
return {
currentPages: this.pages
}
}
}
</script>
I hope this will help you to solve your issue- thanks!

vue js sync modifier doesn't update the input value

I have a beginner question about sync modifier in vuejs. In my example, i want to change the value of inputs depending on focus event. The value is an Object inputsData and i'm getting it from the app. In parent i'm passing it to the child where it is rendering. I set an timer because i want to emit an server request. As you can see in the handleFocusFromChild Methode it change me the dataToBeChanged with newData (se also log after 4 seconds). As i understood from vue guid it should to update also the input value but it doens't, and i don't understand why, because dataToBeChanged have now the new values from newData. Can someone explain me why and how should i do to make it work?
Here i'm using the the Parent:
import Parent from "./parent.js";
Vue.component("app", {
components: {
Parent
},
template: `
<div>
<parent :inputsData="{
'firstElement':{'firstInputValue':'Hi there'},
'secondElement':{'secondInputValue':'Bye there'}
}"></parent>
</div>
`
});
Here is the Parent:
import Child from "./child.js";
export default {
name: "parent",
components: {
Child
},
props: {
inputsData: Object
},
template: `
<div>
<child #focusEvent="handleFocusFromChild"
:value.sync="inputsData.firstElement.firstInputValue"></child>
<child #focusEvent="handleFocusFromChild"
:value.sync="inputsData.secondElement.secondInputValue"></child>
</div>
`,
computed: {
dataToBeChanged: {
get: function() {
return this.inputsData;
},
set: function(newValue) {
this.$emit("update:inputsData", newValue);
}
}
},
methods: {
handleFocusFromChild: function() {
var newData = {
firstElement: { firstInputValue: "Hi there is changed" },
secondElement: { secondInputValue: "Bye there is changed" }
};
setTimeout(function() {
this.dataToBeChanged = newData;
}, 3000);
setTimeout(function() {
console.log(this.dataToBeChanged);
}, 4000);
}
}
};
Here is the child:
export default {
template: `
<div class="form-group">
<div class="input-group">
<input #focus="$emit('focusEvent', $event)"
v-model="value">
</div>
</div>
`,
props: {
value: String
}
};
you child component should emit "this.$emit('update:value', newValue)" as event
take a look over the docs: https://br.vuejs.org/v2/guide/components-custom-events.html
Also a way to do it is like this:
export default {
template: `
<div class="form-group">
<div class="input-group">
<input #focus="$emit('focusEvent', $event)"
v-model="valueProp">
</div>
</div>
`,
props: {
value: String
},
computed: {
valueProp:{
get(){
return this.value
},
set(val){
return this.$emit("update:value", val);
}
},
}
methods: {
handleFocus() {
this.$emit("focusEvent");
}
}
};

Can't find out why vuex getters ById doensim get a company by id

i am still new to VUEX and i am following this tutorial vuex store
The only thing i am doing differently is i am using sequelize instead of mLab like he does.
This is what my getters look like
export const companyGetters = {
allCompanies: (state, getters) => {
return state.companies
},
companyById: (state, getters) => id => {
if (getters.allCompanies.length > 0) {
return getters.allCompanies.filter(c => c._id === id)[0]
} else {
return state.company
}
}
Exactly like what he did.
My action looks like this
companyById ({commit}, payload) {
commit(COMPANY_BY_ID)
axios.get(`${API_BASE}/companies/${payload}`).then(response => {
console.log(payload, response.data)
commit(COMPANY_BY_ID_SUCCESS, response.data)
})
}
Next in my details i have
<template>
<div>
<company-details :company="company" ></company-details>
</div>
</template>
<script>
import CompanyDetails from '../components/company/CompanyDetails'
export default {
created () {
if (!this.company.companyName) {
this.$store.dispatch('companyById', this.$route.params['id'])
}
},
computed: {
company () {
return this.$store.getters.companyById(this.$route.params['id'])
}
},
components: {
'company-details': CompanyDetails
}
}
</script>
and then finally my companyDetails looks like this
<template>
<v-ons-col style="width: 350px; float:left;">
<v-ons-card>
<h1>{{company}}</h1>
</v-ons-card>
</v-ons-col>
</template>
<script>
export default {
props: ['company']
}
</script>
here is the mutations
export const companyMutations = {
[ALL_COMPANYS] (state) {
state.showLoader = true
},
[ALL_COMPANYS_SUCCESS] (state, payload) {
state.showLoader = false
state.companies = payload
},
[COMPANY_BY_ID] (state) {
state.showLoader = true
},
[COMPANY_BY_ID_SUCCESS] (state, payload) {
state.showLoader = false
state.company = payload
}
and here is my actions
allCompanies ({commit}) {
commit(ALL_COMPANYS)
axios.get(`${API_BASE}/companies`).then(response => {
commit(ALL_COMPANYS_SUCCESS, response.data)
})
},
companyById ({commit}, payload) {
commit(COMPANY_BY_ID)
axios.get(`${API_BASE}/companies/${payload}`).then(response => {
console.log(payload, response.data)
commit(COMPANY_BY_ID_SUCCESS, response.data)
})
My CompanyList looks like this
<template>
<div>
<div class="companies">
<div class="container">
<template v-for="company in companies" >
<company :company="company" :key="company.id"></company>
</template>
</div>
</div>
</div>
</template>
<script>
import Company from './Company.vue'
export default {
name: 'companies',
created () {
if (this.companies.length === 0) {
this.$store.dispatch('allCompanies')
}
},
computed: {
companies () {
return this.$store.getters.allCompanies
}
},
components: {
'company': Company
}
}
</script>
Imported Company looks like this
<template>
<v-ons-col style="width: 350px; float:left;">
<router-link :to="'/details/'+company.id" class="company-link">
<v-ons-card>
<img :src="company.imageURL" style="width:100% ;margin: 0 auto;display: block;">
<div class="title">
<b>{{company.companyName}}</b>
</div>
<div class="description">
{{company.description}}
</div>
<div class="content">
<!-- <template v-for="company in companies">
{{company}}
</template> -->
</div>
</v-ons-card>
</router-link>
</v-ons-col>
</template>
<script>
export default {
name: 'company',
props: ['company']
}
</script>
So when i click on one of these "companies" its suppose to get it by id and show the details however in the getters this return getters.allCompanies.filter(c => c._id === id)[0] returns undefined, when i refresh the page then it gets the correct company and displays it, what is going on please help. If you need more info please ask

Vue component not updated when props are async

I have this component
<template>
<div class="list-group">
<div v-for="user in data">
<!-- omitted for brevity -->
</div>
</div>
</template>
<script>
export default ("users-list", {
props: ['users']
,
data() {
return {
data: this.users
}
}
});
</script>
This component is used from another component witch get data with $.ajax (Promise) and set the data
<template>
<div>
<users-list v-bind:users="users"></users-list>
<div>
</template>
<script>
import UsersService from './users.service.js';
import UsersList from './users.list.vue';
export default ('users-main', {
components: {
'users-list': UsersList
},
mounted() {
this.refresh();
},
data() {
return {
data: null,
message: null,
user: null
}
},
methods: {
refresh() {
let service = new UsersService();
service.getAll()
.then((data) => {
this.data = data;
})
.catch((error) => {
this.message = error;
})
},
selected(user) {
this.user = user;
}
}
});
</script>
And this is the UsersService
import $ from 'jquery';
export default class UsersService {
getAll() {
var url = "/Api/Users/2017";
return new Promise((resolve, reject) => {
$.ajax({
url: url,
success(data) {
resolve(data);
},
error(jq, status, error){
reject(error);
}
});
});
}
}
As you can see the service get data with Promise, if I change
<div v-for="user in data">
into the property, I can see the users
<div v-for="user in users">
Question: How I can pass async props value to the components ?
You set data once "onInit" in users-list.
For reactivity you can do
computed:{
data(){ return this.users;}
}
or
watch: {
users(){
//do something
}
}
What do you mean by:
As you can see the service get data with Promise, if I change
<div v-for="user in data">
into the property, I can see the users
<div v-for="user in users">
Use <div v-for="user in users"> should work, so what's the problem?