How to remove extra td on colspan reactjs - reactjs

I have a table which contains td with colspan. Whenever I add colspan to a row, there is an additional or excess added cell.
const RenderTD = ({row}) => {
return table.cols.map(col => (
<td key={col}
colspan={row == 1? 2 : 1}>{col}</td>
))
}
here is the sample code: https://jsfiddle.net/e7gnd1tf/
How can I remove these?

Dont create components inside another component. Or use memoization
Td should be wrapped in tbody
Use key prop
The excess cell is being created because when you add colspan to a cell, it merges that cell with the next cell, effectively removing the next cell from the table. However, in your code, you are still creating that next cell, even though it has been merged with the previous cell. To fix this issue, you can conditionally render the extra cell only if colspan is not used, like this:
const RenderTD = ({ row }) => {
return table.cols.map((col, index) => (
<React.Fragment key={col}>
<td
colSpan={row === 1 && index === 0 ? 2 : undefined}
rowSpan={row === 2 && index === 0 ? 2 : undefined}
>
{col}
</td>
{index === 0 && row === 3 && <td></td>}
</React.Fragment>
));
};
In the above code, the extra cell is only rendered if colspan is not used and the row is the third row (row === 3) and the column is the first column (index === 0).

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
);

sorting tasks in three column

I have a task manager in home component I'm getting all task and I put tasks in column component
const { tasks} = useTypedSelector((state) => state.task);
const new_tasks = tasks.filter((task) => task.position == 'new');
const progress_tasks = tasks.filter((task) => task.position == 'progress');
const done_tasks = tasks.filter((task) => task.position == 'done');
<div className="columns">
<Column position="new" inner_tasks={new_tasks} />
<Column position="progress" inner_tasks={progress_tasks} />
<Column position="done" inner_tasks={done_tasks} />
</div>
then in column component I'm gettin in props inner_tasks
Column = ({ position, inner_tasks })
and render tasks depends of position
{inner_tasks &&
inner_tasks.map((item) =>
item && item.position == position ? (
in total I got 3 arrays, but only one component - column.
I want to add sorting and I want to if I selected sorting in first column tasks in first column will be sorted, but in 2 and 3 column not.
I writed sorting func
const hangleChange = (sortingType, position_name) => {
debugger;
inner_tasks.filter((item) => item.position == position_name);
sorted = inner_tasks.sort((a, b) =>
a.priorityNum > b.priorityNum ? 1 : -1
);
};
sortingType will be 'by date' or 'by priority'
position_name it's just name of column for example 'new tasks' or 'done'
ok, now I have sorted array with name sorted, but how can I replace and rerander my tasks in one column and don't change my other columns. I don't know i to change this part of code
{inner_tasks &&
inner_tasks.map((item) =>
item && item.position == position ? (
I think problem is here. Help me guys!

How to avoid display error when filtering > 0 in the middle of the map

I have a state "inventory", it stores item, price, qty, remark
when display using
this.state.inventory.filter(q => q.qty > 0).map
everything shows fine only if there's no 0 within
Googled and stackoverflowed, can't find any way to solve this..
new to ReactJS
{this.state.inventory.filter(q => q.orderQty > 0).map((val,ind) => (
<tr key={ind}>
<td>{ind}.{this.state.inventory[ind].item}</td>
<td>{(this.state.inventory[ind].price).toLocaleString()}</td>
<td>{(this.state.inventory[ind].orderQty).toLocaleString()}</td>
<td>{(this.state.inventory[ind].orderQty * this.state.inventory[ind].price).toLocaleString()}</td>
<td>{this.state.inventory[ind].orderRem}</td>
<td><button onClick={(e) => { this.handleDeleteRow(e,ind); }}>DEL</button></td>
</tr>
))
}
My question is, when looping inside the map, inventory[ind].orderQty === 0, the rest of the map becomes incorrect. how do I skip when inventory[ind].orderQty === 0?
its because you are using Index. using index is always a bad option. use the object directly instead "val"
{
this.state.inventory.filter(q => q.orderQty > 0).length>0?
this.state.inventory.filter(q => q.orderQty > 0).map((val,ind) => (
<tr key={ind}>
<td>{ind}.{val.item}</td>
<td>{(val.price).toLocaleString()}</td>
<td>{(val.orderQty).toLocaleString()}</td>
<td>{(val.orderQty * val.price).toLocaleString()}</td>
<td>{val.orderRem}</td>
<td><button onClick={(e) => { this.handleDeleteRow(e,ind); }}>DEL</button></td>
</tr>
)):""
}

Rendering a table where each cell correspond to an element with material-ui in React.js

So I need to make a table where each product corresponds to a cell; however, there's something with the JSX that prevents me from returning jsx when I don't close the tags in the returned JSX. I am not sure if there are alternate methods, but it seems that I am in a kind of bind, because the error message doesn't make sense and I get things like unexpected token.
Tried to return the JSX with map inside the callback, but it seems I can't do exactly what I want.
{props.products.slice(0, 50).map((element, i) => {
console.log(element.name);
if (i % 5 == 0) {
return (
<TableRow>
<TableRowColumn>{element.name}</TableRowColumn>
)
} else if (i % 5 == 4) {
return (
<TableRowColumn>{element.name}</TableRowColumn>
</TableRow>
)
} else {
return (
<TableRowColumn>{element.name}</TableRowColumn>
)
}
})}
I expect each row to have 5 columns, and each cell containing a product and the table containing 50 elements. Basically, I want to close the row after 5 column.
I would like to have something like a 5 by 5 table in the end or 5 by 10 to be exact.
You can check some examples on material-ui site (https://material-ui.com/demos/tables/)
If you know which elements are headers names you can use for-loop over products to create columns name e.g.
<TableRow>
{props.products.map((product, index) => {
if (index % 5 === 0) {
return <TableCell>{product.name}</TableCell>;
}
}
</TableRow>
JSX is not HTML and you cannot brake up tag pairs.
Proper solution should be like this
function chunker(array, length) {
// select proper implementation on the link below
return []
}
{chunker(props.products.slice(0, 50)), 5).map((chunk) => {
if (chunk.length !== 5) {
console.warn('not full chunk', chunk)
}
return (
<TableRow>
{chunk.map((element, i) => {
console.log(element.name);
return (
<TableRowColumn>{element.name}</TableRowColumn>
)
})}
</TableRow>
)
})}
Select chunk implementation here Split array into chunks

Conditionally render <td> in a React component

This is a JSX gist I'm displaying on the page.
rows.push(
<tr key={i}>
<td>{this.state['Person Name'] && this.state['Person Name'][i]}</td>
<td>{this.state['Amount'] && this.state['Amount'][i]}</td>
{this.state['Memo'] && this.state['Memo'].length > 0 ? <td>{this.state['Memo'][i]}</td> : undefined}
{this.state['Comment'] && this.state['Comment'].length > 0 ? <td>{this.state['Comment'][i]}</td> : undefined}
{this.state['Incurred Date'] && this.state['Incurred Date'].length > 0 ? <td>{this.state['Incurred Date'][i]}</td> : undefined}
{this.state['Entry Date'] && this.state['Entry Date'].length > 0 ? <td>{this.state['Entry Date'][i]}</td> : undefined}
<td>{this.state['Billable'] && this.state['Billable'][i]}</td>
<td>{this.state.fileName === 'expenses.csv' ? 'Expense' : 'Time'}</td>
</tr>
)
Somehow the conditions that are falsy still display empty <td>s to the table. What did I miss?
Empty columns are shown above.
You don't need to use ternary operators at all. Simply just chain &&'s.
{this.state.Memo && this.state.Memo[i] && <td>{this.state.Memo[i]}</td>}
{this.state.Comment && this.state.Comment[i] && <td>{this.state.Comment[i]}</td>}
{this.state['Incurred Date'] && this.state['Incurred Date'][i] && <td>{this.state['Incurred Date'][i]}</td>}
{this.state['Entry Date'] && this.state['Entry Date'][i] && <td>{this.state['Entry Date'][i]}</td>}
In addition, your array seems to be badly formatted:
// 2 separate variables for the same data?
this.memo = ['a', 'b'];
this.comment = ['comment', 'comment2'];
// Why not make it an array like this?
this.rows = [
{
Memo: 'a',
Comment: 'comment'
},
{
Memo: 'b',
Comment: 'comment2'
}
];
Then you can simply do:
this.rows.map(row => (
<tr key={row.id}>
<td>{row['Person Name']}</td>
<td>{row['Amount']}</td>
{this.state.hasMemos && <td>{row.Memo}</td>}
...
</tr>
)}
A <td> shouldn't be conditional on a row level, it should be conditional on a table level. You can't simply skip TD's if there isn't data for that row, as it will throw off the whole row by shifting columns over. You should either display N/A, an empty <td></td> for rows that may not have data, or hide them entirely on a table level via something like this.state.hasMemos, if there are any memos.
If you're using the new array structure I have listed, you can use this function to determine if any row has a memo:
this.array.some(row => row.Memo);
This will return true if any row has a Memo, thus either hiding the <td> for the entire table, or displaying it for every row.

Resources