Home > Back-end >  Vue js: How to use mixin function in two components? By execution Error
Vue js: How to use mixin function in two components? By execution Error

Time:11-26

I have 2 components: parent and child and one mixin. I am trying to use one function in both of them. Call mixin function from child component, which is in parent component. This mixin function also changes data var from parent component, which in child referenced in props.

However, on this line of code:

this.modals.filter = 'block'; occurs error: TypeError: Cannot set properties of undefined (setting 'filter')

I cannot get why, as modals.filter is referenced in props already?

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Test</title>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
  </head>
  <body>
    <div id="example" style="width:100%;height:100%">
        <parent></parent>
    </div>
  </body>
  <script>
    var myMixin = { 
        methods: {
            powerbiFilterModal: function() {
                this.modals.filter = 'block';
                if (this.embed.channelName, this.filters.columnName, this.filters.tableName) {
                    // Some other functions
                    // ...
                    console.log(this.embed.channelName, this.filters.columnName, this.filters.tableName);
                    // Hide modal
                    this.modals.filter = 'none';
                    // Clear inputs
                    this.embed.channelName = '';
                    this.filters.columnName = '';
                    this.filters.tableName = '';
                }
            }
        }
    };
    Vue.component('child', {
        mixins: [myMixin],
        template: `
        <div :style="{ display: filterOverlay }">
            <span  style="align-self: flex-end; cursor: pointer;" @click="closeModal">x</span>
            <span  style="align-self: center; margin-bottom: 4%">Filter Settings: </span>
            <input type="text" placeholder="Define channel name" v-model.trim="channelName">
            <input type="text" placeholder="Define filter name" v-model.trim="columnName">
            <input type="text" placeholder="Define table to filter" v-model.trim="tableName">
            <button @click="powerbiFilterModal">Subscribe & Send</button>
        </div>
        `,
        props: {
            filterOverlay: {
                type: String,
                required: false,
                default: 'none'
            },
            channelName: {
                type: String,
                required: false
            },
            columnName: {
                type: String,
                required: false
            },
            tableName: {
                type: String,
                required: false
            }   
        },
        methods: {
            closeModal: function() {
                this.$emit('emitEv', 'none');
            }
        }
    });
    
    Vue.component('parent', {
        mixins: [myMixin],
        template: `
            <div>
                <button @click="powerbiFilterModal">Set Filters</button>
                <child @emitEv="changeOverlay" v-bind:filter-overlay="modals.filter">Child</child>
            </div>
        `,
        data: function() {
            return {
                modals: {
                    filter: 'none'
                },
                embed: {
                    channelName: ''
                },
                filters: {
                    columnName: '',
                    tableName: ''
                }
            }
        },
        methods: {
            changeOverlay: function(value) {
                this.modals.filter = value;
            }
        }
    });
    new Vue({
        el: "#example"
    });
  </script>
</html>

CodePudding user response:

Explaining my comment

Child component

Vue.component("child", {
  // mixins: [myMixin], remove mixin from child
  template: `
  <div>
      <!-- bla bla bla -->
      <button @click="$emit('fire')">Subscribe & Send</button>
  </div>
  ...
  `
});

Parent component

Vue.component("parent", {
  mixins: [myMixin],
  template: `
      <div>
          <button @click="powerbiFilterModal">Set Filters</button>

          <!-- HERE we listen for event (fire) from child and call powerbiFilterModal method from mixin -->
          <child @fire="powerbiFilterModal" @emitEv="changeOverlay" v-bind:filter-overlay="modals.filter">Child</child>
      </div>
  `,
  data: function () {
    return {
      modals: {
        filter: "none"
      },
      embed: {
        channelName: ""
      },
      filters: {
        columnName: "",
        tableName: ""
      }
    };
  },
  methods: {
    changeOverlay: function (value) {
      this.modals.filter = value;
    }
  }
});

CodePudding user response:

powerbiFilterModal() is referencing this.modals, which is OK if it's used in the parent component, but the child component has no such data, so the mixin will cause an error if called within the child.

  • Related