ag-grid编辑表格实现可编辑行和单元格

我们在使用表格时有时会想像excel双击单元格实现数据可编辑,ag-grid也提供了编辑单元格的功能,社区免费版提供了输入框、下拉列表、文本域(大输入框)基础的可编辑控件,企业版则提供了自定义编辑控件功能,我们通过代码来看看怎么使用。如果觉得社区免费版的编辑控件不够用可以通过点选中行然后弹出新的对话框网页来进行编辑保存。

代码示例

//定义表格列
var columnDefs = [
    { headerName: '姓名', field: 'name' },
    {
        headerName: '性别', field: 'sex',
        cellEditor: "agSelectCellEditor",//编辑时 显示下拉列表**************
        cellEditorParams: { values: ["男", "女"] }
    },
    {
        headerName: '年龄', field: 'age'
    },
    { headerName: '籍贯', field: 'jg' },
    {
        headerName: '省份', field: 'sf'
    },
    {
        headerName: '地址', field: 'dz',
        cellEditor: 'agLargeTextCellEditor', //编辑时 显示长文本框**************
        cellEditorParams: {
            maxLength: '300',
            cols: '50',
            rows: '6'
        }
    },
];

//与列对应的数据; 属性名对应上面的field
var data = [
    { name: '张三', sex: '男', age: '100', 'jg': '中国', 'sf': '浙江', 'dz': '杭州市古墩路1号' },
    { name: '李四', sex: '女', age: '5', 'jg': '中国', 'sf': '浙江', 'dz': '杭州市古墩路12号' },
    { name: 'bill', sex: '女', age: '20', 'jg': '中国', 'sf': '浙江', 'dz': '杭州市古墩路31号' },
    { name: 'itxst', sex: '女', age: '26', 'jg': '中国', 'sf': '浙江', 'dz': '杭州市古墩路111号' },
    { name: 'taobao', sex: '男', age: '35', 'jg': '中国', 'sf': '浙江', 'dz': '杭州市古墩路12号' }
];

//将列和数据赋给gridOptions
var gridOptions = {
    columnDefs: columnDefs,
    rowData: data,
    //editType:"fullRow", //开启行编辑
    //行编辑完成事件
     onRowEditingStopped: function (event) {
        var itxst = JSON.stringify(event.data);
        //alert(itxst);
    },
    //单元格编辑完成事件**************************
    onCellEditingStopped: function (event) {
        var itxst = JSON.stringify(event.data);
        alert(itxst);
    },
    onGridReady: function () {
        //表格创建完成后执行的事件
        gridOptions.api.sizeColumnsToFit();//调整表格大小自适应
    },
    defaultColDef: {
        editable: true,//单元表格是否可编辑
    }


};
//在dom加载完成后 初始化agGrid完成
document.addEventListener("DOMContentLoaded", function () {
    var eGridDiv = document.querySelector('#myGrid');
    new agGrid.Grid(eGridDiv, gridOptions);
});

在线试一试

自定义编辑控件(企业版)

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>ag-grid 自定义编辑控件例子</title>
     
  <script src="https://unpkg.com/@ag-grid-enterprise/all-modules@22.1.2/dist/ag-grid-enterprise.min.js"  ></script>
</head>
<body>
    点击表格试试看
    <div id="itxst" style="width: 100%;height: 300px;" class="ag-theme-balham"></div>
    <script>
      var students = [
    {
        first_name: 'Bob', last_name: 'Harrison', gender: 'Male',
        address: '1197 Thunder Wagon Common, Cataract, RI, 02987-1016, US, (401) 747-0763',
        mood: "Happy", country: {name: 'Ireland', code: 'IE'}
    }, {
        first_name: 'Mary', last_name: 'Wilson', gender: 'Female',
        age: 11, address: '3685 Rocky Glade, Showtucket, NU, X1E-9I0, CA, (867) 371-4215',
        mood: "Sad", country: {name: 'Ireland', code: 'IE'}
    }, {
        first_name: 'Sadiq', last_name: 'Khan', gender: 'Male', age: 12,
        address: '3235 High Forest, Glen Campbell, MS, 39035-6845, US, (601) 638-8186',
        mood: "Happy", country: {name: 'Ireland', code: 'IE'}
    }, {
        first_name: 'Jerry', last_name: 'Mane', gender: 'Male', age: 12,
        address: '2234 Sleepy Pony Mall , Drain, DC, 20078-4243, US, (202) 948-3634',
        mood: "Happy", country: {name: 'Ireland', code: 'IE'}
    }
];


// double the array twice, make more data!
students.forEach(function (item) {
    students.push(cloneObject(item));
});
students.forEach(function (item) {
    students.push(cloneObject(item));
});
students.forEach(function (item) {
    students.push(cloneObject(item));
});


function cloneObject(obj) {
    return JSON.parse(JSON.stringify(obj));
}


var columnDefs = [
    {headerName: "First Name", field: "first_name", width: 100, editable: true},
    {headerName: "Last Name", field: "last_name", width: 100, editable: true},
    {
        headerName: "Gender",
        field: "gender",
        width: 90,
        editable: true,
        cellRenderer: 'genderCellRenderer',
        cellEditor: 'agRichSelectCellEditor',
        cellEditorParams: {
            cellRenderer: 'genderCellRenderer',
            values: ['Male', 'Female']
        }
    },
    {
        headerName: "Age",
        field: "age",
        width: 70,
        editable: true,
        cellEditor: 'numericCellEditor' //*********************自定义编辑控件*******************
    },
    {
        headerName: "Mood",
        field: "mood",
        width: 70,
        cellRenderer: 'moodCellRenderer',
        cellEditor: 'moodEditor',
        editable: true
    },
    {
        headerName: "Country",
        field: "country",
        width: 100,
        cellRenderer: 'countryCellRenderer',
        cellEditor: 'agRichSelectCellEditor',
        keyCreator: function(country) {
            return country.name;
        },
        cellEditorParams: {
            cellRenderer: 'countryCellRenderer',
            values: [
                {name: 'Ireland', code: 'IE'},
                {name: 'UK', code: 'UK'},
                {name: 'France', code: 'FR'}
            ]
        },
        editable: true
    },
    {
        headerName: "Address",
        field: "address",
        width: 502,
        editable: true,
        cellEditor: 'agLargeTextCellEditor',
        cellEditorParams: {
            maxLength: '300',   // override the editor defaults
            cols: '50',
            rows: '6'
        }
    }
];


var gridOptions = {
    columnDefs: columnDefs,
    rowData: students,
    onGridReady: function (params) {
        params.api.sizeColumnsToFit();
    },
    onRowEditingStarted: function (event) {
        console.log('never called - not doing row editing');
    },
    onRowEditingStopped: function (event) {
        console.log('never called - not doing row editing');
    },
    onCellEditingStarted: function (event) {
        console.log('cellEditingStarted');
    },
    onCellEditingStopped: function (event) {
        console.log('cellEditingStopped');
    },
    //*******************注册自定义编辑控件***********************
    components:{
        genderCellRenderer: GenderCellRenderer,
        numericCellEditor: NumericCellEditor,
        moodCellRenderer: MoodCellRenderer,
        moodEditor: MoodEditor,
        countryCellRenderer: CountryCellRenderer
    }
};


function getCharCodeFromEvent(event) {
    event = event || window.event;
    return (typeof event.which == "undefined") ? event.keyCode : event.which;
}


function isCharNumeric(charStr) {
    return !!/\d/.test(charStr);
}


function isKeyPressedNumeric(event) {
    var charCode = getCharCodeFromEvent(event);
    var charStr = String.fromCharCode(charCode);
    return isCharNumeric(charStr);
}


// simple function cellRenderer, just returns back the name of the country
function CountryCellRenderer(params) {
    return params.value.name;
}


// **********************************自定义编辑控件**********************************
function NumericCellEditor() {
}


// gets called once before the renderer is used
NumericCellEditor.prototype.init = function (params) {
    // create the cell
    this.eInput = document.createElement('input');


    if (isCharNumeric(params.charPress)) {
        this.eInput.value = params.charPress;
    } else {
        if (params.value !== undefined && params.value !== null) {
            this.eInput.value = params.value;
        }
    }


    var that = this;
    this.eInput.addEventListener('keypress', function (event) {
        if (!isKeyPressedNumeric(event)) {
            that.eInput.focus();
            if (event.preventDefault) event.preventDefault();
        } else if (that.isKeyPressedNavigation(event)){
            event.stopPropagation();
        }
    });


    // only start edit if key pressed is a number, not a letter
    var charPressIsNotANumber = params.charPress && ('1234567890'.indexOf(params.charPress) < 0);
    this.cancelBeforeStart = charPressIsNotANumber;
};


NumericCellEditor.prototype.isKeyPressedNavigation = function (event){
    return event.keyCode===39
        || event.keyCode===37;
};




// gets called once when grid ready to insert the element
NumericCellEditor.prototype.getGui = function () {
    return this.eInput;
};


// focus and select can be done after the gui is attached
NumericCellEditor.prototype.afterGuiAttached = function () {
    this.eInput.focus();
};


// returns the new value after editing
NumericCellEditor.prototype.isCancelBeforeStart = function () {
    return this.cancelBeforeStart;
};


// example - will reject the number if it contains the value 007
// - not very practical, but demonstrates the method.
NumericCellEditor.prototype.isCancelAfterEnd = function () {
    var value = this.getValue();
    return value.indexOf('007') >= 0;
};


// returns the new value after editing
NumericCellEditor.prototype.getValue = function () {
    return this.eInput.value;
};


// any cleanup we need to be done here
NumericCellEditor.prototype.destroy = function () {
    // but this example is simple, no cleanup, we could  even leave this method out as it's optional
};


// if true, then this editor will appear in a popup 
NumericCellEditor.prototype.isPopup = function () {
    // and we could leave this method out also, false is the default
    return false;
};




function GenderCellRenderer() {
}


GenderCellRenderer.prototype.init = function (params) {
    this.eGui = document.createElement('span');
    if (params.value !== "" || params.value !== undefined || params.value !== null) {
        var gender = '<img border="0" width="15" height="10" src="https://raw.githubusercontent.com/ag-grid/ag-grid/master/packages/ag-grid-docs/src/images/' + params.value.toLowerCase() + '.png">';
        this.eGui.innerHTML = gender + ' ' + params.value;
    }
};


GenderCellRenderer.prototype.getGui = function () {
    return this.eGui;
};


function MoodCellRenderer() {
}


MoodCellRenderer.prototype.init = function (params) {
    this.eGui = document.createElement('span');
    if (params.value !== "" || params.value !== undefined || params.value !== null) {
        var imgForMood = params.value === 'Happy' ? 'https://raw.githubusercontent.com/ag-grid/ag-grid/master/packages/ag-grid-docs/src/images/smiley.png' : 'https://raw.githubusercontent.com/ag-grid/ag-grid/master/packages/ag-grid-docs/src/images/smiley-sad.png';
        this.eGui.innerHTML = '<img width="20px" src="' + imgForMood + '" />';
    }
};


MoodCellRenderer.prototype.getGui = function () {
    return this.eGui;
};


function MoodEditor() {
    this.defaultImgStyle = 'padding-left:10px; padding-right:10px;  border: 1px solid transparent; padding: 4px;';
    this.selectedImgStyle = 'padding-left:10px; padding-right:10px; border: 1px solid lightgreen; padding: 4px;';
}


MoodEditor.prototype.onKeyDown = function (event) {
    var key = event.which || event.keyCode;
    if (key == 37 ||  // left
        key == 39) {  // right
        this.toggleMood();
        event.stopPropagation();
    }
};


MoodEditor.prototype.toggleMood = function () {
    this.selectMood(this.mood === 'Happy' ? 'Sad' : 'Happy');
};


MoodEditor.prototype.init = function (params) {
    this.container = document.createElement('div');
    this.container.style = "border-radius: 15px; border: 1px solid grey;background: #e6e6e6;padding: 15px; text-align:center;display:inline-block;outline:none";
    this.container.tabIndex = "0";                // to allow the div to capture keypresses


    this.happyImg = document.createElement('img');
    this.happyImg.src = 'https://raw.githubusercontent.com/ag-grid/ag-grid/master/packages/ag-grid-docs/src/images/smiley.png';
    this.happyImg.style = this.defaultImgStyle;


    this.sadImg = document.createElement('img');
    this.sadImg.src = 'https://raw.githubusercontent.com/ag-grid/ag-grid/master/packages/ag-grid-docs/src/images/smiley-sad.png';
    this.sadImg.style = this.defaultImgStyle;


    this.container.appendChild(this.happyImg);
    this.container.appendChild(this.sadImg);


    var that = this;
    this.happyImg.addEventListener('click', function (event) {
        that.selectMood('Happy');
        params.stopEditing();
    });
    this.sadImg.addEventListener('click', function (event) {
        that.selectMood('Sad');
        params.stopEditing();
    });
    this.container.addEventListener('keydown', function (event) {
        that.onKeyDown(event)
    });


    this.selectMood(params.value);
};


MoodEditor.prototype.selectMood = function (mood) {
    this.mood = mood;
    this.happyImg.style = (mood === 'Happy') ? this.selectedImgStyle : this.defaultImgStyle;
    this.sadImg.style = (mood === 'Sad') ? this.selectedImgStyle : this.defaultImgStyle;
};


// gets called once when grid ready to insert the element
MoodEditor.prototype.getGui = function () {
    return this.container;
};


MoodEditor.prototype.afterGuiAttached = function () {
    this.container.focus();
};


MoodEditor.prototype.getValue = function () {
    return this.mood;
};


// any cleanup we need to be done here
MoodEditor.prototype.destroy = function () {
};


MoodEditor.prototype.isPopup = function () {
    return true;
};


// setup the grid after the page has finished loading
document.addEventListener('DOMContentLoaded', function () {
    var gridDiv = document.querySelector('#itxst');
    new agGrid.Grid(gridDiv, gridOptions);
});
    </script>
</body>
</html>