ChatGPT解决这个技术问题 Extra ChatGPT

VueJS access child component's data from parent

I'm using the vue-cli scaffold for webpack

My Vue component structure/heirarchy currently looks like the following:

App PDF Template Background Dynamic Template Image Static Template Image Markdown

PDF Template Background Dynamic Template Image Static Template Image Markdown

Background

Dynamic Template Image

Static Template Image

Markdown

At the app level, I want a vuejs component method that can aggregate all of the child component's data into a single JSON object that can be sent off to the server.

Is there a way to access child component's data? Specifically, multiple layers deep?

If not, what is the best practice for passing down oberservable data/parameters, so that when it's modified by child components I have access to the new values? I'm trying to avoid hard dependencies between components, so as of right now, the only thing passed using component attributes are initialization values.

UPDATE:

Solid answers. Resources I found helpful after reviewing both answers:

Vuex and when to use it

Vuex alternative solution for smaller apps


P
PJ3

In my child component, there are no buttons to emit changed data. It's a form with somewhat 5~10 inputs. the data will be submitted once you click the process button in another component. so, I can't emit every property when it's changing.

So, what I did,

In my parent component, I can access child's data from "ref"

e.g

<markdown ref="markdowndetails"></markdown>
<app-button @submit="process"></app-button>

// js
methods:{
    process: function(){
        // items is defined object inside data()
        var markdowns = this.$refs.markdowndetails.items 
    }
}

Note: If you do this all over the application I suggest move to vuex instead.


Where can i find the documentation for this?
Worked well for me - Thanks @PJ3
It's simple method to pass data from child to parent, the emit is more complicated. Thanks
@BesLey I think they have different use cases. If the component is designed to be a child of another specific component, then accessing its internal data directly maybe the right choice, like getters/setters in object oriented programming. But if the component is to used in different places then event method is the more appropriate one.
B
Belmin Bedak

For this kind of structure It's good to have some kind of Store.

VueJS provide solution for that, and It's called Vuex.If you are not ready to go with Vuex, you can create your own simple store.

Let's try with this

MarkdownStore.js

export default {

 data: {
   items: []
 },

 // Methods that you need, for e.g fetching data from server etc.

 fetchData() {
   // fetch logic
 }

}

And now you can use those data everywhere, with importing this Store file

HomeView.vue

import MarkdownStore from '../stores/MarkdownStore'

export default {

 data() {
   sharedItems: MarkdownStore.data
 },

 created() {
   MarkdownStore.fetchData()
 }

}

So that's the basic flow that you could use, If you dont' want to go with Vuex.


Documentation explains it pretty good as well.
What if I want to move fetchData() logic inside MarkdownStore. it makes sense to put all the components logic inside the component.
This solution almost worked for me. I can access the fetchData() method, but that method can not access the data in the MarkdownStore view. this.data.items, or this.$data.items didn't work
@YeeHaw1234 you should access It by this.items, from your component.
@Toast I truly believe the documentation could (must) say more about the matter.
C
CodinCat

what is the best practice for passing down oberservable data/parameters, so that when it's modified by child components I have access to the new values?

The flow of props is one way down, a child should never modify its props directly.

For a complex application, vuex is the solution, but for a simple case vuex is an overkill. Just like what @Belmin said, you can even use a plain JavaScript object for that, thanks to the reactivity system.

Another solution is using events. Vue has already implemented the EventEmitter interface, a child can use this.$emit('eventName', data) to communicate with its parent.

The parent will listen on the event like this: (@update is the shorthand of v-on:update)

<child :value="value" @update="onChildUpdate" />

and update the data in the event handler:

methods: {
  onChildUpdate (newValue) {
    this.value = newValue
  }
}

Here is a simple example of custom events in Vue:
http://codepen.io/CodinCat/pen/ZBELjm?editors=1010

This is just parent-child communication, if a component needs to talk to its siblings, then you will need a global event bus, in Vue.js, you can just use an empty Vue instance:

const bus = new Vue()

// In component A
bus.$on('somethingUpdated', data => { ... })

// In component B
bus.$emit('somethingUpdated', newData)

M
Mohamed Adel

you can meke ref to child component and use it as this this.$refs.refComponentName.$data

parent-component

<template>
   <section>
      <childComponent ref="nameOfRef" />
   </section>
</template>

 methods: {
  save() {
   let Data = this.$refs.nameOfRef.$data;
 }
},

l
louis_coetzee

In my case I have a registration form that I've broken down into components.

As suggested above I used $refs, In my parent I have for example:

In Template:

<Personal ref="personal" />

Script - Parent Component

export default {
  components: {
    Personal,
    Employment
  },
  data() {
    return {
        personal: null,
        education: null
    }
  },
  mounted: function(){
       this.personal = this.$refs.personal.model
       this.education = this.$refs.education.model
  }
}

This works well as the data is reactive.