Using Vuejs to pass the SAVE function into a CRUD component

I am facing a challenge in finding a suitable solution that involves advanced parent-child communication in Vue.js. The scenario is such that there are multiple parent components, each with its own logic on how to save data. On the other hand, there is only one child component that houses a list of elements and a form for creating new elements, but lacks knowledge on how to save the data.

The dilemma is: Is there an alternative (better) approach to achieve the same functionality without relying on this.$refs.child references? I am contemplating if it's possible to simply pass a function (SaveParent1(...) or SaveParent2(...)) to the child component. However, the issue lies in the fact that these functions contain certain variables from the parent that may not be accessible in the child context and these variables could change during runtime.

Some clarifications:

  1. In reality, the methods SaveParent1 and SaveParent2 return a Promise (axios).
  2. The child-component serves as a CRUD used throughout different sections.

Currently, the communication pattern looks like this: CHILD -event-> PARENT -ref-> CHILD.

Below is an example:

<div id="app">
  <h2>&#128512;Advanced Parent-Child Communication:</h2>
  <parent-component1 param1="ABC"></parent-component1>
  <parent-component2 param2="XYZ"></parent-component2>
</div>
Vue.component('parent-component1', {
  props: { param1: { type: String, required: true } },
  methods: {
    onChildSubmit(p) {
        // Here will be some logic to save the param. Many different parents might have different logic and all of them use the same child component. So child-component contains list, form and validation message but does not know how to save the param to the database.
      var error = SaveParent1({ form: { p: p, param1: this.param1 } });
      if (error)
        this.$refs.child.paramFailed(error);
      else
        this.$refs.child.paramAdded(p);
    }
  },
  template: `<div class="parent"><p>Here is parent ONE:</p><child-component ref="child" @submit="onChildSubmit"></child-component></div>`
});

Vue.component('parent-component2', {
  props: { param2: { type: String, required: true } },
  methods: {
    onChildSubmit(p) {
        // Here is a different logic to save the param. In practice it is going to be different requests to the server.
      var error = SaveParent2({ form: { p: p, param2: this.param2 } });
      if (error)
        this.$refs.child.paramFailed(error);
      else
        this.$refs.child.paramAdded(p);
    }
  },
  template: `<div class="parent"><p>Here is parent TWO:</p><child-component ref="child" @submit="onChildSubmit"></child-component></div>`
});

Vue.component('child-component', {
  data() {
    return {
      currentParam: "",
      allParams: [],
      errorMessage: ""
    }
  },
  methods: {
    submit() {
        this.errorMessage = "";
        this.$emit('submit', this.currentParam);
    },
    paramAdded(p) {
        this.currentParam = "";
        this.allParams.push(p);
    },
    paramFailed(msg) {
        this.errorMessage = msg;
    }
  },
  template: `<div><ol><li v-for="p in allParams">{{p}}</li></ol><label>Add Param: <input v-model="currentParam"></label><button @click="submit" :disabled="!currentParam">Submit</button><p class="error">{{errorMessage}}</p></div>`
});

function SaveParent1(data) {
  // Axios API to save data. Below is a simulation.
  if (Math.random() > 0.5)
    return null;
  else
    return 'Parent1: You are not lucky today';
}

function SaveParent2(data) {
  // Axios API to save data. Below is a simulation.
  if (Math.random() > 0.5)
    return null;
  else
    return 'Parent2: You are not lucky today';
}

new Vue({
  el: "#app"
});

A live demo is also available: https://jsfiddle.net/FairKing/novdmcxp/

Answer №1

From an architectural standpoint, my recommendation is to create a service that is completely separate from the component hierarchy. This service can be injected and utilized in each of the components. By implementing this type of component hierarchy and architecture, you can avoid running into common issues. It's crucial to abstract as much functionality and business logic away from the components as possible. In modern frameworks, components should be viewed as enhanced HTML templates, acting primarily as controllers. Keeping components simple and lightweight will help prevent potential problems. Although I am not familiar with vue.js, I hope this guidance gives you some direction.

Answer №2

I believe I've come up with a solution that eliminates the need for two-way communication. By passing a method to the child component, it can handle everything independently without needing to communicate back to the parent. I'm satisfied with this approach and have marked it as the answer. Thank you to everyone for your assistance.

What are your thoughts on this strategy?

Below is the code snippet showcasing my solution:

<div id="app">
  <h2>&#128512;Advanced Parent-Child Communication:</h2>
  <parent-component1 param1="ABC"></parent-component1>
  <parent-component2 param2="XYZ"></parent-component2>
</div>
Vue.component('parent-component1', {
    props: { param1: { type: String, required: true } },
  computed: {
    saveFunc() {
        return function(p) { SaveParent1({ form: { p: p, param1: this.param1 } }); }.bind(this);
    }
  },
  template: `<div class="parent"><p>Here is parent ONE:</p><child-component :saveFunc="saveFunc"></child-component></div>`
});

Vue.component('parent-component2', {
    props: { param2: { type: String, required: true } },
  computed: {
    saveFunc() {
        return function(p) { SaveParent2({ form: { p: p, param2: this.param2 } }); }.bind(this);
    }
  },
  template: `<div class="parent"><p>Here is parent TWO:</p><child-component :saveFunc="saveFunc"></child-component></div>`
});

Vue.component('child-component', {
    props: { 
    saveFunc: { type: Function, required: true }, // This is gonna be a Promise in real life.
  },
  data() {
    return {
      currentParam: "",
      allParams: [],
      errorMessage: ""
    }
  },
  methods: {
    submit() {
        this.errorMessage = "";
      var error = this.saveFunc(this.currentParam);
      if (error)
        this.paramFailed(error);
      else
        this.paramAdded(this.currentParam);
    },
    paramAdded(p) {
        this.currentParam = "";
        this.allParams.push(p);
    },
    paramFailed(msg) {
        this.errorMessage = msg;
    }
  },
  template: `<div><ol><li v-for="p in allParams">{{p}}</li></ol><label>Add Param: <input v-model="currentParam"></label><button @click="submit" :disabled="!currentParam">Submit</button><p class="error">{{errorMessage}}</p></div>`
});

function SaveParent1(data) {
    console.log(data);
    // Axios API to save data
    if (Math.random() > 0.5)
    return null;
  else
    return 'Parent1: You are not lucky today';
}

function SaveParent2(data) {
    console.log(data);
    // Axios API to save data
    if (Math.random() > 0.5)
    return null;
  else
    return 'Parent2: You are not lucky today';
}

new Vue({
  el: "#app"
});

The live demo can be accessed via this link: https://jsfiddle.net/FairKing/novdmcxp/126/

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

Utilize state objects and child components by accessing sub-values within the object

I have a Dropzone component where multiple uploads can happen simultaneously and I want to display the progress of each upload. Within my Dropzone component, there is a state array called uploads: const [uploads, setUploads] = useState([]) Each element i ...

Unable to Click on Selenium Element

When a link is clicked on a website, the URL remains unchanged but a popup appears on the screen containing elements that can only be accessed after running driver.switchTo().defaultContent(). To access these elements, I have used a javascript executor com ...

The server is unable to process the request for /path

After browsing various posts, I am still unable to identify the root cause of my issue. I am developing a donation page for an organization and need to verify if PayPal integration is functioning correctly. The error I am encountering lies between my form ...

Encountering a Vue3/Vite/Vuetify 3 build issue: The variable was not declared with !default in the imported module

Struggling to implement SASS Variables in my Vue 3, Vuetify 3, Vite build as I keep running into an error regarding variables not being declared with !default Following the guidelines provided in theVuetify 3 documentation for configuring SASS Variables. ...

Having trouble adding the Vonage Client SDK to my preact (vite) project

I am currently working on a Preact project with Vite, but I encountered an issue when trying to use the nexmo-client SDK from Vonage. Importing it using the ES method caused my project to break. // app.tsx import NexmoClient from 'nexmo-client'; ...

Encountered an error while using NPM Bootstrap Carousel: Uncaught TypeError - Super expression must be either null or a function

Currently using the NPM build of Bootstrap (with Gulp) for a custom WordPress theme, and I seem to be facing some issues. While I am new to Bootstrap, I have previous experience with WordPress and Gulp (primarily with Foundation). Below is how I am includ ...

Unable to retrieve content using the query.ID in Next.js

I'm trying to figure out what is causing the issue in this code, but I can't seem to resolve it. My goal is to use the query.id inside getInitialProps to fetch some content. The fetching process works fine, but when an error occurs, I receive thi ...

Why is my jQuery $.ajax success function not providing any results?

When checking the Network tab in Chrome, I noticed that the correct data (action, username, password) is being sent, but the message is not returning to $('#return_login'). Can anyone spot what might be wrong with my code? Below is the jQuery co ...

Prevent form submission without JavaScript

While the issue is easy to grasp, it poses a challenge in implementation. I am encountering clients who disable their browser's Javascript by default, causing complications on my website. This is because my website sends ajax requests upon form submis ...

Personalized JSON response type for AJAX requests

Do you think it's possible to achieve this? I have an idea to create a unique dataType called "json/rows". This new dataType would parse the server output text and manipulate it in some way before passing it to the success function. What do you think ...

How can I make a variable available on the client side by exporting it from my Node JS server built with express framework?

How can I send a variable from my Node JS server, which is built using Express, to be accessed on the client side? I need this variable to hold a value stored locally on the server and then access it in my client side JavaScript code. I discovered that ...

Add design to the footer during a specific event using Javascript

Here is the CSS code I am working with: .footer { font-family: "lato", sans-serif; padding: 20px; line-height: 1.2; text-align: right; background: #eee; color: #0D47A1; font-size: 13px; height: 80px; position: fixed; right: 0px; botto ...

The v-bind value remains static even as the data in Vue.js updates

I created a function called changeActive that is supposed to update the value of an active boolean. Interestingly, after checking the console log, I observed that the active value changes but for some reason, the updated value is not being passed in the ...

Using a variable in a Joomla module to create a JavaScript object with PHP

I am currently developing a Joomla module that features a progress bar utilizing the ProgressBar.js plugin. Since this module is designed to load multiple objects on a single page, hardcoding the IDs of these objects is not feasible. To address this, I uti ...

What is the most effective method in React JS to achieve real-time results with every keystroke by making REST calls to the server?

We are dealing with a huge database and the task at hand is to display results as the user types them in the search box. Preloading queries to attempt matching is out of question due to the enormity of our data. Currently, we make a server request with th ...

The anchor tag is not being used in the function call in an Angular application

Having trouble with calling the logout function inside the login controller. The setup involves a simple login and logout system using ui-router. After successfully logging in and navigating to another page, I encountered issues with calling the logout fu ...

Tips for implementing and utilizing an optional parameter within Vue Router

I am trying to set up a route for a specific component that can be accessed in two ways - one with a parameter and one without. I have been looking into optional parameters but haven't found much information. Here is my current route setup: { pa ...

Execute index.js code from index.html using NodeJS and Express

Currently, I am diving into the world of NodeJS and Express using Replit.com for a small project. The main objective is to develop a basic input field that, upon submission, will post to different channels such as Discord and Twitter. The piece of code be ...

What is the best way to combine two JavaScript functions into a single function, especially when the selector and function to be invoked may differ?

In the provided snippet, I am using the following function callers: // del if ( maxDelivery > 0 ) { if ( maxDelivery === 1 ){ delAdressFunc( dels ); } else { for ( i = 0; i < maxDelivery; i += 1 ){ delAdressFunc( ...

Google Maps GeoCoding consistently relies on the language settings of the browser in use

I have implemented the Google AJAX API loader to retrieve information in German by loading the maps API using this code: google.load("maps", "2", {language : "de"}); Despite trying variations such as deu, ger, de, de_DE, and ...