handsontable在线编辑excel扩展功能-踩坑篇

简述

先说一下背景,之所以封装handsontable插件,是因为公司要实现在线编辑导入excel文件的功能,然后我就找到了这个功能强大的插件handsontable。

具体功能

除了handsontable的功能外,还包括:

1、每一行数据统计错误数,重复数

2、每一列标记重复项,错误项

3、定位功能,当数据过多出现滚动条时,点击上一条/下一条按钮,定位到当前标记项。

4、表头标注每一列数据的校验规则。

5、当数据被编辑后,立即重新校验,并标记重复项、错误项

6、配置isValidate,true则本地校验,false则不校验
(css样式有待改进,后面会更新)

2018/3/30日,修复所有bug,

1、根绝插件局部渲染的特性,将每行的第一列的标注完成局部渲染,以及错误点定位,也根据局部渲染的特性,先滚动到指定行,再进行标记。

2、另外,修复时间控件在最前/后一列/行的情况下,会被遮挡的问题,修改了源码,根据当前单元格的位置来计算时间控件展示的位置。

3、修改源码,将时间控件的英文改为中文。(后面会附上源码修改部分)

2018/4/3日,修改保存错误定位的数据结构,并标记每一个td的row,col位置,保证做到,定位错误点100%准确

 

/*
 * author Happy Guo 
 * date 2018-03-15
 */
'use strict';
define(["jquery","Handsontable"], function ($,Handsontable) {
 var HandsontableExtend = function(opt) {
   this.opt = $.extend(true, {}, opt);
   this.element = document.querySelector(this.opt.el);
   this.header = Object.keys(this.opt.dataObj.headMap);
   this.allErrorNum = [];//记录每一行的错误数
   this.table = null;
   this.errorRow = 0;//统计有几行是有错误的
   this.errorPosition = {
     index:0,
     row: 0,
     col: 0
   };//记录当前被标注的错误位置
   this.firstError = {
    isExist :false,
    row:0,
    col:0
   }
   this.isPosition = false;
   this.position = null;
   //如果没有数据,默认给出一行空行
   if(this.opt.dataObj.dataMap.length===0){
    var obj = {};
     this.header.map(function(item,index){
       obj[item] = {
         value:'',
         errorType:''
       }
     });
    this.opt.dataObj.dataMap.push(obj)
  }
 }
  HandsontableExtend.prototype = {
    constructor: HandsontableExtend,
   // extraType: ["CODE_TYPE","Date"], //不需要校验的类型
    typeMap:{'STRING':'文本','INTEGER':'整型','DOUBLE':'小数','DATE':'日期','CODE_TYPE':'枚举类型','BOOLEAN':'布尔','TIME':'小时分钟'},
    dateFormat:['yyyy-MM-dd','yyyy/MM/dd','yyyy.MM.dd'],
    timePattern:/^([0-1]{1}\d|2[0-3]):([0-5]\d)$/,
    /*@method 整合table的列的配置项
     */
    setColumn: function() {
      var list = [];
      for (var i = 0; i < this.header.length; i++) {
        var obj = {
          data: this.header[i] + ".value",
          width: 150,
          height: 60
        };
        var typeData = this.opt.dataObj.headMap[this.header[i]];
        if (typeData.type === "CODE_TYPE") {
          obj.type = "dropdown";
          obj.source = this.getCodeValueList(typeData.codeValueList);
        }
        if (typeData.type === "BOOLEAN") {
          obj.type = "dropdown";
          obj.source = ['是','否'];
        }
        if(typeData.type === 'TIME'){
          obj.type = "time";
          obj.dateFormat = "h:mm";
        }
        if (typeData.type === "DATE") {
          obj.type = "date";
          obj.dateFormat = "YYYY-MM-DD";
          obj.datePickerConfig={
            firstDay: 1,
            yearRange:100,
            showWeekNumber: true,
            minDate: new Date('1900-01-01')
          }
        }
        list.push(obj);
      }
      return list;
      this.opt.set.columns = list;
    },
    setCell:function(){
      var list = [];
      var that = this;
      this.opt.dataObj.dataMap.map(function(item,index){
        Object.keys(item).forEach(function(key){
          if(item[key].originalValue){
            list.push({
              row:index,
              col:that.header.indexOf(key),
              comment:{
                value:item[key].originalValue
              }
            })
          }
        })
      });
      return list;
    },
    getCodeValueList:function(list){
      var newList = [];
      if(list instanceof Array){
        list.map(function(item,index){
          newList.push(item.displayName);
        });
        return newList;
      }else{
        return [];
      }
    },
    /*@method 初始化table的配置,以及事件监听
     */
    init: function() {
      var that = this;
      this.opt.set = $.extend(true,
        {
          data: that.opt.dataObj.dataMap,
          comments:true,
          columns: this.setColumn(),
          cells: function(row, col, prop) {
            //单元格渲染
            this.renderer = function(instance,td,row,col,prop,value,cellProperties) {
              Handsontable.renderers.TextRenderer.apply(this, arguments);
              var obj = that.opt.dataObj.dataMap[row][that.header[col]];
              $(td).attr({row:row,col:col});
              if (typeof obj["errorType"] !== "undefined") {
                if (obj["errorType"] === "repeat") {
                  $(td).attr({ repeat: true });
                } else if (obj["errorType"] === "error") {
                  $(td).attr({ error: true });
                }
              } else {
                $(td).css({
                  border: "1px solid #ccc",
                  color: "#999",
                  "white-space": "normal",
                  "word-break": "break-all"
                });
              }
              if(obj.originalValue){
                $(td).css({
                  'background-color':'#F1F9FF'
                })
              }
            };
          },
          cell:that.setCell(),
          stretchH: "all",
          width: "100%",
          autoWrapRow: true,
          autoRowSize: true,
          autoColumnSize: true,
          height: "600",
          maxRows: 1000,
          manualRowResize: false,
          manualColumnResize: false,
          // beforeKeyDown : function(e) {
          //     // 禁止选中列后delete键和回退键清空整列数据
          //     if (e.keyCode === 8 || e.keyCode == 46) {
          //         Handsontable.Dom.stopImmediatePropagation(e);
          //     }
          // },
          manualRowMove: true,
          manualColumnMove: true,
          contextMenu: true,
          filters: true,
          dropdownMenu: true
        },
        this.opt.set
      );
      this.opt.set.rowHeaders = function(index) {
        var repeatNum = 0;
        var errorNum =  0;
        if(that.allErrorNum[index] instanceof Array){
          for(var j=0;j<that.allErrorNum[index].length;j++){
            if(that.allErrorNum[index][j].type==='error'){
              errorNum+=1;
            }else{
              repeatNum+=1;
            }
          }
        }
        var html = "<span class='error-th' style='display:"+((that.allErrorNum[index]&&that.allErrorNum[index].length>0)?"block":"none")+"'></span>";
        html +=
          " <span class='error-content'>重复:" + repeatNum +
          ",错误:" + errorNum + "</span>";
        html += "<span id='column_name' style='padding-right:6px;'>" + (index + 1) + "</span>";
        return html;
      };
      this.opt.set.colHeaders = function(index) {
        var desc = that.header[index]+"规则:";
        var map = that.opt.dataObj.headMap[that.header[index]];
        if(map.minLength&&map.maxLength){
          desc=desc+'长度:'+map.minLength+'-'+map.maxLength;
        }else if(map.length){
          desc=desc+'长度:'+map.length
        }
        if(map.type){
          desc=desc+',类型:'+that.typeMap[map.type]
        }
        if(map.required){
          desc=desc+',必填'
        }
        if(map.unique){
          desc=desc+',不能重复'
        }
        var html = "<span class='remark-th'></span>";
        html += " <span class='remark-content'>"+desc+"</span>";
        if(map.required){
          html += "<span id='column_name' style='color:#ED5565'>" + that.header[index] + "</span>";
        }else{
          html += "<span id='column_name'>" + that.header[index] + "</span>";
        }
        return html;
      };
      this.table = new Handsontable(this.element, this.opt.set);
      this.table.updateSettings({
        contextMenu: {
          callback: function(key, options) {
            if (key === "about") {
              setTimeout(function() {
                // timeout is used to make sure the menu collapsed before alert is shown
                alert(
                  "This is a context menu with default and custom options mixed"
                );
              }, 100);
            }
          },
          items: {
            row_above: {
              name: "向上插入一行",
              disabled: function() {
                return that.table.getSelected()[0] === 0;
              }
            },
            remove_row: {
              name: "删除选中行",
              disabled: function() {
                // if first row, disable this option
                return that.table.getSelected()[0] === 0;
              }
            }
          }
        }
      });
      window.onresize = this.opt.isValidate
        ? function() {
            that.render.call(that);
          }
        : null;
      this.table.addHook("afterChange", function() {
        that.opt.isValidate && that.render.call(that);
      });
      this.table.addHook("afterRemoveRow", function() {
        that.opt.isValidate && that.render.call(that);
      });
      var topValue = 0,leftValue = 0;
      var interval = null;
      $(this.opt.el + " .wtHolder")[0].onscroll = function() {
        if (interval == null) {
          interval = setInterval(isFinishScroll, 1000);
        }
      };
      function isFinishScroll() {
        // 判断此刻到顶部的距离是否和1秒前的距离相等
        if ($(that.opt.el + " .wtHolder")[0].scrollLeft === leftValue && $(that.opt.el + " .wtHolder")[0].scrollTop === topValue) {
          clearInterval(interval);
          interval = null;
          that.validate();
          that.renderError(); 
          that.remarkShow();//渲染表头、列头标注
          if(that.position){
            $("td[row='"+that.errorPosition.row+"'][col='"+that.errorPosition.col+"']").attr('current');
          }
        } else {
          topValue = $(that.opt.el + " .wtHolder")[0].scrollTop;
          leftValue = $(that.opt.el + " .wtHolder")[0].scrollLeft;
        }
      }
      this.render();
      return this;
    },
    /*@method 渲染整个table数据
     */
    render: function() {
      var table = this.table;
      this.validate.call(this); //初始化,先验证,并标记重复项
      table.render(); //并渲染在行首部
      this.renderError();
      this.remarkShow();//渲染表头、列头标注
      $(".htInvalid").removeClass('htInvalid');
      $("td[current]").removeAttr('current');
    },
    /*@method 渲染出表头和列头的标注信息
     */
    remarkShow:function(){
      $(".remark-th").hover(function(){
        var top = $(this).closest('th').offset().top;
        var left = $(this).closest('th').offset().left;
        $(this).next().css({'top':top,"left":left})
      });
      $(".error-th").hover(function(){
        var top = $(this).closest('th').offset().top;
        var left = $(this).closest('th').offset().left+10;
        $(this).next().css({'top':top,"left":left})
      })
    },
    /*@method 渲染出重复、错误的单元格
     */
    renderError: function() {
      var that = this;
       var rowHeaderTr = $(".ht_clone_left .htCore").eq(0).find("tbody").find("tr");
       var tr = $(this.opt.el + " .htCore").eq(0).find("tbody").find("tr");
      //渲染错误项(只渲染当前可视区域的),
      //此处天坑,行头是单独的table,之前滚动后渲染位置错误。
      for (var i = 0; i < tr.length; i++) {
        var rowNum =  $(tr[i]).find("th #column_name").text();
        rowNum = parseInt(rowNum) - 1;
        //统计每一行错误项、重复项,如果列数过多,则列会渲染不完全,所以不能用选择器查出准确数据,只能使用统计出的数据
        var repeatNum = 0;
        var errorNum =  0;
        if(that.allErrorNum[rowNum] instanceof Array){
          for(var j=0;j<this.allErrorNum[rowNum].length;j++){
            if(this.allErrorNum[rowNum][j].type==='error'){
              errorNum+=1;
            }else{
              repeatNum+=1;
            }
          }
        }
        var errorTH = $(rowHeaderTr[i]).find("th .error-th").eq(0);
        if(repeatNum+errorNum>0){
          errorTH.css({'display':'block'});
          var top = errorTH.offset().top;
          var left = errorTH.offset().left+10;
          errorTH.next().css({'top':top,"left":left})
          errorTH.next().text('重复:'+repeatNum+',错误:'+errorNum);
        }else{
          errorTH.css({'display':'none'});
        }
        $(tr[i]).find("th .error-th,th .error-content").remove();//将另一处被渲染的行标注删除,防止误导
      }
      this.remarkShow();
    },
    /*@method 验证
     */
    validate: function() {
      var table = this.table;
      var that = this;
      this.allErrorNum = [];//初始化统计错误array
      this.firstError = {
        isExist :false,
        row:0,
        col:0
       };//初始化,第一个错误位置改为不存在
      var cellLength = table.getDataAtRow(0).length;
      var errorRows = [];
      for (var i = 0; i < cellLength; i++) {
        var cellData = table.getDataAtCol(i);
       // var newArr = [];
        cellData.map(function(item, index, arr) {
          var NewCell;
          var validateRule = that.opt.dataObj.headMap[that.header[i]];
          var dataMap = that.opt.dataObj.dataMap[index][that.header[i]];
          //if (newArr.indexOf(index) === -1) {
            //如果被重复项最后一个索引已有渲染标志,则不删除渲染标志。
            NewCell = table.getCell(index, i);
            $(NewCell).removeAttr("error");
            $(NewCell).removeAttr("repeat");
            dataMap["errorType"] = "";
          //}
          if (validateRule.required && !item) {
            dataMap["errorType"] = "error";
            $(NewCell).attr("error", true);
            that.setAllErrorNum.call(that,index,i,"error");
            errorRows.indexOf(index)===-1 && errorRows.push(index);
            return;
          }
          if(item){
            if (validateRule.type &&
              validateRule.type === "CODE_TYPE") {
              var list = that.getCodeValueList(validateRule.codeValueList);
              if(list.indexOf(item)===-1){
                dataMap["errorType"] = "error";
                $(NewCell).attr("error", true);
                that.setAllErrorNum.call(that,index,i,"error");
                errorRows.indexOf(index)===-1 && errorRows.push(index);
                return;
              }
            }
            if(validateRule.type && validateRule.type === "BOOLEAN"){
              if(['是','否'].indexOf(item)===-1){
                dataMap["errorType"] = "error";
                $(NewCell).attr("error", true);
                that.setAllErrorNum.call(that,index,i,"error");
                errorRows.indexOf(index)===-1 && errorRows.push(index);
                return;
              }
            }
            if (
              validateRule.type &&
              validateRule.type === "DATE"
            ) {
              var result = false;
              that.dateFormat.map(function(format,index){
                if(new Date(item).format(format)===item){
                  result = true;
                }
              })
              if(!result){
                dataMap["errorType"] = "error";
                $(NewCell).attr("error", true);
                that.setAllErrorNum.call(that,index,i,"error");
                errorRows.indexOf(index)===-1 && errorRows.push(index);
                return;
              }
            }
            if(validateRule.type &&
              validateRule.type === "TIME" && !that.timePattern.test(item)){
              dataMap["errorType"] = "error";
              $(NewCell).attr("error", true);
              that.setAllErrorNum.call(that,index,i,"error");
              errorRows.indexOf(index)===-1 && errorRows.push(index);
              return;
            }
            if(validateRule.type &&
              validateRule.type === "INTEGER" && parseInt(item)!=item){
                dataMap["errorType"] = "error";
                $(NewCell).attr("error", true);
                that.setAllErrorNum.call(that,index,i,"error");
                errorRows.indexOf(index)===-1 && errorRows.push(index);
                return;
            }
            if(validateRule.type &&
              validateRule.type === "DOUBLE" && parseFloat(item)!=item){
              dataMap["errorType"] = "error";
              $(NewCell).attr("error", true);
              that.setAllErrorNum.call(that,index,i,"error");
              errorRows.indexOf(index)===-1 && errorRows.push(index);
              return;
            }
            if (parseInt(validateRule.minLength) && item.length < parseInt(validateRule.minLength)) {
              dataMap["errorType"] = "error";
              $(NewCell).attr("error", true);
              that.setAllErrorNum.call(that,index,i,"error");
              errorRows.indexOf(index)===-1 && errorRows.push(index);
              return;
            }
            if (parseInt(validateRule.maxLength) && item.length > parseInt(validateRule.maxLength)) {
              dataMap["errorType"] = "error";
              $(NewCell).attr("error", true);
              that.setAllErrorNum.call(that,index,i,"error");
              errorRows.indexOf(index)===-1 && errorRows.push(index);
              return;
            }
            if ((!validateRule.maxLength && !validateRule.minLength&& validateRule.length) && item.length !== validateRule.length) {
              dataMap["errorType"] = "error";
              $(NewCell).attr("error", true);
              that.setAllErrorNum.call(that,index,i,"error");
              errorRows.indexOf(index)===-1 && errorRows.push(index);
              return;
            }
            if (validateRule.regexp) {
              var pattern = new RegExp(validateRule.regexp);
              if(!pattern.test(item)){
                dataMap["errorType"] = "error";
                $(NewCell).attr("error", true);
                that.setAllErrorNum.call(that,index,i,"error");
                errorRows.indexOf(index)===-1 && errorRows.push(index);
                return;
              }
            }
            if (validateRule.unique && that.getRepeatNum(arr,item,index)) {
              $(NewCell).attr("repeat", true);
              dataMap["errorType"] = "repeat";
              that.setAllErrorNum.call(that,index,i,"repeat");
              errorRows.indexOf(index)===-1 && errorRows.push(index);
            }
          }
        });
      }
      $(".htInvalid").removeClass('htInvalid');
      this.errorRow = errorRows.length;
    },
    /*@method 辅助方法,获取table中第一个错误点的位置
     */
    setAllErrorNum:function(x,y,type){
      if(!this.firstError.isExist||this.firstError.row>x){
        this.firstError = {
          isExist:true,
          row:x,
          col:y
        };
      }
      if(!this.allErrorNum[x]){
       this.allErrorNum[x] = [];
      } 
      this.allErrorNum[x].push({
        type:type,
        row:x,
        col:y
      });
      //如果在已经定位的情况下,又修改了其他单元格到处出现新的数据,那么此处的错误定位要重新定位
      if(x === this.errorPosition.row && y === this.errorPosition.col){
        this.errorPosition.index = this.allErrorNum[x].length-1;
      }
    },
    /*@method 辅助方法,判断数组中某一个值是否有重复项
     */
    getRepeatNum:function(arr,val,i){
      var result = false;
      arr.map(function(item,index,array){
        if(item===val && index!==i){
          result = true;
        }
      })
      return result;
    },
    /*@method 下一个错误调用方法
     */
    nextError: function() {
      if (this.position) {
        $("td[current]").removeAttr("current");
        this.position = "next";
        this.nextErrorPostion();
        this.isPosition = true;
        this.scrollToError();
      }
    },
    /*@method 上一个错误调用方法
     */
    prevError: function() {
      if (this.position) {
        $("td[current]").removeAttr("current");
        this.position = "prev";
        this.prevErrorPosition();
        this.isPosition = true;
        this.scrollToError();
      }
    },
    /*@method 计算出下一个错误单元格的位置
     */
    nextErrorPostion: function() {
      var length = this.allErrorNum[this.errorPosition.row].length;
      if (this.errorPosition.index < length - 1) {
        this.errorPosition.index += 1;
        this.errorPosition.col = this.allErrorNum[this.errorPosition.row][this.errorPosition.index].col;
      } else {
        var maxLength = this.allErrorNum.length;
        for (var i = this.errorPosition.row + 1; i < maxLength; i++) {
          if (this.allErrorNum[i] instanceof Array &&this.allErrorNum[i].length>0) {
            this.errorPosition = {
              index:0,
              row: i,
              col: this.allErrorNum[i][0].col
            };
            return;
          }
        }
        if (i === maxLength && (this.errorPosition.index === this.allErrorNum[i-1].length-1)) {
          this.errorPosition = {
            index:0,
            row: this.firstError.row,
            col: this.firstError.col
          };
        }
      }
    },
    /*@method 计算出上一个错误单元格的位置
     */
    prevErrorPosition: function() {
      var length = this.allErrorNum[this.errorPosition.row].length;
      if (this.errorPosition.index > 0) {
        this.errorPosition.index -= 1;
        this.errorPosition.col = this.allErrorNum[this.errorPosition.row][this.errorPosition.index].col;
      } else {
        for (var i = this.errorPosition.row - 1; i >= 0; i--) {
          if (this.allErrorNum[i] instanceof Array &&this.allErrorNum[i].length>0) {
            var len = this.allErrorNum[i].length-1;
            this.errorPosition = {
              index:this.allErrorNum[i].length-1,
              row: i,
              col: this.allErrorNum[i][len].col
            };
            return;
          }
        }
      }
    },
    /*@method 滚动到errorPosition记录的位置
     */
    scrollToError: function() {
      var that = this;
      var tr = $(that.opt.el + " .htCore tbody").find("th #column_name:contains('"+(that.errorPosition.row+1)+"')").closest('tr');
      var lastTd = (tr.length>0)?tr.find("td[col='"+this.errorPosition.col+"']"):'';
      //滚动到对应行的位置,并且插件会自动渲染出新的可视区域,此时再找出定位的单元格,并标记
      $(this.opt.el + " .wtHolder").animate({ scrollTop: (this.errorPosition.row-5)*28 }, 300);
      lastTd = tr.find("td[col='"+that.errorPosition.col+"']");
      $(this.opt.el + " .wtHolder").animate({ scrollLeft: (this.errorPosition.col-1)*150 }, 300);
      setTimeout(function(){
      //此处因为是定时器,所以要注意tr和ladtTd会在定时器回掉函数开始执行时消失,所以要在定时器中重新定义,或者使用闭包
        var tr = $(that.opt.el + " .htCore tbody").find("th #column_name:contains('"+(that.errorPosition.row+1)+"')").closest('tr');
        lastTd = tr.find("td[col='"+that.errorPosition.col+"']");
        $(lastTd).attr("current",true);
        that.isPosition = false;
      },600)
    },
    /*@method 标记当前错误点
     */
    currentError: function(){
      if(!this.position){
        this.errorPosition.row = this.firstError.row;
        this.errorPosition.col = this.firstError.col;
      }
      this.isPosition = true;
      this.position = "current";
      this.scrollToError();
    },
    /*@method 获取有多少条记录是有错误的、正确的 
     *@return array [总记录数,错误数,正确数]
     */
    getErrorNum:function(){
      var total = this.opt.dataObj.dataMap.length;
      return [total,this.errorRow,total-this.errorRow];
    },
    /*@method 获取到编辑后的table数据
     */
    getData: function() {
      return this.opt.dataObj;
    }
  };
  $.fn.HandsontableExtend = function (opts) {
   var hand = new HandsontableExtend(opts);
   return hand.init(window);
  };
})

 

//修改源码部分:
//第36508行,function showDatepicker(event)的部分,228,258分别为时间控件的高和宽
      if(this.TD.offsetTop+228>holder.offsetHeight){
        this.datePickerStyle.top = window.pageYOffset + offset.top - 228 + 'px';
      }else{
        this.datePickerStyle.top = window.pageYOffset + offset.top + (0, _element.outerHeight)(this.TD)  + 'px';
      }
      if(this.TD.offsetLeft+258>holder.offsetWidth){
        this.datePickerStyle.left = window.pageXOffset + offset.left - (0, _element.outerWidth)(this.TD) + 'px';
      }else{
        this.datePickerStyle.left = window.pageXOffset + offset.left + 'px';
      }
      //this.datePickerStyle.top = window.pageYOffset + offset.top + (0, _element.outerHeight)(this.TD) + 'px';
      //this.datePickerStyle.left = window.pageXOffset + offset.left + 'px';
//i18n,json对象改为
i18n:{
            previousMonth : '上一月',
            nextMonth     : '下一月',
            months        : ['一月','二月','三月','四月','五月','六月','七月','八月','九月','十月','十一月','十二月'],
            weekdays      : ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'],
            weekdaysShort : ['周日','周一','周二','周三','周四','周五','周六']
        }

 

 调用方法:


var handTableExtend = $("#hot").HandsontableExtend({
el:'#hot',
dataObj:$scope.dataObject,
isValidate:true,
set:{
height: 500
}
})
//dataObject接受的数据结构
dataObject = {
                headMap:{
                    '姓名':{
                        isRequired:true,
                        type:'string',
                        minLength:2,
                        maxlength:20,
                        isUnique:false
                    },
                    '性别':{
                        isRequired:false,
                        type:'string',
                        isUnique:false
                    },
                    '身份证号':{
                        isRequired:true,
                        type:'string',
                        minLength:9,
                        maxlength:20,
                        isUnique:true,
                        regexp:/^[1-9][0-9]{5}(19|20)[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|31)|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}([0-9]|x|X)$/
                    },
                    '联系电话':{
                        isRequired:true,
                        type:'string',
                        //length:11,
                        isUnique:true
                    },
                    '地址':{
                        isRequired:false,
                        type:'string',
                        maxLength:50,
                        isUnique:false
                    },
                    '职位':{
                        isRequired:false,
                        type:'string',
                        isUnique:false
                    },
                    '部门':{
                        isRequired:false,
                        type:'code_type',
                        enumData:['it部','hr部','后勤部','销售部'],
                        isUnique:false
                    },
                    '入职日期':{
                        isRequired:false,
                        type:'date',
                        isUnique:false
                    }
                },
                dataMap:[
                    {
                        '姓名':{
                            value:'张三',
                            errorType:''
                        },
                        '性别':{
                            value:'男',
                            errorType:''
                        },
                        '身份证号':{
                            value:'',
                            errorType:''
                        },
                        '联系电话':{
                            value:'18817802351',
                            errorType:'repeat'
                        },
                        '地址':{
                            value:'上海浦东',
                            errorType:''
                        },
                        '职位':{
                            value:'it',
                            errorType:''
                        },
                        '部门':{
                            value:'it部',
                            errorType:''
                        },
                        '入职日期':{
                            value:'it部',
                            errorType:''
                        }
                    },{
                        '姓名':{value:'李四1',
                        errorType:''},
                        '性别':{value:'女',
                        errorType:''},
                        '身份证号':{value:'111222',
                        errorType:''},
                        '联系电话':{value:'18817802351',
                        errorType:''},
                        '地址':{value:'上海浦东',
                        errorType:''},
                        '职位':{value:'it',
                        errorType:''},
                        '部门':{value:'it部',
                        errorType:''},
                        '入职日期':{value:'it部',
                        errorType:''}
                    },{
                        '姓名':{value:'李四1',
                        errorType:''},
                        '性别':{value:'女',
                        errorType:''},
                        '身份证号':{value:'111222',
                        errorType:''},
                        '联系电话':{value:'18817802351',
                        errorType:''},
                        '地址':{value:'上海浦东',
                        errorType:''},
                        '职位':{value:'it',
                        errorType:''},
                        '部门':{value:'it部',
                        errorType:''},
                        '入职日期':{value:'it部',
                        errorType:''}
                    }
                ]
            }; 

页面html代码

<div ng-controller="SurveyHandsontable">
    <button id="prev" ng-click="prevError()">></button>
    <button id="next" ng-click="nextError()"><</button>
    <div id="hot"></div>
    <button ng-click="getData()">点击</button>
</div>

 

posted @ 2018-03-15 16:36  happyYawen  阅读(4982)  评论(0编辑  收藏  举报