
# Custom row validation

You can verify values on a cell-by-cell basis by using the onValidateRow event that the grid generates when row editing is complete.

#### onValidateRow event

[onValdateRow](/refs/Class/GridBase#onvalidaterow) The field name and edited value of the cell are passed as parameters of the event.
After verifying the value and passing the error level and message as the return value of the event, the grid cannot complete editing (commit) and displays a message to the user.

Try changing the values of the ‘Age’ and ‘Contribution’ columns in the grid below.

```js
const fields = [
  { fieldName: "KorName", dataType: "text" },
  { fieldName: "Gender", dataType: "text" },
  { fieldName: "Age", dataType: "number" },
  { fieldName: "Phone", dataType: "text" },
  { fieldName: "ProductId", dataType: "text" },
  { fieldName: "KorCountry", dataType: "text" },
  { fieldName: "OrderDate", dataType: "datetime", datetimeFormat: "yyyy-MM-dd", amText: "AM", pmText: "PM" },
  { fieldName: "CardNumber", dataType: "text" },
  { fieldName: "Monetary", dataType: "text" },
  { fieldName: "StartDate", dataType: "datetime", datetimeFormat: "yyyy-MM-dd", amText: "AM", pmText: "PM" },
  { fieldName: "EndDate", dataType: "datetime", datetimeFormat: "yyyy-MM-dd", amText: "AM", pmText: "PM" },
  { fieldName: "ToMonth", dataType: "number" },
  { fieldName: "Month", dataType: "number" },
  { fieldName: "Year", dataType: "number" },
  { fieldName: "InterestRate", dataType: "number" },
  { fieldName: "SaveCost", dataType: "number" },
  { fieldName: "SaveMaturity", dataType: "number" },
  { fieldName: "CurrentSave", dataType: "number" }
];

const columns = [
  { name: "KorName", fieldName: "KorName", width: "60", header: { text: "Name" } },
  { name: "Gender", fieldName: "Gender", width: "40", header: { text: "Gender" } },
  { name: "Age", fieldName: "Age", width: "40", header: { text: "Age", styleName: "orange-column" }, styleName: "right-column", numberFormat: "#,##0" },
  { name: "Phone", fieldName: "Phone", width: "100", header: { text: "Phone" } },
  { name: "SaveCost", fieldName: "SaveCost", width: "80", numberFormat: "#,##0", header: { text: "Payment Amount", styleName: "orange-column" }, styleName: "right-column" },
  { name: "ProductId", fieldName: "ProductId", width: "120", header: { text: "Product ID" } },
  { name: "KorCountry", fieldName: "KorCountry", width: "100", header: { text: "Investment Country" } },
  { name: "OrderDate", fieldName: "OrderDate", width: "100", header: { text: "Order Date" } },
  { name: "CardNumber", fieldName: "CardNumber", width: "140", header: { text: "Card Number" } },
  { name: "Monetary", fieldName: "Monetary", width: "40", header: { text: "Currency" } },
  { name: "StartDate", fieldName: "StartDate", width: "100", header: { text: "First Payment Date" } },
  { name: "EndDate", fieldName: "EndDate", width: "100", header: { text: "End Date" } },
  { name: "ToMonth", fieldName: "ToMonth", width: "50", header: { text: "Payment Count" }, styleName: "right-column" },
  { name: "Month", fieldName: "Month", width: "50", header: { text: "Remaining Count" }, styleName: "right-column" },
  { name: "InterestRate", fieldName: "InterestRate", width: "50", numberFormat: "0.00", header: { text: "Interest Rate" }, styleName: "right-column" },
  { name: "SaveMaturity", fieldName: "SaveMaturity", width: "80", numberFormat: "#,##0", header: { text: "Maturity Amount" }, styleName: "right-column" },
  { name: "CurrentSave", fieldName: "CurrentSave", width: "80", numberFormat: "#,##0", header: { text: "Current Balance" }, styleName: "right-column" }
];

const { gridView, dataProvider } = RealGrid.createGrid("realgrid", {
  columns,
  header: {
    height: 40
  },
  display: {
    rowHeight: 36,
    emptyMessage: "No data to display."
  },
  edit: {
    insertable: true,
    appendable: true
  },
  footer: {
    height: 40
  },
  stateBar: {
    width: 16
  },
  onValidateRow: (grid, itemIndex, dataRow, inserting, values) => {
    const error = {};
    
    if (values.SaveCost < 50000) {
      error.level = "error";
      error.message = "Payment amount must be at least 50,000.";
    } else if (values.SaveCost > 100000) {
      error.level = "warning";
      error.message = "Payment amount must be 100,000 or less.";
    }

    if (values.Age < 1) {
      error.level = "error";
      error.message = "Age must be at least 1.";
    } else if (values.Age > 60) {
      error.level = "warning";
      error.message = "Age must be 60 or less.";
    }
    
    return error;
  },
  onInitialized: (grid) => {
    fetch('/data/en/simple_data.json')
      .then(response => response.json())
      .then(data => {
        grid.getDataSource().setRows(data);
      });
  }
}, {
  fields
});

window.gridView = gridView;
window.dataProvider = dataProvider;
```

```js
gridView.onValidateRow = function(grid, itemIndex, dataRow, inserting, values) {
     var error = {};
  
     if (values.SaveCost < 50000) {
         error.level = "error";
         error.message = "Payment must be over 50,000.";
     } else if (values.SaveCost > 100000) {
         error.level = "warning";
         error.message = "Payment must be less than 100,000.";
     }

     if (values. Age < 1) {
         error.level = "error";
         error.message = "Age must be greater than 1.";
     } else if (values.Age > 60) {
         error.level = "warning";
         error.message = "You must be under 60.";
     }
  
     return error;
}
```

For levels, messages, error states, etc., see [Cell Validation](/refs/realgrid#validationlevel).