Merging Headers in Element UI Table Component


<el-table-column align="center" label="Standard Output Rate (%)">
  <template slot-scope="scope">
    <span v-if="scope.row.isEditing">
      <el-input v-model="scope.row.stageList[itemIndex].stageLabel" size="mini" placeholder="Enter value" />
    </span>
    <span v-else>{{ scope.row.stageList[itemIndex].stageLabel}}</span>
  </template>
</el-table-column>
<el-table-column align="center" label="Price">
  <template slot-scope="scope">
    <span v-if="scope.row.isEditing">
      <el-input v-model="scope.row.stageList[itemIndex].outputRate" size="mini" placeholder="Enter value" />
    </span>
    <span v-else>{{ scope.row.stageList[itemIndex].outputRate }}</span>
  </template>
</el-table-column>

JavaScript Copmonent


export default {
  data() {
    return {
      loading: false,
      // Table component data object
      tableData: [],
      programList: [],
      editRowJson: ''
    };
  },
  created() {
    this.initializeData();
  },
  methods: {
    fetchData() {
      const records = [
        {
          id: '123',
          name: 'School 1',
          stageList: [
            { programLabel: 'Planned Target', stageLabel: 'Phase 1', outputRate: ''},
            { programLabel: 'Planned Target', stageLabel: 'Phase 2', outputRate: ''},
            { programLabel: 'Planned Target', stageLabel: 'Phase 3', outputRate: ''},
            { programLabel: 'Planned Target', stageLabel: 'Phase 4', outputRate: ''}
          ]
        },
        {
          id: '123',
          name: 'School 1',
          stageList: [
            { programLabel: 'Basic Target', stageLabel: 'Phase 1', outputRate: '' },
            { programLabel: 'Basic Target', stageLabel: 'Phase 2', outputRate: '' },
            { programLabel: 'Basic Target', stageLabel: 'Phase 3', outputRate: '' },
            { programLabel: 'Basic Target', stageLabel: 'Phase 4', outputRate: '' }
          ]
        },
        {
          id: '123',
          name: 'School 1',
          stageList: [
            { programLabel: 'Basic Target', stageLabel: 'Phase 1', outputRate: '' },
            { programLabel: 'Basic Target', stageLabel: 'Phase 2', outputRate: '' },
            { programLabel: 'Basic Target', stageLabel: 'Phase 3', outputRate: '' },
            { programLabel: 'Basic Target', stageLabel: 'Phase 4', outputRate: '' }
          ]
        }
      ];
      // Set table data
      this.tableData = records;
      this.stageList = (records[0] && records[0]['stageList']) || [];
    },
    /**
     * @method processRowData
     * @description Handle editing or saving row data
     */
    processRowData(row, itemIndex) {
      // If another row is being edited, force save first
      for (const schoolItem of this.tableData) {
        if (schoolItem.isEditing && schoolItem.id !== row.id) {
          this.$message({
            type: 'info',
            message: 'Please save the currently editing row first'
          });
          return;
        }
      }
      if (row.isEditing) {
        // Save mode
        for (const programItem of row.programList) {
          // Check for empty values
          for (const stageItem of programItem.stageList) {
            if (stageItem.value === '') {
              this.$message({
                type: 'info',
                message: 'Data fields cannot be empty'
              });
              return;
            }
          }
        }
        this.$set(row, 'isEditing', false);
      } else {
        // Edit mode
        this.editRowJson = JSON.stringify(row);
        this.$set(row, 'isEditing', true);
      }
    },
    /**
     * @method discardChanges
     * @description Cancel editing and revert changes
     */
    discardChanges(row, itemIndex) {
      const editRow = JSON.parse(this.editRowJson);
      row.programList = editRow.programList;
      row.isEditing = !row.isEditing;
    },
    /**
     * @method removeRow
     * @description Delete a table row
     */
    removeRow(row, itemIndex) {
      this.$confirm('Are you sure you want to delete this record?', 'Confirmation', {
        confirmButtonText: 'Confirm',
        cancelButtonText: 'Cancel',
        type: 'warning'
      })
      .then(() => {
        this.tableData.splice(itemIndex, 1);
      })
      .catch(error => {
        console.log(error);
        this.$message({
          type: 'info',
          message: 'Operation cancelled'
        });
      });
    }
  }
};

Tags: Element UI Vue.js Table Headers Frontend Development

Posted on Sat, 11 Jul 2026 16:52:03 +0000 by mclamais