Improving the structure of Vue single-file components

As my single-file component continues to grow, I decided to do some refactoring. It turns out that a couple of dialogs are making the .vue file quite large (800+ lines). To maintain a clean and organized component, I am working on transforming these dialogs into separate child components (mydialog). Although I'm using vuetify, you don't need to be familiar with it.

In the parent component, there's a button that triggers the dialog. I pass the dialog prop to the child component, which is then attached to the v-model of the dialog. The issue arises as it only works the first time. This happens because when I click the 'close' button, it sets the dialog value to false and it remains false thereafter since the communication between the child and parent component gets disconnected. How can this be resolved under such circumstances?

Here's an excerpt:

Vue.component('mydialog', {
  props:{
    dialog: {
      type: Boolean,
      default: false
    }
  },

  template: `
<div class="text-xs-center">
    <v-dialog
      v-model="dialog"
      width="500"
    >

      <v-card>
        <v-card-title
          class="headline grey lighten-2"
          primary-title
        >
          A Dialog
        </v-card-title>

        <v-card-text>
          Lorem ipsum dolor sit amet,
        </v-card-text>

        <v-divider></v-divider>

        <v-card-actions>
          <v-spacer></v-spacer>
          <v-btn
            color="primary"
            flat
            @click="dialog = false"
          >
            Close
          </v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
  </div>
`,
  data: function() {
    return {
      // dialog: false,
    }
  }

});

new Vue({
  el: '#app',
  data: {
    dialog: false
  }

});
<!doctype html>
<html>

<head>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vuetify/1.2.0/vuetify.min.css" />
</head>

<body>
  <div id="app">
    <v-app id="inspire">
      <v-btn color="red lighten-2" dark @click="dialog=true">Click Me</v-btn>
      <mydialog :dialog="dialog"></mydialog>
    </v-app>

  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vuetify/1.2.0/vuetify.min.js"></script>
</body>

</html>

Answer №1

Your component communication needed some adjustment: essentially, the dialog was not notifying the app component when it was closed. To facilitate upstream communication between the modal and app components, two changes were made:

Within the app template:

<mydialog :dialog.sync="dialog"></mydialog>

Inside the mydialog controller:

data: function() {
    return {
      dialog$: false,
    };
  },
  methods: {
    onClose() {
      this.dialog$ = false;
      this.$emit('update:dialog', this.dialog$);
    },
  },
  watch: {
    dialog: {
      immediate: true,
      handler() {
        this.dialog$ = this.dialog;
      },
    },
  }

The first change allows the app component to listen for updates on the dialog prop from mydialog.

In mydialog, a data property dialog$ was introduced to mirror the dialog prop (since props should remain constant). A watcher ensures that downstream updates on dialog are reflected in dialog$. The onClose method updates dialog$ when the dialog is closed and emits an update to subscribers, specifically the app component.

Vue.component('mydialog', {
  props:{
    dialog: {
      type: Boolean,
      default: false
    }
  },

  template: `

// template code here

`,
  data: function() {
    return {
      dialog$: false,
    };
  },
  methods: {
    onClose() {
      this.dialog$ = false;
      this.$emit('update:dialog', this.dialog$);
    },
  },
  watch: {
    dialog: {
      immediate: true,
      handler() {
        this.dialog$ = this.dialog;
      },
    },
  }
});

new Vue({
  el: '#app',
  data: {
    dialog: false
  },
  template: `

// template code here

`,

});
<!doctype html>
<html>

<head>

// head content here

</head>

<body>
  <div id="app"></div>
  
  // scripts here
  
</body>

</html>


As mentioned by @raina77ow, another approach to solving this issue is using an event bus, but it's not necessary in this scenario.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

It seems that the JavaScript object is producing varied values in distinct locations despite no alterations made in between

I've encountered a puzzling issue where a variable is returning different values within a function, despite no modifications being made to it. This problem arises in a form component created using Vue.js (v2) that triggers a Vuex action. While I beli ...

AngularJS: The blend of bo-bind, bindonce, and the translate filter

I am currently working with angular 1.2.25, angular-translate 2.0.1, angular-translate-loader-static-files 2.0.0, and angular-bindonce 0.3.1. My goal is to translate a static key using bindonce. Here is the code snippet I have: <div bindonce> < ...

There seems to be an issue with the bootstrap datepicker as it is throwing an error stating that $(

Currently in the process of developing a web application using AngularJS with MVC, I have integrated Bootstrap's datepicker into my project, Here is the code snippet: <div class="container"> <div class="row"> <div class=& ...

I am looking for a way to showcase a success message coming from my backend on a Vue

How do I show my success message in a Vue template? Here is my JSON data: { "data": { "message": "Email has been sent" } } This is my template: <form @submit.prevent="handleSubmit"> < ...

The ul cannot be hidden if there are no li elements within it

Currently, I am attempting to hide the unordered list (ul) on a specific page using AJAX due to certain sections of the site being Ajax-based. <ul class="sub-nav-20-m" id="filtersList_m"> </ul> Below is the code that I hav ...

I am confused about the process of mounting components

Utilizing pattern container/representational components, I have a CardContainer component that retrieves data from a server and passes it to a Card component. Container Component: class CardContainer extends Component { state = { 'ca ...

Having trouble accessing cookies in JavaScript on Internet Explorer 11?

I am facing an issue with my Angular application where cookies are not being read properly in Internet Explorer 11. The JavaScript code works fine on Chrome, but IE seems to be having trouble accessing the cookie data even though it is visible in the devel ...

What is the reason behind getElementsByClassName not functioning while getElementById is working perfectly?

The initial code snippet is not functioning correctly DN.onkeyup = DN.onkeypress = function(){ var div = document.getElementById("DN").value document.document.getElementsByClassName("options-parameters-input").style.fontSize = div; } #one{ heigh ...

Stop CSS tooltip from overflowing outside of the page or window

One issue I am facing is with a CSS-only tooltip that uses a span to display the tooltip when hovering over a link. The problem arises when the link is positioned near the top or side of a page, causing the tooltip to extend beyond the edge of the page. I ...

Show the helper text when a TextField is selected in Material UI

I would like the error message to only show up when a user clicks on the TextField. Here's my code: import React, { useState, useEffect } from 'react'; import { TextField, Grid, Button } from '@material-ui/core'; const ReplyToComm ...

Reset the counter variable when a certain condition is met

I am facing an issue with my simple "pagination" counter that fetches the next page from an API. The problem arises when I switch between different categories, such as movies or series, because the counter does not reset. Instead of starting again from the ...

Utilizing the reduce method to process an object and return a collection of objects

I have a complex object that I'm trying to transform using the reduce method, but I'm struggling to figure it out... Here is the structure of my object: const object = { ... } My goal is to create a new object with keys that are a combinatio ...

Make sure to wait for the VueX value to be fully loaded before loading the component

Whenever a user attempts to directly navigate and load a component URL, a HTTP call is initiated within my Vuex actions. This call will set a value in the state once it has been resolved. I am looking to prevent my component from loading until the HTTP ca ...

Implementing Bootstrap in Angular 2 using vanilla JavaScript/ES6: A step-by-step guide

Currently, I am in the process of developing an Angular 2 application without TypeScript and facing difficulties with bootstrapping it as I cannot find any relevant examples. My app, which does not include the bootstrap() function, starts off like this: ...

What is the best way to integrate JavaScript and Python for seamless collaboration?

I'm looking to create a bidirectional communication model between JavaScript and Python. The idea is for JavaScript to handle data processing, send it to Python for further processing, and then receive the results back from Python. However, I'm u ...

Ways to allow scroll events on top of an overlay without passing click events

My goal is to develop a unique map annotation tool with custom controls, not relying on the built-in features of map providers. Imagine something like this: https://i.sstatic.net/70Yj7.gif I had the idea of placing a canvas over the map for this purpose ...

What are the reasons behind professional web designers opting for absolute paths over relative paths (like for CSS, Javascript, images, etc.)?

It used to be my belief that everyone utilized relative paths, like /styles/style.css. However, I've noticed that certain renowned web designers (such as and ) prefer absolute paths (http://example.com/styles/style.css). This begs the question - why ...

Implementing a delay using setTimeOut function to execute an action upon user input

Take a look at this code snippet: $("#test").on("keyup", (e) => { if(e.target.value.length === 3) { setTimeout(() => { console.log("fired") }, 2000) } }) <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.m ...

Toggling a div updates the content of a different div

I am looking to make the content within <div class="tcw-content"> dynamically change when a different div is clicked. I have little experience with Ajax, so I'm wondering if there are alternative ways to accomplish this using JS/CSS. If anyone h ...

Improving Vue Method with Lodash?

In one of my Vue components, I have implemented logic in the watch prop that allows for sequential switching between elements when the down arrow key (key code 40) is pressed. While it is not too messy right now, there is a concern that it may become highl ...