Warm tip: This article is reproduced from stackoverflow.com, please click
crud javascript parent-child vue.js

Vuejs: Passing SAVE function into CRUD component

发布于 2020-05-03 02:46:44

I am struggeling with a proper solution which requires an advanced parent-child communication in vuejs. There can be many different parent components which has a logic how to save data. From the other side there will be only one child component which has a list of elements and a form to create new elements but it doesn't know how to save the data.

The question is: Is there any other way (better approach) to have the same functionality but to get rid of this.$refs.child links. For example I am wondering if I can just pass a function (SaveParent1(...) or SaveParent2(...)) to the child component. But the problem is the function contains some parent's variables which won't be available in child context and those variables could be changed during the runtime.

Just few clarifications:

  1. The methods SaveParent1 and SaveParent2 in real life return Promise (axios).
  2. The child-component is like a CRUD which is used everywhere else.

At the moment the communication looks like that: CHILD -event-> PARENT -ref-> CHILD.

Bellow is the 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 prictice it is gonna 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. Bellow 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. Bellow is a simulation.
  if (Math.random() > 0.5)
    return null;
  else
    return 'Parent2: You are not lucky today';
}

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

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

Questioner
ADM-IT
Viewed
30
ADM-IT 2020-02-16 21:31

I think I have found a solution. So no two ways communication. I can just pass a method and the child will do everything without communicating with parent. I am happy with that I am marking it as an answer. Thanks everyone for your help.

Let me please know what do you think guys.

Bellow is 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 demo link: https://jsfiddle.net/FairKing/novdmcxp/126/