Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

inyansuta's avatar

Use vue or not to use it?

I'm trying to create a very complex system with vue. And for the third time, I'm reworking the whole code.

The biggest problem is that I do not know how to make any internal component call the parent's main component. For example, I have a <file-manager> component that is at the parent level (this is a singleton). If any other component (such as the text I want to link to a file) needs to communicate with this file manager, what procedures would you recommend?

I've tried everything, including the vuex I left again. In other words, for more complex communication between the various components (panels, offers, different managers, etc.), Vue is terribly cumbersome due to the scattered communication between the parent and the children.

Example:

<admin-component ref="admin"></admin-component>

new Vue({
    components: {
        AdminComponent,
    },
    methods: {
        getFileManager() {
            return this.$refs.admin.$refs.fileManager;
        }
    },
});

// now when another components need working with global fileManager, this is one solution, what I use... but is terrible...

$anotherComponent.$root.getFileManager().method()...

Is there a tutorial that solves really complex and robust stuff using vue js (video, article..)?

Thanks for help.

0 likes
15 replies
ramonrietdijk's avatar

If I understand you correctly, you could take a look at Vue.js' emit function. This way you can listen to an event from the child component in the parent component. Documentation can be found on https://vuejs.org/v2/api/#vm-emit

1 like
NoTimeForCaution's avatar

As @ramon10203 suggested, you need to utilize the $emit function from within your child components and a listener on the parent.

In your child component:

this.$emit('statusMessage', 'DATA SAVED');

In your parent component:

<parent-component @statusMessage="myMessage"></parent-component>

methods: {
     myMessage(msg) {
          this.status = msg;
          setTimeout(this.resetStatusMessage, 5000);
     }
}
inyansuta's avatar

@ramon10203 @dawgonking I will try to describe the whole situation. I create an administration where the user can work with any html element on the page (classic website). If I click, for example, on a paragraph (this paragraph has unique id in database), I will display a sidebar with options (operations that can be performed with a paragraph). Now, for example, the sidebar Vue component need a cooperate with file manager Vue component (file manager is a singleton, I do not want each component on the page to create a custom file manager instance).

The question is: how can one component interact with another component? Using direct interaction, without complicated triangular $emit communication - CHILD (sidebar) / ROOT (admin) / ANOTHER CHILD (file manager). I need direct access to the FILE MANAGER (for example, if a component is embedded in other components, communication through parents is mad).

When I tried to use Vuex (storage plugin), of course I can share all the possible objects and methods (other class instances, etc.), but even with Vuex it is not possible to share any VUE !!! component.

In short, I still do not know the best solution. Here is an example of how I achieved what I want, but it is terribly scabbard. If you can advise me on what I'm doing wrong, and if there is a solution, I'll be grateful.

// index.blade.php
<div id="file-manager">
    <file-manager-component></file-manager-component>
</div>
<div id="admin">
    <admin-component>
        <panel-manager-component>
            <panel-component>
                <paragraph-component>
                </paragraph-component>
                // HERE I NEED DIRECT COMUNICATION between
                // panel component and file manager (singleton) component
            </panel-component>
        </panel-manager-component>
    </admin-component>
</div>

// fileManager.js
import FileManagerComponent from './FileManagerComponent';

export const fileManager = new Vue({
    el: '#file-manager',
    components: {
        FileManagerComponent,
    },
    // ...
});

// PanelComponent.vue
    import {fileManager} from "./fileManager";
    ...
    data: {
        // now I can in every component import fileManager
        fileManager: fileManager
    }

inyansuta's avatar

Let me try briefly two lines of code

new Vue({
  created () {
    // share a standard object is no problem
    // I can access the service from
    // any component using $root.nonVueService
    this.nonVueService = new NonVueService()

    // but i want share Vue component
    // how can I get this component from children?
    // (I get back to the introductory question - see also
    // my main introductory question and the example given in it)
    this.vueComponent = ???
  }
});
D9705996's avatar

If you are doing anything with components in vue that involves complex events it gets really messy really quickly unless you use vuex for managing the state. Each component is then responsible for updating the vuex state and reacting to state changes it cares about. If you need to store lots of related data in vuex this package is superb

https://github.com/vuex-orm/vuex-orm

inyansuta's avatar

@d9705996 I have just one simple requirement on Vue. Create a global component that anyone can work with. Impossible with Vue.

rodrigo.pedra's avatar

Hi @inyansuta

There are several ways you could achieve this. Communicating with the root component. Most of them are documented in the Handling Edge Cases in the official Vue guide.

1. Access directly the $root component:

https://vuejs.org/v2/guide/components-edge-cases.html#Accessing-the-Root-Instance

Although I do not recommend this, as it fights against the proposal of having parent/child communication, this might be an option in your case.

2. Use Vuex

https://github.com/vuejs/vuex

Vuex is a centralized state management then once installed and configured would let you access the same Store in all your app components.

3. Accessing the parent component

https://vuejs.org/v2/guide/components-edge-cases.html#Accessing-the-Parent-Component-Instance

Again, not recommended. For direct communication from parent to child you can use events and props

4. Accessing Child component

https://vuejs.org/v2/guide/components-edge-cases.html#Accessing-Child-Component-Instances-amp-Child-Elements

This method I use sometimes, it allows you to define a ref attribute on child component inside the parent's template and execute child methods or access child variables.

The example in the docs illustrate a parent invoking a child method to focus an input that lies inside the child component. There are many other use cases, such as closing a child sidebar component whenever its parent element receives an event from a sibling child component.

4. Dependency injection

https://vuejs.org/v2/guide/components-edge-cases.html#Dependency-Injection

For a highly coupled component hierarchy, dependency injection is a viable option. The link above provide examples

5. Use an event hub (or event bus)

There would be an external Vue instance responsible only to share events between components inside an app.

I hope one of these options fit your needs.

inyansuta's avatar

Thank you very mutch, @rodrigo.pedra

During the last week I've tried all the options you describe. Now I am in a situation where I am completely confused. I will try to ask directly and simply which way (from above) you would use for the following situation.

Panel Manager component

  • can create panels, control their opening and closing, display various internal components (form elements), etc.
  • can accept the list of components to display

File Manager component

  • displays saved files,
  • allows you to upload, save, delete files, etc.,
  • according to the performed operations, the File Manager component requires the Panel Manager to create a panel (panels)
  • (Note: The File Manager component is not the only one asking the panel manager to create a panel and display different data (components))

Paragraph component (as an example only)

  • again asking the panel manager to create different panels (core panel with textarea field etc.)
  • One of the operations is to insert a link to a file - so I need:
  • a) Ask File Manager to select a file
  • b) File Manager opens, this prompts the user to select the file and then passes the file back to the Paragraph component (which previously registered the callback)

How do you achieve communication between these Vue components?

D9705996's avatar

What you are asking is not an easy question I'm afraid. It sounds like a dashboard component your writing that can have panels with dynamic content.

You probably need to look at this

https://vuejs.org/v2/guide/components.html#Dynamic-Components

And also how you structure your project to accommodate this. Regardless of how you implement you are going to have shared state which is what vuex is for rather than emiting events

rodrigo.pedra's avatar

As @d9705996 said, I think your question is not an easy question, it really depends on how you want your components to interact, and it is hard to help with a high-level description.

By your description I would go with the Vuex or Event Bus route.

As a proof of concept, I built a small demo app to demonstrate how you could achieve coordination between sibling components. In this demo I used just events and refs to achieve communication between components.

https://gist.github.com/rodrigopedra/db023f59d7a19cb8f78bf92eaeb0bdff

Right in the gist header there is a link to download a ZIP, download, extract and open the index.html in your browser.

As it is a demo, I didn't tested for support in all browsers and also used inline templates to simplify running it. I also used Bootstrap for minimal UI. Edit: I tested in Firefox and Chrome.

There is a Dashboard component, which wraps all other components. There you can add LinksList or ImagesList components, how many you want. It also wraps a AssetManager component which is responsible to manage assets and provide an UI for the user to add or remove assets (an asset is either a link or an image).

On each of these "List" components, you can add add an asset. This will tell the Dashboard component to ask the AssetsManager component to interact with the user for a new asset.

If an user remove an asset from the AssetManager, it will emit an event to tell the Dashboard to update the corresponding "List" component.

You'll see that my approach was to let the components focused on the minimal tasks they should do. All the coordination and rendering is achived by manipulating data.

Please let me know if you have any doubts, or if this demo was helpful in any ways. At least it was fun to code it.

inyansuta's avatar

@rodrigo.pedra Amazing. I did not expect such an exhaustive answer. I really appreciate your time and I am grateful for it. Now I'm going to study your code and design concept. By the way, it's exactly the technique I'm looking for. I'm curious how this code corresponds to what I've created so far ... I'll definitely let you know.

Thank you once again.

rodrigo.pedra's avatar

@inyansuta I really hope it helps.

From your previous descriptions I think you are not using the wrapping component (Dashboard in my demo) to coordinate the communication between the various components.

The key in my demo is that each component has little to no knowledge about each other, the only one which has some deep knowledge about one of its child components is the Dashboard, which is fair enough as it acts as a coordinator (or controller if you wish) between the various components.

I guess the difference is that you wanted to access the AssetsManager inside the List components, when you could use this approach to make the coordination between them easier.

Glad if this could help in any form.

Thanks for your quick response.

inyansuta's avatar

@rodrigo.pedra I add the following link only for a better understanding. Please do not stand by studying my code, I do not want to delay you at all. However, there is visible work with individual elements on the page.

http://vaclavgraf2.petrzavicak.cz/o-nas/o-nasi-spolecnosti

In the middle of the page, when you right-click on text "Petr Zavičák" (simple text/paragraph component), the options panel (insert new item, edit, delete) will be displayed on the right. Each html component on the page naturally has its own options. For example, when selecting a second option (editing), another panel is opened (with another options). When you focus text form field and when you selected text, next option panel is visible, etc...

Note that I uploaded a working version to the server, so all the options are not fully implemented and you will surely encounter the error messages.

In the console you can view the vue components using Vue devtools. Although it's been the third version of the code for the last 14 days, which I've completely redesigned from scratch, the code is crazy in my opinion (and . But it is because I'm already losing it and I do not know which concept to use.

Thanks again for your previous post and code, I must first study properly.

rodrigo.pedra's avatar

Hi @inyansuta I took a look at the linked page and got some idea on how it works.

From the Vue developer console tools I see that the hierarchy is similar to the demo I sent previously. You have the content (paragraphs) stored in root, and also the PanelManager, so the root component could act as a coordinator.

I saw that your app doesn't use events to much between components (ar leas the Vue developer tools didn't recorded any). Of course you already told this is the third version of the app and that you are trying different approaches. But I personally like the "events up / props down" approach preached by many tutorials and the Vue guide. It helps me keep my components small and focuses. The key is to better understand how Vue's reactivity system works and don't worry to share this control with Vue.

Also, I would wrap them all in another high-level component so I could share this component more easily between pages. Or if you move to a SPA you have it decoupled from the root component. But it is just a matter of preference. If you prefer to have a Vue instance per page and can manage that as separated apps/components, it is ok. there is no right or wrong answer here.

In the past I worked with some more traditional architectures (Delphi, Java, etc.) having all the interactions and dependencies referenced inside each component was the common way to work. It required me a mind shift to think in a component model based on reactivity and shared roles. This shift is not always easy, old habits are hard to let go, but for me, at least, learningn the "Vue-way" paid off very quickly.

One quick gain I noticed in your app (and pardon me if you already did this in some previous version) is to toggle the overflow from the body element when the side-panel is open or closed.

Something like this:

// execute this when side bar is opened
document.body.style.overflowY = 'hidden';

and

// execute this when side bar is closed
document.body.style.overflowY = 'auto';

It will "lock" the page content scroll while the sidebar is opened, so the highlighted element won't move when a user scrolls the mouse.

If you have any doubts about my demo, please let me know.

And good luck in your quest, by far the idea is great and the design looks good to me.

Please or to participate in this conversation.