简体   繁体   中英

Vue warning and dialog only appears once

Having vue ui, creating a basic new project with Babel and Lint, I installed deps vuetify, vuetify-loader, and vue-bootstrap. All I want is a simple 'open dialog' button that open a dialog defined in a separate component (file). The dialog shows, without problems/warnings, but when I close it (either by clicking elsewhere or on one of the buttons, I get a warning about "Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders." Clicking the button again has no longer effect. Although the "JAAA" is shown in the console. The code:

HelloWorld.vue

<template>
  <div class="hello">

    <v-btn @click="openDialog" class="btn btn-info">Open dialog</v-btn>
                <Dialog :showDialog="showDialog"></Dialog>
  </div>
</template>

<script>
  import Dialog from "./Dialog";
  export default {
    name: 'HelloWorld',
    components: {
      Dialog
    },
    props: {
      msg: String
    },
    data() {
      return {
              showDialog: false
          }
      },
      methods: {
        openDialog() {
          this.showDialog = true
          window.console.log('JAAA')
        }
      }
  }
</script>

Dialog.vue

<template>
  <div>
    <v-dialog v-model="showDialog" width="500">
      <v-card>
        <v-card-title class="headline grey lighten-2" primary-title>
          Remark
        </v-card-title>
        <v-card-text>
          Remark: <input type="text">
        </v-card-text>
        <v-divider></v-divider>
        <v-card-actions>
          <div class="flex-grow-1"></div>
          <v-btn color="primary" text @click="hideDialog">
            Done
          </v-btn>
          <v-btn color="primary" text @click="hideDialog">
            Cancel
          </v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
  </div>
</template>

<script>
    export default {
        name: "Dialog",
        props: ['showDialog'],
        methods: {
          hideDialog() {
            this.showDialog = false;
          }
        }
    }
</script>

Mutating the value in child will not reflect to parent, the props data flows at the time of child component created hook and while closing you are try to mutate it in child level and the state is not shared with the parent. From the next time onwards its just calls updated hook in dialog box

Make these changes to the Dialog.vue component

<template>
  <div>
    <v-dialog v-model="displayDialog" width="500">
      <v-card>
        <v-card-title class="headline grey lighten-2" primary-title>
          Remark
        </v-card-title>
        <v-card-text>
          Remark: <input type="text">
        </v-card-text>
        <v-divider></v-divider>
        <v-card-actions>
          <div class="flex-grow-1"></div>
          <v-btn color="primary" text @click="hideDialog">
            Done
          </v-btn>
          <v-btn color="primary" text @click="hideDialog">
            Cancel
          </v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
  </div>
</template>

<script>
    export default {
        name: "Dialog",
        props: {
          showDialog: {
            type: Boolean,
          }
        },
        data() {
          return {
            displayDialog: false,
          };
        },
        methods: {
          hideDialog() {
            this.displayDialog = false;
          }
        },
       watch: {
          showDialog(val) {
             this.displayDialog  = val;
          }
       }
    }
</script>

You should not change the values of props directly in a component as the change will not be reflected in your parent.

You can instead convert your dialog component to use a v-model instead combined with a computed property in your child to emit changes to your parent so that it knows the value has been updated.

HelloWorld.vue

<template>
  <div class="hello">
    <v-btn @click="openDialog" class="btn btn-info">Open dialog</v-btn>
    <Dialog v-model="showDialog"></Dialog>
  </div>
</template>

<script>
import Dialog from "./Dialog";
export default {
  name: 'HelloWorld',
  components: {
    Dialog
  },
  props: {
    msg: String
  },
  data() {
    return {
      showDialog: false
    }
  },
  methods: {
    openDialog() {
      this.showDialog = true
      window.console.log('JAAA')
    }
  }
}
</script>

Dialog.vue

<template>
  <div>
    <v-dialog v-model="displayDialog" width="500">
      <v-card>
        <v-card-title class="headline grey lighten-2" primary-title>
          Remark
        </v-card-title>
        <v-card-text>
          Remark: <input type="text">
        </v-card-text>
        <v-divider></v-divider>
        <v-card-actions>
          <div class="flex-grow-1"></div>
          <v-btn color="primary" text @click="hideDialog">
            Done
          </v-btn>
          <v-btn color="primary" text @click="hideDialog">
            Cancel
          </v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
  </div>
</template>

<script>
export default {
  name: "Dialog",
  props: {
    value: {
      type: Boolean,
      default: false
    }
  },
  computed: {
    displayDialog: {
      get() {
        // returns the value of your prop
        return this.value 
      },
      set(newValue) {
        // v-model listens to the input event, so emitting `input` with a value 
        // will update the model with that value
        this.$emit('input', newValue)
      }
    };
  },
  Methods: {
    hideDialog() {
      this.displayDialog = false;
    }
  }
}
</script>

This worked for me => To close the dialog all you have to do is emit an event to the parent component and change the value of dialog property(ie close dialog from parent not from child)

      <div class="hello">
            <Dialog v-model="showDialog" @closeDialog="showDialog=false"> <Dialog>
      </div>

dialog component =>

  <v-dialog v-model="displayDialog" width="500">
      .....
        <v-card-actions>
          <div class="flex-grow-1"></div>
          <v-btn color="primary" text @click="$emit('closeDialog')">
            Done
          </v-btn>
          <v-btn color="primary" text @click="$emit('closeDialog')">
            Cancel
          </v-btn>
        </v-card-actions>
     ......
    </v-dialog>


  export default {
        name: "Dialog",
        props: {
          showDialog: {
            type: Boolean,
          }
        },
        data() {
          return {
            displayDialog:this.showDialog,
          };
        },

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM