How do I get a parent and child vue components to share data with another?


#1

Since my guestbook webapp has a sign component and a view component, I feel the need to not put all code into one component.

But question two is how do I get one data object from one script to the next?

I’ve tried the following:

/src/components/Guestbook.vue

<template>
<div>
    <h1>Guestbook</h1>

    <SignGuestbook />
    <ViewGuestbook :entries="v_entries" />
    <ViewGuestbook :p_entries="v_entries" />
    <!-- Error: '[Vue warn]: Property or method "store" is not defined on the instance but referenced during render.' -->
    <!-- <ViewGuestbook :entries="store" /> -->
    <!--   <ViewGuestbook :p_entries="store" /> -->
    <!-- Error: '[Vue warn]: Property or method "$store" is not defined on the instance but referenced during render.' -->
    <!-- <ViewGuestbook :entries="$store" /> -->
    <!-- <ViewGuestbook :p_entries="$store" /> -->
</div>
</template>

<script>
import SignGuestbook from './SignGuestbook.vue'
import ViewGuestbook from './ViewGuestbook.vue'
import Vue from 'vue'
import Vuex from 'vuex'
import guestbook from './guestbook.js'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    entries: [
      { id: 1, name: 'stored 1', comment: 'comment' },
      { id: 2, name: 'stored 2', comment: 'comment' }
    ]
  },
  getters: {
    entries: entries => {
      return entries
    }
  },
  mutations: {
    refreshList (state) {
      state.s_entries = guestbook.getItems()
    }
  }
})

export default {
  name: 'Guestbook',
  components: {
    SignGuestbook,
    ViewGuestbook
  },
  props: ['v_entries'],
  data () {
    return { comment: '', name: '', entries: ['test'] }
  },
  methods: {
    refreshList: async function () {
      this.entries = await guestbook.getItems()
      store.commit('refreshList')
      // this.$store = await guestbook.getItems()
      console.log('regular entries:', this.entries)
      console.log('stored entries:', this.store.getters.entries)
    }
  },
  async created () {
    await guestbook.authoriseAndConnect()
    await guestbook.createMutableData()
    await this.refreshList()
  }
}
</script>

/src/components/ViewGuestbook.vue

<template>
  <div>

    get entries attempt #1<br>
    <div v-for="entry in entries">
      an entry<br>
    </div>
    <br>
    get entries attempt #2<br>
    {{ entries }}
    <br>
    <!-- Error: '[Vue warn]: Property or method "$store" is not defined on the instance but referenced during render.' -->
    <!-- stored entries<br>
    {{ this.$store }}
    <br>-->
    <br>

    </div>
  </div>
</template>

<script>

export default {
  name: 'ViewGuestbook',
  props: ['p_entries'],
  data () {
    return { entries: [
      { id: 1, name: 'child 1', comment: 'comment' },
      { id: 2, name: 'child 2', comment: 'comment' }
    ] }
  },
  async created () {
    this.entries = this.p_entries
  }
}

</script>

/src/components/guestbook.js

let app
let md

async function authoriseAndConnect () {
  const opts = {
    forceUseMock: true
  }
  let appInfo = {
    name: 'SAFE Guestbook Application',
    id: 'net.maidsafe.tutorials.web-app',
    version: '0.1.0',
    vendor: 'MaidSafe.net Ltd.'
  }
  app = await window.safe.initialiseApp(appInfo, null, opts)
  console.log('Authorising SAFE application...')
  try {
    const authReqUri = await app.auth.genAuthUri()
    console.log('Generated authentication URI...', authReqUri)
    const authUri = await window.safe.authorise(authReqUri)
    console.log('SAFE application authorised...')
    await app.auth.loginFromUri(authUri)
  } catch (err) {
    console.warn('Application authorisation was rejected', err)
  }
  console.log('Application connected to the network')
}

async function createMutableData () {
  console.log('Creating MutableData with initial dataset...')
  const typeTag = 15000
  md = await app.mutableData.newRandomPublic(typeTag)
  const initialData = {
    'random_key_1': JSON.stringify({
      name: 'parent 1',
      comment: 'comment'
    }),
    'random_key_2': JSON.stringify({
      name: 'parent 2',
      comment: 'comment'
    })
  }
  await md.quickSetup(initialData)
}

async function getItems () {
  const entries = await md.getEntries()
  let entriesList = await entries.listEntries()
  let items = []
  entriesList.forEach((entry) => {
    const value = entry.value
    if (value.buf.length === 0) return
    const parsedValue = JSON.parse(value.buf)
    items.push({ key: entry.key, value: parsedValue, version: value.version })
  })
  return items
}

module.exports = {
  authoriseAndConnect,
  createMutableData,
  getItems
}

index.js

import Vue from 'vue'
import App from './App'
import router from './router'

export default new Vue({
  el: '#root',
  router,
  render: (h) => h(App)
})

// Error: unused variable
// let globalData = new Vue({
//   data: {
//     $store: {}
//   }
// })

// Error: '[Vue warn]: Property or method "$store" is not defined on the instance but referenced during render.'
// Vue.mixin({
//   computed: {
//     $store: {
//       get: function () { return globalData.$data.$store },
//       set: function (newData) { globalData.$data.$store = newData }
//     }
//   }
// })

Expected (at least one of them):

get entries attempt #1
an entry
an entry
get entries attempt #2
[{ id: 1, name: 'stored 1', comment: 'comment' },{ id: 2, name: 'stored 2', comment: 'comment' }]

Result:

get entries attempt #1

get entries attempt #2

#2

i m not a skilled man in codage but i try to learn .good work go on


#3

As this question is not really specific to SAFE I would suggest looking for other resources that help you with your problem.


Anyway, some remarks:

  • You’re using require as well as import/export. I think that’s confusing as you would usually only need one of those mechanisms.
  • It might be that the error lies in the circular way the app is built. Guestbook includes ViewGuestbook which includes Guestbook again.
  • Why not include the guestbook.js directly from the ViewGuestbook.vue?
  • Look into https://vuex.vuejs.org/ . I think your problem arises from a design point of view. Think about how you’re structuring your app.

#4

I’ve updated the problem.


#5

Your update changed the question completely. The core issue is still unrelated to SAFE.

Passing data is perfectly explained in the Vue.js guide: https://vuejs.org/v2/guide/components.html#Passing-Data-to-Child-Components-with-Props


I would be glad to help you via Riot; I don’t think this is forum material.


#6

@bzee Thanks for helping me out.

Though I still stand by that the vuejs guide is rather minimal and obtuse due to the fact that one has to make a
“translation switch” from Global component code to Single File Component code.

Here is the solution:

/src/components/Guestbook.vue

<template>
<div>
    <h1>Guestbook</h1>

    <SignGuestbook />
    <ViewGuestbook v-bind:entries="d_entries" />
</div>
</template>

<script>
import SignGuestbook from './SignGuestbook.vue'
import ViewGuestbook from './ViewGuestbook.vue'

import guestbook from '~/api/guestbook'

export default {
  name: 'Guestbook',
  components: {
    SignGuestbook,
    ViewGuestbook
  },
  data () {
    return {
      comment: '',
      name: '',
      d_entries: []
    }
  },
  methods: {
    refreshList: async function () {
      this.d_entries = await guestbook.getItems()
    }
  },
  async created () {
    await guestbook.authoriseAndConnect()
    await guestbook.createMutableData()
    await this.refreshList()
  }
}
</script>

/src/components/ViewGuestbook.vue

<template>
  <div>

    entries<br>
    <div v-for="entry in entries">
      {{ entry.value.name }}<br>
      {{ entry.value.comment }}<br>
    </div>

  </div>
</template>

<script>

export default {
  name: 'ViewGuestbook',
  props: {
    'entries': Array
  }
}
</script>

To share data, bind a data object from a parent component to a props object of a child component using v-bind.


#7

Glad to be of help so far!

I see a few examples use the Vue.component function, but the only difference is that the template value is put in separate <template> tags in a Single File Component. That shouldn’t make it harder to understand. Actually, the guides being minimalist I’ve found them to be extremely to the point and clear.


I saw Vue.js has a forum; they might be able to help you much quicker with some of these basic Vue.js issues.