0

I have 2 components

My first component like this :

<template>
    ...
        <b-form-input type="text" class="rounded-0" v-model="keyword"></b-form-input>
        <b-btn variant="warning" @click="search"><i class="fa fa-search text-white mr-1"></i>Search</b-btn>
    ...
</template>
<script>
    export default {
        data () {
            return {
                keyword: ''
            }
        },
        methods: {
            search() {
                this.$root.$emit('keywordEvent', this.keyword)
                location.href = '/#/products/products'
            }
        }
    }
</script>

My second component like this :

<template>
    ...
</template>
<script>
    export default {
        data () {
          return{
              keyword: ''
          }
        },
        mounted: function () { 
            this.$root.$on('keywordEvent', (keyword) => {
                this.keyword = keyword
            })
            this.getItems()
        },
        methods: {
            getItems() {
                console.log(this.keyword)
                ....
            }
        }
    }
</script>

I using emit to pass value between components

I want to pass value of keyword to second component

/#/products/products is second component

I try console.log(this.keyword) in the second component. But there is no result

How can I solve this problem?

Update :

I have index.js which contains vue router like this :

import Vue from 'vue'
import Router from 'vue-router'
...
const Products = () => import('@/views/products/Products')
Vue.use(Router)
export default new Router({
  mode: 'hash', // https://router.vuejs.org/api/#mode
  linkActiveClass: 'open active',
  scrollBehavior: () => ({ y: 0 }),
  routes: [
    {
      path: '/',
      redirect: '/pages/login',
      name: 'Home',
      component: DefaultContainer,
      children: [
        {
            path: 'products',
            redirect: '/products/sparepart',
            name: 'Products',
            component: {
                render (c) { return c('router-view') }
            },
            children : [
                ...
                {
                    path: 'products',
                    name: 'products',
                    component: Products,
                    props:true
                }
            ]
        },
      ]
    },
    {
      path: '/products/products',
      name: 'ProductsProducts', // just guessing
      component: {
          render (c) { return c('router-view') }
      },
      props: (route) => ({keyword: route.query.keyword}) // set keyword query param to prop
    }
  ]
})
moses toh
  • 12,344
  • 71
  • 243
  • 443

2 Answers2

1

From this code...

location.href = '/#/products/products'

I'm assuming /#/products/products maps to your "second" component via vue-router, I would define the keyword as a query parameter for the route. For example

{
  path: 'products',
  name: 'products',
  component: Products,
  props: (route) => ({keyword: route.query.keyword}) // set keyword query param to prop
}

Then, in your component, define keyword as a string prop (and remove it from data)

props: {
  keyword: String
}

and instead of directly setting location.href, use

this.$router.push({name: 'products', query: { keyword: this.keyword }})
Phil
  • 157,677
  • 23
  • 242
  • 245
  • If I click search button, it call url `http://localhost:8080/#/products/products?keyword=test`. In my second component, I add `props: { keyword: String }`. In `getItems` method, I add `console.log(this.keyword)`, the result : `undefined` – moses toh Sep 16 '18 at 10:26
  • @SuccessMan and what about your router, ie the first block of code in my answer? If my answer is not working for you, please update your question – Phil Sep 16 '18 at 10:26
  • I had update my question. I had add script from your answer in my routes – moses toh Sep 16 '18 at 10:44
  • @SuccessMan I didn't mean for you to just copy / paste my code. The example was how to add the query param to `props` handling to one of your existing routes, ie the one that handles the `/products/products` URL – Phil Sep 16 '18 at 13:10
0

There are some ways to do it in Vue.

  1. Use EventBus with $emit like you did;

event-bus.js

import Vue from 'vue';
const EventBus = new Vue();
export default EventBus;

component1.vue :

import EventBus from './event-bus';
...
methods: {
    my() {
      this.someData++;
      EventBus.$emit('invoked-event', this.someData);
    }
  }

component2.vue

import EventBus from './event-bus';
...
data(){return {changedValue:""}},
...
mounted(){
    EventBus.$on('invoked-event', payLoad => {
        this.changedValue = payload
    });
}
  1. Use Vuex store, will be accessible at any component, at any page; (my favorite way)

store/index.js

import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);

const store = () =>
    new Vuex.Store({
    store: {myStore:{value:0}},
    actions:{["actionName"]:function({commit}, data){commit("actionName", data);}}, // I usualy using special constant for actions/mutations names, so I can use that here in code, and also in components
    mutations:{["actionName"]:function(state, data){state.myStore.value = data;}},
    getters:{myStoreValue: state => !!state.myStore.value}
})

component1.vue

...
methods:{
    change:function(){
        this.$store.dispatch("actionName", this.someData); //nuxt syntax, for simple vue you have to import store from "./../store" also
    }
}

component2.vue

...
data(){return {changedValue:""}},
...
mounted(){
    this.changedValue = this.$store.getters.myStoreValue;
}
  1. Use props like @Phil said.
SiarheiK
  • 797
  • 4
  • 17