简体   繁体   中英

Dynamically adding elements in vue.js

tl;dr : I am generating a table with editable cells similar to the one pictured below. I have it so the cells are editable and the total updates, but I am struggling to figure out the process I need to follow to actually add new rows and columns.

在此处输入图像描述

All of the cells with the exception of total are editable by the end user, for example cell[ex1][item1] can be changed from 100 to 150, which then causes an event that will update that total for that row from 320 to 370.

Initially I define the main template in the HTML file...

<div class="container" id="app">

    <script type="text/x-template" id="datagrid-template">
        <table class="table-striped">
            <thead>
                <headerrow v-bind:columns="columns"></headerrow>
            </thead>

            <tbody>
            <datarow v-for="row in rows" v-bind:columns="columns" v-bind:data="row"></datarow>
            </tbody>
        </table>
    </script>

    <div class="row">
        <div class="col-sm-10">
            <datagrid v-bind:columns="columns" v-bind:data="rows"></datagrid>
        </div>
        <div class="col-sm-2">
            <div class="row">
                <button type="button" v-on:click="addColumn()">Add Column</button>
            </div>
            <div class="row">
                <button type="button" v-on:click="addRow()">Add Row</button>
            </div>
        </div>
    </div>
</div>

In the JS file I init the main Vue element as such...

var app = new Vue({
  el: "#app",
  data: {
    categories: [...],
    companies: [...]
  },
  methods: {
    addRow: function() {
      console.log(this.$children[0]);
    },
    addColumn: function() {
      this.$children[0].columns.push({value: 'test'});
    }
  }
});

I then have 6 main different component types:

  • datainput (general input cell)
  • dataheader (extends datainput)
  • datacell (extends datainput)
  • baserow (row in the tables)
  • headerrow (extends baserow, composed of dataheaders)
  • datarow (extends baserow, composed of datacells)

I add a row and the cells through as such

baserow

var baseRow = {
  render: function(createElement) {
    return createElement('tr', {}, this.getProps(createElement));
  },
  props: {...}
  }
};

headerrow

Vue.component('headerrow', {
  mixins: [baseRow],
  methods: {
    getProps: function(createElement) {
      var comps = [];
      this.$options.propsData.columns.forEach(function(el) {
        comps.push(createElement('dataheader', {
          props: {...}
        }));
      });
      return comps;
    }
  }
});

When I click add column I can see the 'test' get added to the columns prop when viewing the <datagrid> using the chrome extension. Additionally, I see the 'test' get added to the <headerrow> columns prop, but nothing in the UI is ever actually generated. I am assuming that this is a result of how I initially render the rows and columns, and that I am just having some sort of fundamental misunderstanding... Could anyone provide some direction as to far as what and where I go wrong?

在此处输入图像描述

So it was a fundamental misunderstanding. To accomplish this the data must be used in conjunction with the props. Initially the values must be attached as a prop and then the prop should then be assigned to a data value. The following example highlights what I was trying to do.

var baseRow = {
  render: function(createElement) {
    return createElement('tr', this.createCells(createElement));
  },
  props: {
    initColumns: {
      type: Array,
      default: []
    },
    initData: {
      type: Object,
      default: null
    }
  },
  data: function() {
    return {
      columns: this.initColumns,
      data: this.initData
    }
  }
};

Then to add an element, from the main Vue object (that contains the row component) you can call something similar to this.columns.push({value: 'test'}); . This will update the columns data attribute and will also update the UI.

From my understanding this is a result of the props having aone-way data flow , while the data property is reactive, which is disucessed in this section of the docs .

You can't use anything other than a <tr> within a <tbody> . You can use the Vue directive is to add other components there:

<tbody>
    <tr is="datarow" v-for="row in rows" v-bind:columns="columns" v-bind:data="row"></tr>
</tbody>

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