Creating SpreadJS custom cells using VUE components

Posted by AcidCool19 on Wed, 12 Jan 2022 05:44:37 +0100

In the previous article, we introduced how to dynamically create spreadsheet components in Vue by setting runtimeCompiler to true. For details, click to view useVUE component creates SpreadJS custom cell (I).

However, in the actual scenario, we may only need to dynamically create VUE components, and the template content of components does not need to be dynamically loaded. In this case, autoComplete is a typical usage scenario.

autoComplete gives us the freedom to convert any input received into a tag & lt; input>,& lt; textarea> And elements with the contenteditable attribute. When keyboard entry is complete, the plug-in starts searching for matching entries and displays a list of available values. By entering more characters, users can filter the list to better match.

stay Front end spreadsheet In, we can directly use it to select the content, such as entering the label of the article or entering the e-mail address in the address book.; Autocomplete can also be used to populate relevant information, such as entering city names and obtaining postal codes. Now, if we want to implement this function in the pure front-end table, we can solidify the dynamically created components, import them on demand, and then mount them.

This simplifies what we mentioned in the previous article. You need to start runtimeCompiler to implement it.

Next, let's introduce the specific methods:

  1. Encapsulating AutoComplete components
  <div>
    <el-autocomplete
      :style="cellStyle"
      popper-class="my-autocomplete"
      v-model="text"
      :fetch-suggestions="querySearch"
      placeholder="Please enter the content"
      :popper-append-to-body="false"
      value-key="name"
      @select="handleSelect"
    >
      <i
        class="el-icon-edit el-input__icon"
        slot="suffix"
        @click="handleIconClick"
      >
      </i>
      <template slot-scope="{ item }">
        <div class="name">{{ item.name }}</div>
        <span class="addr">{{ item.phone }}</span>
      </template>
    </el-autocomplete>
  </div>
</template>
  <script>

import DataService from '../static/dataService'

export default {
    props: ['text','cellStyle'],
    mounted() {
        this.items = DataService.getEmployeesData();
    },
    methods: {
        querySearch(queryString, cb) {
            var items = this.items;
            var results = queryString ? items.filter(this.createFilter(queryString)) : items;
            // Unable to set the location of dynamic content. gcUIElement can be added dynamically
            // setTimeout(() => {
            //   let popDiv = document.getElementsByClassName("my-autocomplete")[0];
            //   if(popDiv){
            //     popDiv.setAttribute("gcUIElement", "gcEditingInput");
            //   }
            // }, 500);
            // Call callback to return the data of the suggestion list
            cb(results);
        },
        createFilter(queryString) {
            return (restaurant) => {
            return (restaurant.name.toLowerCase().indexOf(queryString.toLowerCase()) === 0);
            };
        },
        handleSelect(item) {
            console.log(item);
        },
        handleIconClick(ev) {
            console.log(ev);
        }
    }
}
</script>

There are several points to note

  • The component provides a text (or value) attribute for the value to be edited in the corresponding cell. If the component is not bound in both directions with model, it needs to actively update the text after the operation
  • Provide cellStyle, user CellType, and control the size of the component according to the cell size
  • If the injected DOM element of the component is not inside the template div, you need to add the gcUIElement attribute. The reason is described in detail in the previous article

2. autoComplete mounts components directly without additional dynamic declarations

import AutoComplete from '../components/AutoComplete'

AutoComplateCellType.prototype.activateEditor = function (editorContext, cellStyle, cellRect, context) {
    let width = cellRect.width > 180 ? cellRect.width : 180;
    if (editorContext) {
       // create component constructor
       const AutoCompleteCtor = Vue.extend(AutoComplete);
        this.vm = new AutoCompleteCtor({
        propsData: {
          cellStyle: {width: width+"px"}
        }
      }).$mount(editorContext.firstChild);
    }
};


The rest of the code remains unchanged, which not only eliminates the need for runtimeCompiler, but also improves the maintainability of the code.

The two articles in this series introduce in detail two different methods to solve the problem that the components under the framework cannot be used directly under the framework page through template due to the problems of framework life cycle and custom cell rendering logic. We successfully solved this problem with Vue, and optimized it in the second way to effectively improve the maintainability of the code.

In the future, we will also bring you more interesting content from other angles ~ if you are right Pure front-end spreadsheetSpreadJS If you are interested in other powerful functions, you can actually experience them.

Topics: Front-end IDE