Ag-grid fill row after select in infinite scroll model reactjs - reactjs

I use ag-grid as infinite scroll model. When i select some row, i check it in BE and after that i want to fill this row as green (in screenshot blue - it's selected row, i want to fill green this row after some action, for example, after click button for checking this row).
I try to set RowClassRules for this way, but it's not worked. But this work before the table waas rendered. After the table was rendered i select row and it's not fill green.
I know about updateData function, but it's not supported in infinite scroll model. Can i do this with another way?
render(){
let cells = this.state.rowIndexWithBadValue;
let cellsImported = this.state.rowIndexAlreadyImported;
return(
...
<AgGridReact
enableColResize={true}
columnDefs={this.state.columnDefs}
rowModelType="infinite"
rowSelection="multiple"
rowDeselection={true}
maxBlocksInCache={2}
suppressRowClickSelection={true}
getRowNodeId={this.state.getRowNodeId}
datasource={this.getDataSource(1000)}
isRowSelectable={this.state.isRowSelectable}
rowClassRules={{
"red-row": function(params) {
return cells.find(e => e === params.node.rowIndex) !== undefined ? true : false;
},
"green-row": function(params) {
return cellsImported.find(e => e === params.node.id) !== undefined ? true : false;
},
}}
onGridReady={this.onGridReady}
onSelectionChanged={this.onSelectionChanged}
/>
...
)
}
State:
this.state = {
columnDefs: this.props.columnDefs,
data: this.props.data,
selectedData: null,
getRowNodeId: function(item) {
let columnIndex = null;
Object.keys(item).map((elem, index) => {
if (elem === item_id) { columnIndex = index; }
});
return Object.values(item)[columnIndex];
},
rowIndexWithBadValue: this.props.rowIndexWithBadValue,
isRowSelectable: function(rowNode) {
return row.find(e => e === rowNode.rowIndex) == undefined ? true :false;
},
jumpButton: true,
selectButton: false,
deselectButton: false,
primaryKey: this.props.primaryKey,
nextBadRow: null,
columnsWithDefaultsvalues: this.props.columnsWithDefaultsvalues,
rowIndexAlreadyImported: this.props.rowIndexAlreadyImported
};

For this case you don't have full solution.
You can make only one: fill this rows, but after rerendering it lose.
So you can only prepare data before first render of table, or you can change source data and rerender table, but in this case you lose all selected rows and you need to set it selected again.

Related

Limit user input in a text field using Kendo UI grid and React

So I have a datagrid, with editable rows where the user can edit and add rows.
I want the user to have a limit on each different row cell field. For example, smallNumber will have 3 and description will have 15. I am using Kendo UI and React v18.2.0
<Grid
editField={editField}
onItemChange={itemChange}
data={dataField}
key="keys"
>
<Column field="smallNumber " title="Small NR" />
<Column field="stationDescription" title="DESCRIPTION" />
</Grid>
And itemChange func is like:
const itemChange = (event) => {
const newData = dataField.map((item) =>
item.dataFieldID === event.dataItem.dataFieldID
? { ...item, [event.field || ""]: event.value, changed: true }
: item
);
setDataField(newData);
};
If I add a maxLength={3} to the column for ex, it will give me a 500 server error. I want to use the onItemChange event, and check the value lenght for that field. If it is over 5, then the values in the state wont be updated, but i dont know how to do it. And also how to do it for different fields such as SmallNumber which needs less than 3 and Description that needs less than 15.
Found the solution:
Initialized the max length for each column
const itemsLength = {
stationDescription: 225,
stationNumber: 3
}
And then changed the newData funx like this
const newData = stations.map((item) =>
item.stationID === event.dataItem.stationID
? { ...item, [event.field || ""]: event.value.length <= itemsLength[event.field] ? event.value : item[event.field], changed: true }
: item
);

Primereact datatable: filter null values or template values

I have a datatable in primereact with a list of customers which has a column validTo which returns a date or null. I want to filter all valid customers, so I would filter for equals null, but that doesn't work because null resets the filter.
Second Option would be to replace null with something like "-" in a template, but how do I filter the value returned by the template, as it seems, that datatable only filters the source data?
Update 1:
I got a bit further.
my column looks like this
<Column
field="giltbis"
header="giltbis"
filter={true}
filterElement={giltbisFilterElement}
filterMatchMode="custom"
filterFunction={filterGiltbis}
sortable={true}
body={dateTemplate_giltbis}
/>
And here is my filter setup:
const handleFilterClick = (value) => {
setgiltbisSelected(value);
dt.current.filter(value, "giltbis", "custom");
};
const filterGiltbis = (value) => {
if (giltbisSelected === "Gültig") {
return value == null;
} else if (giltbisSelected === "Ungültig") {
return value != null;
} else {
//how to cancel filter or show all values
}
};
const giltbisFilterElement = (
<SelectButton
style={{ width: "100%" }}
value={giltbisSelected}
options={giltbisoptions}
onChange={(e) => handleFilterClick(e.value)}
/>
);
So only one problem left. How to I cancel the filtering or show all values?
You need to implement a custom filter function. Here is an example
filterMatchMode="custom" filterFunction={customFunction}
export const customFunction = (value, filter) => {
return value.toUpperCase().indexOf(filter.toUpperCase()) >= 0
}

I want to set checkbox to true based on a condition in ag-grid

I have a button which basically imports some data. This imported data needs to be compared with the data inside already loaded ag-grid and if there is a match, set the cehckbox of that particlar row node to true.
This is the button which checks for the condition:
enableCheck() {
alert('works');
if (this.DataService.isNotBlank(this.rowDataImport)) {
for (let i = 0; i < this.rowDataImport.length; i++) {
if (this.DataService.isNotBlank(this.rowData)) {
for (let j = 0; j < this.rowData.length; j++) {
if (this.DataService.isNotBlank(this.rowData[j].calDate)) {
for (const calDates of this.rowData[j].calDate) {
if (
this.rowDataImport[i].isin === calDates.isin ||
this.rowDataImport[i].portfolioName === calDates.portfolioName ||
this.rowDataImport[i].valuationDate === calDates.valuationDate
)
{
// alert('true')
this.checkValue = true;
} else {
this.checkValue = false;
}
}
}
}
}
}
}
}
The this.checkValue is a flag which will be true if match is found.
public gridColumnDefs = [
{
headerName: 'Portfolio Name',
field: 'portfolioName',
cellRenderer: 'agGroupCellRenderer',
headerCheckboxSelection: true,
headerCheckboxSelectionFilteredOnly: true,
checkboxSelection: true,
pinned: 'left',
filter: true,
cellRendererParams:(params) => {
console.log(params);
if (this.checkValue) {
params.node.selected = true;
}
}
},
]
here I used cellRendererParams. But this will only for on load I guess. What to do if I want to update the ag-grid row from a value outside i.e. from import check as given above?
First of all, you should add id for each row in defaultColDef
this.defaultColDef = {
getRowNodeId: data => data.id,
};
Then you can find this id and set the checkbox to true.
Also, you can find separate field by name.
It is really easy, you should use the next combination
selectRow() {
this.gridApi.forEachNode(node => {
if (node.id == 1 || node.id == 2 || node.data.country == 'Australia') {
node.setSelected(true);
}
});
}
Working example:
https://plnkr.co/edit/ijgg6bXVleOAmNL8
In this example when we click on the button - we set the checkbox to true for two rows with id 1 and 2 and for each field that has country 'Australia'
And in your case, you are using incorrect configuration.
You should you cellRenderer
cellRenderer: params => {
if(params.value === 'Ireland') {
params.node.setSelected(true)
}
return params.value
},
One more example: https://plnkr.co/edit/PcBklnJVT2NsNbm6?preview
I manpulated a bit and did the below which worked like a charm.
this.gridApi.forEachNode(node => {
if (node.data.isin === this.rowDataImport[i].isin &&
node.data.portfolioName === this.rowDataImport[i].portfolioName &&
node.data.valuationDate === this.rowDataImport[i].valuationDate
) {
node.setSelected(true);
}

How do I validate a checkout form in React?

I am trying to implement a checkout form in React. The form has 4 fields in all: Name, CC Number, CC expiration and CVV. I am using a library that validates each field on unfocus. The validation is triggered by the validationCallback method which takes 3 arguments: field, status, and message. I'd like to key off of the status for each input and only allow submit once each status === true. Here is my code.
constructor(props) {
super(props);
this.state = {
nameOnCard: '',
errorMessage: '',
showLoaderForPayment: '',
collectJs: null,
token: null,
isPaymentRequestCalled: false,
showErrorModal: false,
paymentErrorText: '',
disabled: true,
};
}
I have a disabled property in my state which I'm initially setting to true.
validationCallback: (field, status, message) => {
if (status) {
this.setState({ errorMessage: '' });
} else {
let fieldName = '';
switch (field) {
case 'ccnumber':
fieldName = 'Credit Card';
break;
case 'ccexp':
fieldName = 'Expire Date';
break;
case 'cvv':
fieldName = 'Security Code';
break;
default:
fieldName = 'A';
}
if (message === 'Field is empty') {
this.setState({ errorMessage: `${fieldName} ${message}` });
} else {
this.setState({ errorMessage: `${message}` });
}
}
},
In the above method, I'd like to set disabled to false if each of the field's status===true... Below is the button which I'm setting to be the value of this.state.disabled.
<button
className="continueBtn disabled"
disabled={this.state.disabled}
onClick={this.handleCardSubmit}
>
<span className="fa fa-lock" />
Pay $
{selectedPayment.amount}
</button>
I hope this is enough of the code to help with the issue. I can provide more of the file if need be.
From what i understand, you want to set the button to NOT DISABLED if all the fields are filled properly, i.e. all status are true.
What you can do is maintain a boolean array for each field and update the status in that array, i.e. initialize an array of length = no. of fields (in your case 3) and set all values as false. False depicts that the field hasn't been validated.
this.state = {
statusArray = [false, false, false] // For as many fields
}
Then in validationCallback, set the index as true or false for that field i.e. if the 2nd field status is returned true by your validation library, set statusArray as [false, true, false].
The form will only be validated if all 3 of the values become true. So you can iterate over the array and check if array has all 3 values as true. or you can use the logical AND operator which returns true only if all values are true(the approach which i use below).
For the button,
<button disabled={this.checkDisable()}>
checkDisable = () => {
let temp = this.state.statusArray;
let answer = true;
for(int i=0;i<temp.length;i++)
answer = answer && temp[i];
return answer; // Only returns true if all 3 values are true
}
I hope you get it now.
You need to check 2 things, has the form been touched and are there any errors. I don't know what library you are using but most likely it has a property touched in it, if not add an onFocus to each input field and a touched property in your state. You don't really need a disabled property in your state since its a computed value. Just check on every render if the form has been touched and if there are any errors.
state = {
...,
touched: false,
...
}
handleFocus = () => this.setState({touched: true})
render(){
const disabled = !!(this.state.touched && this.state.errorCode)
return(
...
<input onFocus={this.handleFocus} ... />
...
<button disabled={disabled}
)
}
EDIT:
state = {
...
validInputs: []
}
validationCallback: (field, status, message) => {
if (status) {
this.setState((state) => ({ errorMessage: '', validInputs: [... new Set([...state.validInputs, field])] }));
} else {
...
render(){
const disabled = this.state.length < inputs.length // the number of the input fields
return(
...
<button disabled={disabled} >
...
)

How Can I Make All Checkboxes "Checked" By Default

How can I ensure by default all by checkboxes (output from my data) are all checked by default on load?
Output checkbox
<div v-for="(category, index) in remove_category_duplicates" class="form-check">
<input type="checkbox" class="form-check-input" v-model="cat_data" :id="category" :value="category">
<label class="form-check-label">{{ category }}</label>
</div>
Setup checkbox values from data
remove_category_duplicates: function () {
// Get all categories and remove duplicates
let data = {}
this.info.forEach(i=>{
Object.assign(data,i.category_data);
})
return data;
},
Data:
{
"id": 1,
"title": "Title one",
"category_data": {
"2": "Team",
"7": "Queries"
}
},
CodePen: https://codepen.io/anon/pen/XxNORW?editors=1011
Thanks
To initialize the checkboxes to true/checked, their v-model array (cat_data) should contain the true-value of each checkbox. In this case, it would be:
["Team", "Questions", "Queries", "Fax"]
Here's how I would update your code:
Add a computed property to return an array of available categories:
computed: {
categories() {
const cats = this.remove_category_duplicates;
return Object.keys(cats).map(k => cats[k]);
}
}
Update select() to set cat_data based on selectAll. If selectAll is true, set cat_data to the category array computed above (thus marking all boxes checked), or else an empty array (thus unchecking all boxes):
methods: {
select() {
this.cat_data = this.selectAll ? this.categories : [];
}
}
Add a method (e.g., named "toggleSelectAll") to toggle selectAll based on whether all checkboxes are checked, keeping the Select All checkbox in sync with the state of the other checkboxes:
methods: {
toggleSelectAll(e) {
const checked = e.currentTarget.checked;
if (checked) {
this.selectAll = this.arrayContains(this.categories, this.cat_data);
} else {
this.selectAll = false;
}
}
}
Add a change-handler on each checkbox (except the Select All box) that calls toggleSelectAll defined above:
<div v-for="category in remove_category_duplicates">
<input type="checkbox" #change="toggleSelectAll">
demo

Resources