I would like to display the property of age and if a person is vaccinated under each name after each button's click, but these properties appear under the page. How can I do it?
Furthermore, which concepts of the dom should I explore in order to build logics where there is a correlation and interaction between dom and objects? (e.g. select an item via the dom and view its details).
<body>
<div class="container">
<div class="list-container"></div>
</div>
<script src="script.js"></script>
</body>
const persons = [
{ name: "carl", age: 20, vaccinated: true, id: 1 },
{ name: "alex", age: 45, vaccinated: false, id: 2 },
{ name: "alice", age: 12, vaccinated: true, id: 3 },
{ name: "erick", age: 2, vaccinated: true, id: 4 },
{ name: "fred", age: 23, vaccinated: false, id: 5 },
{ name: "wandy", age: 13, vaccinated: true, id: 6 },
];
const generalContainer = document.querySelector(".container");
const listContainer = document.querySelector(".list-container");
function renderItems(obj) {
let dataId;
let item;
let sub;
obj.forEach((element) => {
item = document.createElement("div");
let itemAttr = document.createAttribute("data-id");
itemAttr.value = element.id;
item.setAttributeNode(itemAttr);
dataId = item.dataset.id;
item.innerHTML = `<p>NAME: ${element.name}</p>
<button class="btn">${element.name}</button>
<div class='sub'></div>
`;
sub = document.querySelector(".sub");
listContainer.appendChild(item);
});
let btn = document.querySelectorAll(".btn");
let selected;
let subItem = document.createElement("div");
btn.forEach((el) => {
el.addEventListener("click", (e) => {
e.preventDefault();
let textValue = el.textContent;
selected = obj.find((ele) => {
return ele.name === textValue;
});
//subItem = document.createElement("div");
subItem.innerHTML = `
<div><p>AGE: ${selected.age}</p>
<p>VACCINE STATUS: ${
selected.vaccinated ? "Vaccinated" : "Not vaccinated"
}</div>`;
console.log(sub);
sub.appendChild(subItem);
item.append(sub);
});
});
}
renderItems(persons);
Try a more simplified version. Among other things, it uses event delegation for event listeners:
const persons = [{
name: "carl",
age: 20,
vaccinated: true,
id: 1
},
{
name: "alex",
age: 45,
vaccinated: false,
id: 2
},
{
name: "alice",
age: 12,
vaccinated: true,
id: 3
},
{
name: "erick",
age: 2,
vaccinated: true,
id: 4
},
{
name: "fred",
age: 23,
vaccinated: false,
id: 5
},
{
name: "wandy",
age: 13,
vaccinated: true,
id: 6
}
];
let listContainer = document.querySelector(".list-container");
function renderItems(obj) {
obj.forEach((element) => {
new_elem = `
<div data-id="${element.id}">
<p>NAME: ${element.name}</p>
<button but-id="${element.id}">${element.name}</button>
<div class='sub'></div>
</div>
`;
listContainer.insertAdjacentHTML("afterbegin", new_elem);
});
listContainer.addEventListener("click", (e) => {
person = e.target.getAttribute("but-id");
p_name = e.target.innerText;
dest = document.querySelector(`div[data-id="${person}"] div.sub`);
let selected = persons.find(({name}) => name === p_name);
subItem = `
<div>
<p>AGE: ${selected.age}</p>
<p>VACCINE STATUS: ${
selected.vaccinated ? "Vaccinated" : "Not vaccinated"
}</p>
</div>
`;
dest.innerHTML = subItem;
});
}
renderItems(persons);
<body>
<div class="container">
<div class="list-container"></div>
</div>
</body>
Related
I have two arrays of objects.
I'm trying to create a function that can subtract values from one array of objects from another array of object using the same id on name in REACT
export default function App() {
const stockArray = [
{ id: 1, name: "Iphone", amount: 23 },
{ id: 2, name: "Samsung", amount: 28 },
{ id: 3, name: "Huawei", amount: 14 },
{ id: 4, name: "Motorola", amount:20 }
];
const basketArray = [
{ id: 1, name: "Iphone", amount: 3 },
{ id: 3, name: "Huawei", amount: 4 }
];
const [stock, setStock] = React.useState(stockArray);
const [basket, setBasket] = React.useState(basketArray);
const handleUpdateStock = () => {
// How to subtract amount values in basketArray from amount values in stockArray
in objects with the same id or name.
// the result should be :
// const stockArray = [
// { id: 1, name: "Iphone", amount: 20 },
// { id: 2, name: "Samsung", amount: 28 },
// { id: 3, name: "Huawei", amount: 10 },
// { id: 4, name: "Motorola", amount:20 }
// ];
}
return (
<div>
<h3>Stock:</h3>
{stock.map(product=> (
<h5>{product.name} - {product.amount} </h5>
))}
<br/>
<h3>Basket:</h3>
{basket.map(product=> (
<h5>{product.name} - {product.amount} </h5>
))}
<button onClick={handleUpdateStock}>Save and update stock </button>
</div>
);
}`
You can loop your stock array, and compare each product with in it with each product from the basket.
If they have the same id you should subtract the amount from the product.amount from the the product inside the basket.
In the end we should setStock with the new array.
function App() {
const stockArray = [
{ id: 1, name: "Iphone", amount: 23 },
{ id: 2, name: "Samsung", amount: 28 },
{ id: 3, name: "Huawei", amount: 14 },
{ id: 4, name: "Motorola", amount:20 }
];
const basketArray = [
{ id: 1, name: "Iphone", amount: 3 },
{ id: 3, name: "Huawei", amount: 4 }
];
const [stock, setStock] = React.useState(stockArray);
const [basket, setBasket] = React.useState(basketArray);
const handleUpdateStock = () => {
const newStock = stock.map(product => {
const productInBasket = basket.find(el => el.id === product.id);
if (!productInBasket) return product;
return {
...product,
amount: product.amount - productInBasket.amount,
}
})
setStock(newStock);
}
return (
<div>
<h3>Stock:</h3>
{stock.map(product=> (
<h5 key={product.id}>{product.name} - {product.amount} </h5>
))}
<br/>
<h3>Basket:</h3>
{basket.map(product=> (
<h5 key={product.id}>{product.name} - {product.amount} </h5>
))}
<button onClick={handleUpdateStock}>Save and update stock </button>
</div>
);
}
ReactDOM.createRoot(
document.getElementById("root")
).render(
<App />
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>
function substract (stockArray,basketArray){
return stockArray.map(stock=>{
const basket = basketArray.find(basket=>stock.id===basket.id);
if(basket){
return {
...stock,
amount:stock.amount-basket.amount,
}
} else {
return stock;
}
})
}
this function iterates all indexes in stockArray, will find same object with the same id in basketArray and if basket is an object, it changes value of amount in stock
I have such data:
const dataList = [
{
id: 1,
title: 'obj1',
published: true,
},
{
id: 2,
title: 'obj2',
published: true,
},
{
id: 3,
title: 'obj3',
published: false,
},
{
id: 4,
title: 'obj4',
published: true,
},
{
id: 5,
title: 'obj5',
published: false,
},
];
I also have two checkboxes with this structure:
enter image description here
filterList = [
{
id: 1,
title: 'published',
label: 'published',
checked: false,
},
{
id: 2,
title: 'unpublished',
label: 'unpublished',
checked: false,
},
],
how do I filter this kind of data using these checkboxes? I have implemented switching their state, but I don't understand how to filter the data
I'm trying to implement this in a function
const applyFilter = () => {
let updData = dataList;
const filterChecked = filterList.filter((item: any) => item.checked);
if (filterChecked.length) {
// how to dynamically substitute data from checkboxes?
updData = updData.filter((item) => item.published === //true//);
}
};
Here's an attempt at a minimal example that hopefully gives a clear overview of how it's possible to filter elements. You can use your state to control how the elements are filtered out of the list, and then render those that remain:
const App = () => {
const [showingBs, setShowingBs] = React.useState(true);
return (<div>
<input
type = "checkbox"
checked = {showingBs}
onChange = {
() => setShowingBs(!showingBs)
}
/>
{
['a', 'b', 'a', 'b', 'b', 'a', 'b']
.filter(x => showingBs || x !== 'b')
.map(x => <p>{x}</p>)
}
</div>)
}
ReactDOM.render( < App / > , document.getElementById("mount"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="mount"></div>
I am trying to filter array as per gender (using checkbox ) but its not working. When i clicked on male checkbox it works but it wont work by clicking on female checkbox button. Here is my App.tsx. Need help to solve this?
import React, { useState } from "react";
const App = () => {
const [students, setStudents] = useState([
{ id: 1, title: "Akita from place1", race: "Akita", gender: 'female' },
{ id: 2, title: "Akita from place2", race: "Akita", gender: 'female' },
{ id: 3, title: "Akita from place3", race: "Akita", gender: 'female' },
{ id: 4, title: "Chihuahua from place4", race: "Chihuahua" , gender: 'male' },
{ id: 5, title: "Cockapoo from place5", race: "Cockapoo" , gender: 'male'},
{ id: 6, title: "Dachshund from place6", race: "Dachshund", gender: 'male' },
{ id: 7, title: "Dutch Shepherd from place7", race: "Dutch Shepherd" , gender: 'female' },
{ id: 8, title: "Bulldog from place8", race: "Bulldog", gender: 'male' },
{ id: 9, title: "Goldador from place9", race: "Goldador", gender: 'female' },
]);
const filterData = (e: any) => {
console.log(e.target.value);
if (e.target.value === "male") {
const filteredData = students.filter((student) => {
return student.gender === "male";
});
setStudents(filteredData);
}
if (e.target.value === "female") {
const filteredData = students.filter((student) => {
return student.gender === "female";
});
setStudents(filteredData);
}
};
return (
<div>
<h3>app</h3>
Male: <input type="checkbox" name='male' value='male' onChange={filterData} />
Female: <input type="checkbox" name='female' value='female' onChange={filterData} />
{students
.map((student: any) => {
return (
<div key={student.id}>
{student.id}-{student.title}-{student.race}-{student.gender}
</div>
);
})}
</div>
);
};
export default App;
const {
useState
} = React;
const App = () => {
const [students, setStudents] = React.useState([{
id: 1,
title: "Akita from place1",
race: "Akita",
gender: 'female'
},
{
id: 2,
title: "Akita from place2",
race: "Akita",
gender: 'female'
},
{
id: 3,
title: "Akita from place3",
race: "Akita",
gender: 'female'
},
{
id: 4,
title: "Chihuahua from place4",
race: "Chihuahua",
gender: 'male'
},
{
id: 5,
title: "Cockapoo from place5",
race: "Cockapoo",
gender: 'male'
},
{
id: 6,
title: "Dachshund from place6",
race: "Dachshund",
gender: 'male'
},
{
id: 7,
title: "Dutch Shepherd from place7",
race: "Dutch Shepherd",
gender: 'female'
},
{
id: 8,
title: "Bulldog from place8",
race: "Bulldog",
gender: 'male'
},
{
id: 9,
title: "Goldador from place9",
race: "Goldador",
gender: 'female'
},
]);
const [filtered, setFiltered] = useState([])
const filterData = (e) => {
const {value, checked} = e.target;
//check if value not in state and checked is true then add value to state
if(!filtered.includes(value) && checked){
setFiltered([...filtered, value])
}else{
setFiltered(filtered.filter(f=>f!==value))
}
};
const filteredStudent = filtered.length > 0 ? students.filter(s => filtered.includes(s.gender)) : students;
return (
<div>
<h3>app</h3>
Male: <input type="checkbox" name='male' value='male' onChange={filterData}/>
Female: <input type="checkbox" name='female' value='female' onChange={filterData}/>
{filteredStudent
.map((student) => {
return (
<div key={student.id}>
{student.id}-{student.title}-{student.race}-{student.gender}
</div>
);
})}
</div>
);
};
// Render it
ReactDOM.createRoot(
document.getElementById("root")
).render( <
App / >
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
It does not work because you are filtering all the female out and updating the state, this means that after clicking one button once, the filtered values does not exist in state anymore. To fix this, you could track the filter type in state and derive the filtered students during render.
Note that you could use radio buttons so only one gender can be selected at a time.
import React, {useState} from "react";
const App = () => {
const [students, setStudents] = useState([
{id: 1, title: "Akita from place1", race: "Akita", gender: 'female'},
{id: 2, title: "Akita from place2", race: "Akita", gender: 'female'},
{id: 3, title: "Akita from place3", race: "Akita", gender: 'female'},
{id: 4, title: "Chihuahua from place4", race: "Chihuahua", gender: 'male'},
{id: 5, title: "Cockapoo from place5", race: "Cockapoo", gender: 'male'},
{id: 6, title: "Dachshund from place6", race: "Dachshund", gender: 'male'},
{id: 7, title: "Dutch Shepherd from place7", race: "Dutch Shepherd", gender: 'female'},
{id: 8, title: "Bulldog from place8", race: "Bulldog", gender: 'male'},
{id: 9, title: "Goldador from place9", race: "Goldador", gender: 'female'},
]);
const [filter, setFilter] = useState<null | string>(null)
const filterData = (e) => {
setFilter(e.target.checked ? e.target.value : null)
};
const filteredStudent = filter ? students.filter(s => s.gender === filter) : students;
return (
<div>
<h3>app</h3>
Male: <input type="checkbox" name='male' value='male' onChange={filterData}/>
Female: <input type="checkbox" name='female' value='female' onChange={filterData}/>
{filteredStudent
.map((student) => {
return (
<div key={student.id}>
{student.id}-{student.title}-{student.race}-{student.gender}
</div>
);
})}
</div>
);
};
export default App;
This is shop page.jsx file here i want to show the list of filtered items at the top of the page. Here im using data list for getting all the details. Here i want to show length of filtered products at showing 9 0f 9 products.
import React, { useEffect, useState } from 'react';
import EmptyView from '../components/common/EmptyView';
import FilterPanel from '../components/Home/FilterPanel';
import List from './Home/List';
// import SearchBar from '../../components/Home/SearchBar';
import { dataList } from '../constants';
// import './styles.css';
import '../App.css';
import ButtonAppBar from "./Header";
const Shop = () => {
// const [selectedCategory, setSelectedCategory] = useState(null);
// const [selectedRating, setSelectedRating] = useState(null);
const [selectedPrice, setSelectedPrice] = useState([0, 150]);
const [cuisines, setCuisines] = useState([
{ id: 1, checked: false, label: 'Furniture' },
{ id: 2, checked: false, label: 'Decoration' },
{ id: 3, checked: false, label: 'Bedding' },
{ id: 4, checked: false, label: 'Lighting' },
{ id: 5, checked: false, label: 'Bath&Shower' },
{ id: 6, checked: false, label: 'Curtains' },
{ id: 7, checked: false, label: 'Toys' },
]);
const [brand, setBrand] = useState([
{ id: 1, checked: false, label: 'Poliform' },
{ id: 2, checked: false, label: 'Rochie Bobois' },
{ id: 3, checked: false, label: 'Edra' },
{ id: 4, checked: false, label: 'Kartell' },
]);
const [availability, setAvailability] = useState([
{ id: 1, checked: false, label: 'Onstock' },
{ id: 2, checked: false, label: 'Outofstock' },
]);
const [list, setList] = useState(dataList);
const [resultsFound, setResultsFound] = useState(true);
// const [searchInput, setSearchInput] = useState('');
// const handleSelectCategory = (event, value) =>
// !value ? null : setSelectedCategory(value);
// const handleSelectRating = (event, value) =>
// !value ? null : setSelectedRating(value);
const handleChangeChecked = (id) => {
const cusinesStateList = cuisines;
const changeCheckedCuisines = cusinesStateList.map((item) =>
item.id === id ? { ...item, checked: !item.checked } : item
);
setCuisines(changeCheckedCuisines);
};
const handleChangeCheckeds = (id) => {
const brandStateList = brand;
const changeCheckedsBrand = brandStateList.map((item) =>
item.id === id ? { ...item, checked: !item.checked } : item
);
setBrand(changeCheckedsBrand);
};
const handleChangeCheckedss = (id) => {
const availabilityStateList = availability;
const changeCheckedssAvailability = availabilityStateList.map((item) =>
item.id === id ? { ...item, checked: !item.checked } : item
);
setAvailability(changeCheckedssAvailability);
};
const handleChangePrice = (event, value) => {
setSelectedPrice(value);
};
const applyFilters = () => {
let updatedList = dataList;
// // Rating Filter
// if (selectedRating) {
// updatedList = updatedList.filter(
// (item) => parseInt(item.rating) === parseInt(selectedRating)
// );
// }
// // Category Filter
// if (selectedCategory) {
// updatedList = updatedList.filter(
// (item) => item.category === selectedCategory
// );
// }
// Cuisine Filter
const cuisinesChecked = cuisines
.filter((item) => item.checked)
.map((item) => item.label.toLowerCase());
if (cuisinesChecked.length) {
updatedList = updatedList.filter((item) =>
cuisinesChecked.includes(item.cuisine)
);
}
// brand filter
const brandChecked = brand
.filter((item) => item.checked)
.map((item) => item.label.toLowerCase());
if (brandChecked.length) {
updatedList = updatedList.filter((item) =>
brandChecked.includes(item.brand)
);
}
// availabilty filter
const availabilityChecked = availability
.filter((item) => item.checked)
.map((item) => item.label.toLowerCase());
if (availabilityChecked.length) {
updatedList = updatedList.filter((item) =>
availabilityChecked.includes(item.availability)
);
}
// // Search Filter
// if (searchInput) {
// updatedList = updatedList.filter(
// (item) =>
// item.title.toLowerCase().search(searchInput.toLowerCase().trim()) !==
// -1
// );
// }
// // Price Filter
const minPrice = selectedPrice[0];
const maxPrice = selectedPrice[1];
updatedList = updatedList.filter(
(item) => item.price >= minPrice && item.price <= maxPrice
);
setList(updatedList);
!updatedList.length ? setResultsFound(false) : setResultsFound(true);
};
useEffect(() => {
applyFilters();
}, [cuisines, brand, availability, selectedPrice]);
return (
<div>
<ButtonAppBar />
<div className='home'>
{/* Search Bar */}
{/* <SearchBar
value={searchInput}
changeInput={(e) => setSearchInput(e.target.value)}
/> */}
<br /><br /><br /> <div className='home_panelList-wrap'>
{/* Filter Panel */}
<div className='home_panel-wrap'>
<FilterPanel
// selectedCategory={selectedCategory}
// selectCategory={handleSelectCategory}
// selectedRating={selectedRating}
selectedPrice={selectedPrice}
// selectRating={handleSelectRating}
cuisines={cuisines}
changeChecked={handleChangeChecked}
brand={brand}
changeCheckeds={handleChangeCheckeds}
availability={availability}
changeCheckedss={handleChangeCheckedss}
changePrice={handleChangePrice}
/>
</div>
{/* List & Empty View */}
<div className='home_list-wrap'>
<h6>Showing
<span style={{ color: "#bd744c" }}><b>{dataList.length}</b></span> of
<span style={{ color: "#bd744c" }}><b>9</b></span>
Products</h6>
{resultsFound ? <List list={list} /> : <EmptyView />}
</div>
</div>
</div>
</div>
);
};
export default Shop;
This is constant.js file from here we are getting all our details in shop.jsx file.
export const dataList = [
{
id: 1,
title: 'AwesomeLamp',
cuisine: 'lighting',
price: 40,
image: '/images/AwesomeLamp.png',
brand: 'poliform',
availability: 'onstock',
name: 'AwesomeLamp',
tagName: 'AwesomeLamp'
},
{
id: 2,
title: 'CozySofa',
cuisine: 'furniture',
price: 150,
image: '/images/CozySofa.png',
brand: 'edra',
availability: 'outofstock',
name: 'CozySofa',
tagName: 'CozySofa'
},
{
id: 3,
title: 'AwesomeCandle',
cuisine: 'lighting',
price: 15,
image: '/images/AwesomeCandle.png',
brand: 'kartell',
availability: 'onstock',
name: 'AwesomeCandle',
tagName: 'AwesomeCandle',
},
{
id: 4,
title: 'FancyChair',
cuisine: 'furniture',
price: 70,
image: '/images/FancyChair.png',
brand: 'poliform',
availability: 'outofstock',
name: 'FancyChair',
tagName: 'FancyChair'
},
{
id: 5,
title: 'ChineseTeapot',
cuisine: 'decoration',
price: 50,
image: '/images/ChineseTeapot.png',
brand: 'rochie bobois',
availability: 'onstock',
name: 'ChineseTeapot',
tagName: 'ChineseTeapot'
},
{
id: 6,
title: 'SoftPillow',
cuisine: 'bedding',
price: 30,
image: '/images/SoftPillow.png',
brand: 'edra',
availability: 'onstock',
name: 'SoftPillow',
tagName: 'SoftPillow'
},
{
id: 7,
title: 'WoodenCasket',
cuisine: 'decoration',
price: 20,
image: '/images/WoodenCasket.png',
brand: 'kartell',
availability: 'onstock',
name: 'WoodenCasket',
tagName: 'WoodenCasket'
},
{
id: 8,
title: 'AwesomeArmChair',
cuisine: 'furniture',
price: 90,
image: '/images/AwesomeArmChair.png',
brand: 'poliform',
availability: 'onstock',
name: 'AwesomeArmchair',
tagName: 'AwesomeArmchair'
},
{
id: 9,
title: 'CoolFlower',
cuisine: 'decoration',
price: 20,
image: '/images/CoolFlower.png',
brand: 'none',
availability: 'onstock',
name: 'CoolFlower',
tagName: 'CoolFlower'
},
];
I have declared cell validation function but in cells property but it is not getting invoked and no error is also thrown
I have declared the function definition as member function and trying to call it from componentDidMount function
Also some suggestions regarding using handsontable with react would be great!
Below is my code
import React from 'react';
import Handsontable from 'handsontable/dist/handsontable';
let hot = {};
let columns = [];
let data = '';
class SpreadSheet extends React.Component {
constructor(props){
super(props);
this.state = {
data : [
{year: "2016", name: 'John', age: 23, contact: 8000142880},
{year: "2015", name: 'Doe', age: 22, contact: 9494858568},
{year: "2013", name: 'Jack', age: 21, contact: 7878989825},
{year: "2012", name: 'Joe', age: 20, contact: 9898454526},
]
}
columns = [
{ data: 'year', type: 'text' },
{ data: 'name', type: 'text' },
{ data: 'age', type: 'numeric' },
{ data: 'contact', type: 'numeric' }
]
}
getData = () => {
var datafromtable = document.getElementById('foo');
//console.log(datafromtable);
data = hot.getData();
console.log(data);
}
negativeValueRenderer = () => (instance, td, row, col, prop, value, cellProperties) => {
console.log('arguments');
//Handsontable.renderers.TextRenderer.apply(this, arguments);
//return;
}
componentDidMount() {
var container = document.getElementById('foo');
hot = new Handsontable(container, {
data: this.state.data,
minSpareCols: 1 ,
minSpareRows: 1,
minCols: 5,
minRows: 5,
rowHeaders: true,
colHeaders: ['Year','Name','Age','Contact'],
columns: columns,
cells: function (row, col, prop) {
console.log(this);
this.renderer = this.negativeValueRenderer;//not getting triggered
},
contextMenu: true
});
}
render() {
return (
<div>
<div id="foo"></div>
<button onClick = {this.getData}>Get Data</button>
{data}
</div>
);
}
}
export default SpreadSheet;
Are you trying to apply the negativeValueRenderer to each cell, or just the Age column?
Give this a shot:
constructor(props) {
super(props);
this.negativeValueRenderer = this.negativeValueRenderer.bind(this);
}
...
negativeValueRenderer(instance, td, row, col, prop, value, cellProperties) {
renderers.NumericRenderer.apply(this, arguments);
if (parseInt(value, 10) < 0) {
td.style.color = 'red';
}
}
...
hot = new Handsontable(container, {
data: this.state.data,
minSpareCols: 1 ,
minSpareRows: 1,
minCols: 5,
minRows: 5,
rowHeaders: true,
colHeaders: ['Year','Name','Age','Contact'],
columns: columns,
columns={[
{
data: 'year',
},
{
data: 'name',
},
{
data: 'age',
validator: this.negativeValueValidator,
},
{
data: 'contact',
},
contextMenu: true
});