vuejs / Discussion

Vue.js discussion
167 stars 17 forks source link

Communicating between two sibling components #382

Closed nivv closed 8 years ago

nivv commented 9 years ago

Hey!

I've found myself in a little (I hope) pickle. I have two components (using vueify) that I insert manually in my view.

Main.js

var Vue = require('vue');
Vue.use(require('vue-resource'));
new Vue({
    el: '#app',
    components: {
        'attach-image-button': require('./components/partials/attach-image-button.vue'),
        'mb-image-picker': require('./components/mb-image-picker.vue')
    }
});

Component 1

The idea here is to be able to pass some configuration options as props. I'll have multiple buttons but I only want 1x Component 2. Although, I need to pass the props to the sibling component on click.

<template>
    <a data-toggle="modal"
         href="#mediabank-files-modal"
         v-on="click: setId"
         class="{{classes}}">
         {{buttonText}}
    </a>
</template>
var component = {
    inherit: true,
    props: ['modelName', 'modelId', 'view', 'appendTo', 'classes', 'view', 'buttonText', 'setModelName', 'setModelId', 'setView', 'setAppendTo'],
    methods: {
        setId: function() {
            this.modelName = this.setModelName;
            this.modelId = this.setModelId;

            if (this.setView) {
                this.view = this.setView;
            }

            if (this.setAppendTo) {
                this.appendTo = this.setAppendTo;
            }
        }
    }
}
module.exports = component; 

Component 2

This component makes the AJAX request, here I need the supplied configuration options I passed as props. As you can I do not want to make 60 API-requests every time I insert the above button component.

var component = {
    inherit: true,
    props: ['modelName', 'modelId', 'view'],
    data: function() {
        return {
            appReady: false,
            loading: false
        }
    },
    components: {
        'item': require('./partials/folder-tree.vue')
    },
    ready: function() {
        this.$set('loading', true);
        this.$http.get('https://site.com/api/v1/folder/' + this.modelId + '/' + this.modelName, function(data, status, request) {
                this.$set('loading', false);
                console.log('success')
            }).error(function(data, status, request) {
                console.log('error getting stuff')
                console.log(data);
            })
    }
}
module.exports = component; 

How my "static" view looks like:

<mb-image-picker></mb-image-picker>
<!-- A bunch of buttons -->
<attach-image-button
    model-name="post"
    model-id="1"
    button-text="Add image">
</attach-image-button>
<attach-image-button
    model-name="post"
    model-id="2"
    button-text="Add image">
</attach-image-button>
<attach-image-button
    model-name="post"
    model-id=3"
    button-text="Add image">
</attach-image-button>
<attach-image-button
    model-name="post"
    model-id="4"
    button-text="Add image">
</attach-image-button>

What I've tried so far

soulprovidr commented 8 years ago

Check this page of the docs out: http://vuejs.org/guide/application.html#State_Management

Using a single, static data object as a 'store' will simplify your code since Vue automatically takes care of updating your component views when an attribute on the data object is set.

Notice we are putting all actions that mutate the store’s state inside the store itself. This type of centralized state management makes it easier to understand what type of mutations could happen to the state, and how are they triggered. Each component can still own and manage its private state.

Put the AJAX request (i.e. the state mutation) in the store. That way you can share the data between your components.

nivv commented 8 years ago

@sholanozie I see, so the solution is to have the shared data in a parent component? I've done that before and it works well. Thanks for your input!

NextSeason commented 8 years ago

I add a "bridge" in parent for events. I don't know if it is a good way

events : {
    'bridge'( e, ...args ) {
        // $broadcast would not trigger the events in parent, add $emit if you want parent itself can also detect the event.
        this.$emit( e, ...args );
        this.$broadcast( e, ...args ); 
   }
}

and dispatch event in components with the bridge

this.$dispatch( 'bridge', 'real-event-name', params );