Custom Validation

With SpreadJS you can use custom data validation in a worksheet.

Description
app.vue
index.html
Copy to CodeMine

You can customize the validator’s title, input message, error message, and so on. With these settings you will know what data can or should be entered in a cell, and when the data is invalid you will get a message.

When you use the validator object, you can set its properties. For example:

    var dv1 = sheet.getDataValidator(1, 1);
    dv1.inputTitle('Please choose a category:');
    dv1.inputMessage('Fruit, Vegetable, Food');
    dv1.showInputMessage(true); //whether to display the input title and input message.
    dv1.showErrorMessage(true); //whether to display an error message.
    dv1.inCellDropdown(true); //whether to display a drop-down button.
    dv1.ignoreBlank(false); //whether to ignore an empty value.
    dv1.errorStyle(GC.Spread.Sheets.DataValidation.ErrorStyle.stop);

When you input invalid data, the control will trigger the ValidationError event. For example:

    sheet.bind(GC.Spread.Sheets.Events.ValidationError, function(e, args) {
       // do some thing.
    });
You can customize the validator’s title, input message, error message, and so on. With these settings you will know what data can or should be entered in a cell, and when the data is invalid you will get a message. When you use the validator object, you can set its properties. For example: When you input invalid data, the control will trigger the ValidationError event. For example:
<template> <div class="sample-tutorial"> <gc-spread-sheets class="sample-spreadsheets" @workbook-initialized="initSpread"> <gc-worksheet></gc-worksheet> </gc-spread-sheets> <div class="options-container"> <p> Select a cell or range of cells in the sheet then use the options below to create a data validator for that cell(s). You can also set the input message that displays when the user tries to edit the cell(s) as well as the error message that shows if the input does not fit the conditions. </p> <div class="option-row"> <select id="validatorTypes" @change="changeValidatorTypes"> <option value="DateValidator" selected>DateValidator</option> <option value="FormulaListValidator">FormulaListValidator</option> <option value="FormulaValidator">FormulaValidator</option> <option value="ListValidator">ListValidator</option> <option value="NumberValidator">NumberValidator</option> <option value="TextLengthValidator">TextLengthValidator</option> </select> </div> <div id="validatorTab1"> <div class="option-row"> <select id="validatorComparisonOperator" @change="changeValidatorComparisonOperator"> <option value="6" selected>Between</option> <option value="7">NotBetween</option> <option value="0">EqualTo</option> <option value="1">NotEqualTo</option> <option value="2">GreaterThan</option> <option value="4">LessThan</option> <option value="3">GreaterThanOrEqualTo</option> <option value="5">LessThanOrEqualTo</option> </select> </div> <div class="option-row"> <input class="normal-input" id="txtValidatorValue1" type="text" placeholder="Value1" /> </div> <div class="option-row"> <input class="normal-input" id="txtValidatorValue2" type="text" placeholder="Value2" /> </div> <div class="option-row" id="isIntTab"> <input class="normal-input" id="chkIsInteger" type="checkbox" /><label for="chkIsInteger">Is Integer</label> </div> </div> <div class="option-row" id="validatorTab2"> <input class="normal-input" type="text" id="txtValidatorValue" placeholder="Value1" /> </div> <div class="option-row" id="validatorTab3"> <input class="normal-input" type="text" id="txtListValidatorValue" placeholder="(eg:1,2,3,4,5)" /> <input class="normal-input" type="checkbox" id="ckbIncellDropDown" checked="checked" /> <label for="ckbIncellDropDown">Show In-Cell DropDown</label> </div> <div class="option-row"> <input class="normal-input" type="checkbox" checked="checked" id="ckbShowInputMessage" /> <label for="ckbShowInputMessage">Show InputMessage</label> </div> <div class="option-row"> <label>Title:</label> <input class="normal-input" type="text" id="txtInputTitle" placeholder="Title" /> </div> <div class="option-row"> <label>Input Message:</label> <input class="normal-input" type="text" id="txtInputMessage" placeholder="Input Message" /> </div> <div class="option-row"> <input class="normal-input" id="chkShowError" type="checkbox" @change="changeShowError" /> <label for="chkShowError">ShowErrorMessage</label> </div> <div class="option-row"> <input class="normal-input" id="chkValidatorIgnoreBlank" type="checkbox" @change="changeValidatorIgnoreBlank" /> <label for="chkValidatorIgnoreBlank">IgnoreBlank</label> </div> <div class="option-row"> <input class="normal-input" id="txtErrorTitle" type="text" placeholder="ErrorTitle" /> </div> <div class="option-row"> <input class="normal-input" id="txtErrorMessage" type="text" placeholder="ErrorMessage" /> </div> <div class="option-row"> <select id="validatorErrorStyles"> <option value="0" selected>Stop</option> <option value="1">Warning</option> <option value="2">Information</option> </select> </div> <div class="option-row"> <label>Custom HighlightStyle:</label> <select id="highlightType" @change="changeHighlightType"> <option selected="selected" value="circle" data-bind="text: res.dataValidationDialog.circle"> Circle </option> <option value="dogear" data-bind="text: res.dataValidationDialog.dogear"> Dogear </option> <option value="icon" data-bind="text: res.dataValidationDialog.icon"> Icon </option> </select> </div> <div class="option-row"> <input class="normal-input" id="highlightColor" type="text" placeholder="HighlightColor" /> </div> <div id="dogear-position" class="option-row"> <label>Dogear Position:</label> <select id="dogearPositionOption"> <option value="Top Left" data-bind="text: res.dataValidationDialog.topLeft"> Top Left </option> <option value="Top Right" data-bind="text: res.dataValidationDialog.topRight"> Top Right </option> <option value="Bottom Right" data-bind="text: res.dataValidationDialog.bottomRight"> Bottom Right </option> <option value="Bottom Left" data-bind="text: res.dataValidationDialog.bottomLeft"> Bottom Left </option> </select> </div> <div id="icon-position" class="option-row"> <label>Icon Position:</label> <select id="iconPositionOption"> <option value="Outside Left" data-bind="text: res.dataValidationDialog.outsideLeft"> Outside Left </option> <option value="Outside Right" data-bind="text: res.dataValidationDialog.outsideRight"> Outside Right </option> </select> </div> <div id="iconFile" class="option-row"> <input id="highlighticon" type="file" accept="image/*" @change="changeHighlighticon"> </div> <div class="option-row"> <input class="normal-input" id="btnSetValidator" type="button" value="Set Validator" @click="setValidator" /> </div> <div class="option-row"> <input class="normal-input" id="btnClearValidator" type="button" value="Clear Validator" @click="clearValidator" /> </div> </div> </div> </template> <script setup> import { ref } from 'vue'; import '@mescius/spread-sheets-vue'; import GC from '@mescius/spread-sheets'; const spread = ref(null); const imageBase64 = ref(''); const initSpread = (spreadInstance) => { spread.value = spreadInstance; spread.value.suspendPaint(); spread.value.options.highlightInvalidData = true; document.getElementById("validatorTab2").style.display = 'none'; document.getElementById("validatorTab3").style.display = 'none'; document.getElementById("isIntTab").style.display = 'none'; document.getElementById("dogear-position").style.display = 'none'; document.getElementById("icon-position").style.display = 'none'; document.getElementById("iconFile").style.display = 'none'; spread.value.bind(GC.Spread.Sheets.Events.EnterCell, (e, args) => { const sheet = spread.value.getActiveSheet(); const activeRow = sheet.getActiveRowIndex(); const activeCol = sheet.getActiveColumnIndex(); const dataValidator = sheet.getDataValidator(activeRow, activeCol); const validatorTypesElement = document.getElementById("validatorTypes"); let validatorTypes; if (dataValidator) { const type = dataValidator.type(); switch (type) { case 1: case 2: validatorTypes = "NumberValidator"; break; case 3: const condition = dataValidator.condition(); if (condition && condition.formula()) { validatorTypes = "FormulaListValidator"; } else { validatorTypes = "ListValidator"; } break; case 4: validatorTypes = "DateValidator"; break; case 6: validatorTypes = "TextLengthValidator"; break; case 7: validatorTypes = "FormulaValidator"; break; } validatorTypesElement.value = validatorTypes; updateValidatorTab(validatorTypes); document.getElementById("validatorComparisonOperator").value = dataValidator.comparisonOperator(); document.getElementById("txtValidatorValue1").value = dataValidator.value1(); document.getElementById("txtValidatorValue2").value = dataValidator.value2(); document.getElementById("txtValidatorValue").value = dataValidator.value1(); document.getElementById("txtListValidatorValue").value = dataValidator.value1(); document.getElementById("chkIsInteger").setAttribute('checked', type === 1); document.getElementById("ckbShowInputMessage").setAttribute('checked', dataValidator.showInputMessage()); document.getElementById("txtInputTitle").value = dataValidator.inputTitle(); document.getElementById("txtInputMessage").value = dataValidator.inputMessage(); document.getElementById("chkShowError").setAttribute('checked', dataValidator.showErrorMessage()); document.getElementById("chkValidatorIgnoreBlank").setAttribute('checked', dataValidator.ignoreBlank()); document.getElementById("txtErrorTitle").value = dataValidator.errorTitle(); document.getElementById("txtErrorMessage").value = dataValidator.errorMessage(); document.getElementById("validatorErrorStyles").value = dataValidator.errorStyle(); } }); spread.value.resumePaint(); }; const changeHighlighticon = (e) => { const file = e.target.files[0]; const reader = new FileReader(); if (file) { reader.readAsDataURL(file); reader.onloadend = () => { imageBase64.value = reader.result; }; } }; const changeHighlightType = (e) => { switch (e.target.value) { case 'circle': document.getElementById("dogear-position").style.display = 'none'; document.getElementById("icon-position").style.display = 'none'; document.getElementById("iconFile").style.display = 'none'; break; case 'dogear': document.getElementById("dogear-position").style.display = ''; document.getElementById("icon-position").style.display = 'none'; document.getElementById("iconFile").style.display = 'none'; break; case 'icon': document.getElementById("dogear-position").style.display = 'none'; document.getElementById("icon-position").style.display = ''; document.getElementById("iconFile").style.display = ''; break; } }; const changeValidatorTypes = (e) => { const validatorTypes = e.target.value; updateValidatorTab(validatorTypes); }; const updateValidatorTab = (validatorTypes) => { switch (validatorTypes) { case "DateValidator": case "TextLengthValidator": document.getElementById("validatorTab1").style.display = 'block'; document.getElementById("isIntTab").style.display = 'none'; document.getElementById("validatorTab2").style.display = 'none'; document.getElementById("validatorTab3").style.display = 'none'; break; case "ListValidator": document.getElementById("validatorTab3").style.display = 'block'; document.getElementById("validatorTab2").style.display = 'none'; document.getElementById("validatorTab1").style.display = 'none'; break; case "FormulaListValidator": case "FormulaValidator": document.getElementById("validatorTab2").style.display = 'block'; document.getElementById("validatorTab1").style.display = 'none'; document.getElementById("validatorTab3").style.display = 'none'; break; case "NumberValidator": document.getElementById("validatorTab1").style.display = 'block'; document.getElementById("isIntTab").style.display = 'block'; document.getElementById("validatorTab2").style.display = 'none'; document.getElementById("validatorTab3").style.display = 'none'; break; } }; const changeValidatorComparisonOperator = (e) => { const operatorType = e.target.value; switch (operatorType) { case '6': case '7': document.getElementById("txtValidatorValue2").style.display = 'block'; break; default: document.getElementById("txtValidatorValue2").style.display = 'none'; break; } }; const setValidator = (e) => { const gcdv = GC.Spread.Sheets.DataValidation; let ddv = null; const v1 = document.getElementById("txtValidatorValue1").value; const v2 = document.getElementById("txtValidatorValue2").value; const validatorTypes = document.getElementById("validatorTypes").value; switch (validatorTypes) { case "DateValidator": ddv = gcdv.createDateValidator(parseInt(document.getElementById("validatorComparisonOperator").value), new Date(v1), new Date(v2)); break; case "FormulaListValidator": ddv = gcdv.createFormulaListValidator(document.getElementById("txtValidatorValue").value); break; case "FormulaValidator": ddv = gcdv.createFormulaValidator(document.getElementById("txtValidatorValue").value); break; case "ListValidator": ddv = gcdv.createListValidator(document.getElementById("txtListValidatorValue").value); ddv.inCellDropdown(document.getElementById("ckbIncellDropDown").checked); break; case "NumberValidator": if (document.getElementById("chkIsInteger").checked) { ddv = gcdv.createNumberValidator(parseInt(_getElementById("validatorComparisonOperator").value), isNaN(v1) ? v1 : parseInt(v1), isNaN(v2) ? v2 : parseInt(v2), true); } else { ddv = gcdv.createNumberValidator(parseInt(_getElementById("validatorComparisonOperator").value), isNaN(v1) ? v1 : parseFloat(v1), isNaN(v2) ? v2 : parseFloat(v2), false); } break; case "TextLengthValidator": ddv = gcdv.createTextLengthValidator(parseInt(_getElementById("validatorComparisonOperator").value), isNaN(v1) ? v1 : parseInt(v1), isNaN(v2) ? v2 : parseInt(v2)); break; } if (ddv != null) { ddv.errorMessage(_getElementById("txtErrorMessage").value); ddv.errorStyle(parseInt(_getElementById("validatorErrorStyles").value)); ddv.errorTitle(_getElementById("txtErrorTitle").value); ddv.showErrorMessage(_getElementById("chkShowError").checked); ddv.ignoreBlank(_getElementById("chkValidatorIgnoreBlank").checked); ddv.showInputMessage(_getElementById("ckbShowInputMessage").checked); ddv.inputTitle(_getElementById("txtInputTitle").value); ddv.inputMessage(_getElementById("txtInputMessage").value); let highLightStyle = _getElementById("highlightType").value; let dogearPosition = _getElementById("dogearPositionOption").value; let iconPosition = _getElementById("iconPositionOption").value; let highlightStyleColor = _getElementById("highlightColor").value; if (highLightStyle === "circle") { ddv.highlightStyle({ type: GC.Spread.Sheets.DataValidation.HighlightType.circle, color: highlightStyleColor }); } else if (highLightStyle === "dogear" && dogearPosition === "Top Left") { ddv.highlightStyle({ type: GC.Spread.Sheets.DataValidation.HighlightType.dogEar, color: highlightStyleColor, position: GC.Spread.Sheets.DataValidation.HighlightPosition.topLeft }); } else if (highLightStyle === "dogear" && dogearPosition === "Top Right") { ddv.highlightStyle({ type: GC.Spread.Sheets.DataValidation.HighlightType.dogEar, color: highlightStyleColor, position: GC.Spread.Sheets.DataValidation.HighlightPosition.topRight }); } else if (highLightStyle === "dogear" && dogearPosition === "Bottom Left") { ddv.highlightStyle({ type: GC.Spread.Sheets.DataValidation.HighlightType.dogEar, color: highlightStyleColor, position: GC.Spread.Sheets.DataValidation.HighlightPosition.bottomLeft }); } else if (highLightStyle === "dogear" && dogearPosition === "Bottom Right") { ddv.highlightStyle({ type: GC.Spread.Sheets.DataValidation.HighlightType.dogEar, color: highlightStyleColor, position: GC.Spread.Sheets.DataValidation.HighlightPosition.bottomRight }); } else if (highLightStyle === "icon" && iconPosition === "Outside Left") { ddv.highlightStyle({ type: GC.Spread.Sheets.DataValidation.HighlightType.icon, color: highlightStyleColor, position: GC.Spread.Sheets.DataValidation.HighlightPosition.outsideLeft, image: self.imageBase64 }); } else if (highLightStyle === "icon" && iconPosition === "Outside Right") { ddv.highlightStyle({ type: GC.Spread.Sheets.DataValidation.HighlightType.icon, color: highlightStyleColor, position: GC.Spread.Sheets.DataValidation.HighlightPosition.outsideRight, image: self.imageBase64 }); } let ss = spread.value; let sheet = ss.getActiveSheet(); sheet.suspendPaint(); let sels = sheet.getSelections(); for (let i = 0; i < sels.length; i++) { let sel = getActualRange(sheet, sels[i]); sheet.setDataValidator(sel.row, sel.col, sel.rowCount, sel.colCount, ddv); } sheet.resumePaint(); } }; const clearValidator = (e) => { const sheet = spread.value.getActiveSheet(); let sels = sheet.getSelections(); for (let i = 0; i < sels.length; i++) { let sel = getActualRange(sheet, sels[i]); sheet.setDataValidator(sel.row, sel.col, sel.rowCount, sel.colCount, null); } }; const changeShowError = (e) => { const ss = spread.value; let checked = e.target.checked; if (checked) { ss.bind(GC.Spread.Sheets.Events.ValidationError, function (event, data) { let dv = data.validator; if (dv) { alert(dv.errorMessage()); } }); } else { ss.unbind(GC.Spread.Sheets.Events.ValidationError); } }; const changeValidatorIgnoreBlank = (e) => { const sheet = spread.value.getActiveSheet(); let sels = sheet.getSelections(); for (let i = 0; i < sels.length; i++) { let sel = getActualRange(sheet, sels[i]); for (let r = 0; r < sel.rowCount; r++) { for (let c = 0; c < sel.colCount; c++) { let dv = sheet.getDataValidator(sel.row + r, sel.col + c); if (dv) { dv.ignoreBlank(e.target.checked); } } } } }; const getActualRange = (sheet, range) => { let row = range.row, rowCount = range.rowCount; if (row === -1) { row = 0; rowCount = sheet.getRowCount(); } let col = range.col, colCount = range.colCount; if (col === -1) { col = 0; colCount = sheet.getColumnCount(); } return new GC.Spread.Sheets.Range(row, col, rowCount, colCount); }; function _getElementById(id) { return document.getElementById(id); } </script> <style scoped> #app { height: 100%; } .sample-tutorial { position: relative; height: 100%; overflow: hidden; } .sample-spreadsheets { width: calc(100% - 280px); height: 100%; overflow: hidden; float: left; } .options-container { float: right; width: 280px; padding: 12px; height: 100%; box-sizing: border-box; background: #fbfbfb; overflow: auto; } .option-row { font-size: 14px; padding: 5px; margin-top: 5px; } .normal-input { display: block; padding: 4px 6px; box-sizing: border-box; width: 100%; } select { display: block; padding: 4px 6px; box-sizing: border-box; width: 100%; } input[type=checkbox] { display: inline-block; width: auto; } body { position: absolute; top: 0; bottom: 0; left: 0; right: 0; } </style>
<!DOCTYPE html> <html style="height:100%;font-size:14px;"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <title>SpreadJS VUE</title> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" type="text/css" href="$DEMOROOT$/en/vue3/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css"> <script src="$DEMOROOT$/en/vue3/node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script src="compiler.js" type="module"></script> <script> var System = SystemJS; System.import("./src/app.js"); System.import('$DEMOROOT$/en/lib/vue3/license.js'); </script> </head> <body> <div id="app"></div> </body> </html>
(function (global) { SystemJS.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true }, paths: { // paths serve as alias 'npm:': 'node_modules/' }, packageConfigPaths: [ './node_modules/*/package.json', "./node_modules/@mescius/*/package.json", "./node_modules/@babel/*/package.json", "./node_modules/@vue/*/package.json" ], map: { 'vue': "npm:vue/dist/vue.esm-browser.js", 'tiny-emitter': 'npm:tiny-emitter/index.js', 'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js', "systemjs-babel-build": "npm:systemjs-plugin-babel/systemjs-babel-browser.js", '@mescius/spread-sheets': 'npm:@mescius/spread-sheets/index.js', '@mescius/spread-sheets-vue': 'npm:@mescius/spread-sheets-vue/index.js', }, meta: { '*.css': { loader: 'systemjs-plugin-css' }, '*.vue': { loader: "../plugin-vue/index.js" } } }); })(this);