I have this code in running, here I have given hard coded [0] value,
using this data in <MaterialTable columns={Here using data for table} />,
it should render only first row, but instead its rendering all rows after giving hardcoded 0,
How this result into rendering all columns with all rows and iterating two time?
previewData = [
{id: 1, name: "FileName", size: 15690, type: "doc", Date: "DDMMYY"}
{id: 2, name: "FileName", size: 15690, type: "doc", Date: "DDMMYY"},
{id: 3, name: "FileName", size: 15690, type: "doc", Date: "DDMMYY"},
{id: 4, name: "FileName", size: 15690, type: "doc", Date: "DDMMYY"}
]
Object.keys(props.previewData[0]).map((x) => {
if(x=="id"){return <div>{x}</div>}
) : []
Strange working code:
const columns = () => {
return (
props.previewData && props.previewData.length > 0 ?
Object.keys(props.previewData[0]).map((x) => {
if (props.Table && props.Table !== "nameTable") {
if (x === "id"){
return ({
title: ,
field: x,
width: "500rem",
sorting: false
})// similar code for other fields also
// this code should gets called only once for array [0], its get iterated over from `.forEach()` from data of MaterialTable How???
}
return (
<MaterialTable
title = ""
icons={}
options={{
}}
columns={columns()}
data={
props.previewData && props.previewData.length > 0 ? props.previewData.map((row) => {
const eachRowData = {};
Object.keys(row).forEach((y) =>{
})
return eachRowData;
}) : []
}
/>
Object.keys(props.previewData[0]) with your example previewData is:
["id", "name", "size", "type", "Date"]
Then you map those values to:
[<div>id</div>, undefined, undefined, undefined, undefined]
because you've used map (not filter) and returned something only when the x parameter's value is "id", which is only true for one of the five elements in the array.
It's not clear to me from your question what you want to do instead, but that's why you're getting an array with five elements rather than one. It almost seems like you're trying to filter so you only produce one div, but you're filtering based on a hardcoded value ("id") which would mean you wouldn't need map at all, you'd just do:
<div>{props.previewData[0].id}</div>
Related
Good day! I was wondering why I didnt display data on my grid table eventhough I can see or received data from my api response, I just wondering whats wrong on my code. here is my current code and please see my return data below, thanks
const UserModule = () => {
const logHeader = [
{ field: 'id', headerAlign: 'left', headerName: 'ID', hide: true, width: 50 },
{ field: 'firstname', headerAlign: 'left', headerName: 'First Name', width: 130 },
{ field: 'lastname', headerAlign: 'left', headerName: 'Last Name', sortable: true, width: 110 },
{ field: 'status', headerAlign: 'left', headerName: 'Status', width: 80 },
]
const [transactionLogData, setTransactionLogData] = useState([]);
useEffect(() => {
WorkflowApi.getTransactionLogForRevenueOfficer().then(logs => {
const newLogs = Object.fromEntries(Object.entries(logs).map( ([k,v]) => {
return [k, {
...v,
id: v._id
}] // I think the problem is here
}))
console.log("newLogs: ", newLogs)
setTransactionLogData(newLogs)
})
})
....
return (
<Grid item xs={12}>
<Box ref={componentRef}>
<RecordTable
columns={logHeader}
rows={transactionLogData}>
</RecordTable>
</Box>
</Grid>
)
}
//RecordTable.js
const RecordTable = (props) => {
const { columns, rows } = props
useEffect(async () => {
}, [rows])
//This type of array did my RecordTable component expects
// const sampleRows = [
// {
// "_id": 458,
// "LastUpdateDate": "2022-02-10",
// "status": "Approved",
// "firstname": "Yuno",
// "lastname": "Santiago",
// "id": 458
// }
// ]
return(
<DataGrid
....
columns={columns}
rows={rows}
....
/>
)
}
response i received from my api
{
"_id": 458,
"LastUpdateDate": "2022-02-10",
"status": "Approved",
"firstname": "Yuno",
"lastname": "Santiago",
"id": 458
}
this is the error i get
Warning: Failed prop type: Invalid prop rows of type object supplied to ForwardRef(DataGrid), expected array.`
Update after i remove the Object.fromEntries
const newLogs = Object.entries(logs).map( ([k,v]) => {
return [k, {
...v,
id: v._id
}] // I think the problem is here
})
i received this error
Uncaught Error: MUI: The data grid component requires all rows to have a unique id property.
check your rows props, it highly possible is empty object at first render.
To do so, you just console.log({rows}) and see the value printed in browser
I believe the problem is in the Object.fromEntries, the result of this method is always an object, not an array. Try to remove the Object.fromEntries, and leave only the Object.entries
For me, the problem is that I put the column content in another file.
I just put it in the app component and it solves the problem.
It creates an object if the column is in another file,
try to put your recordtable component in the same component(userModule I guess)
I have a fairly simple table, and am currently using a bottom calculator formatter:
export let myTable = new Tabulator("#my-table", {
columns:[
{title:"ID", field:"id", headerSort:false, visible:false, responsive:2},
{formatter:"rowSelection", titleFormatter:"rowSelection", align:"center", bottomCalc:"sum", hozAlign:"center", headerSort:false, cellClick:function(e, cell){
cell.getRow().toggleSelect();
}},
{title:"Name", field:"address", width:300, bottomCalc:"count"},
{title:"My Data", field:"mydata", bottomCalc:avNoOutsiders},
],
});
export let avNoOutsiders = function(values, data, calcParams){
// filter outliers
let myArray = filterOutliers(values);
// filter any null or falsy values
let av = average(myArray);
return av
}
The code isn't super important, but what I'd like to be able to do is allow the user to de-select a row to exclude the value from this calculation.
The problem is, I don't understand how to access the isSelected() function here, I think it's just the row() I can access it. I can access the values (all the column values) but there's no selection data there, I can access the data - the whole table, but there's no way of determining which row it is, or whether it is selected or not.
My current direction of thinking is either
using bottomCalcParams. I don't understand how I would do this. This function returns a getRow() is not a function error:
function cellIsSelected(cell){
selected = cell.getRow().isSelected()
return {isSelected:selected};
}
or
Writing individual functions for each bottom calc. This doesn't work as I can't call the table inside the table calcs - var selectedRows = table.getSelectedRows() causes a circular error if I try to put that into a column calc function. I can reference the table inside the table.
Any ideas how I can access the row selection data to make a column calculation?
There might be an easier way, but one way to achive that would be to create a hidden placeholder column which can be updated to true/false upon row selection/deselection. Then you can use the values of this hidden column in your bottomCalc function to exclude rows that are not selected. Here is an example where selecting a row will re-trigger bottom calculation and average the age of all selections:
const dataSet1 = [
{ id: 1, name: 'Billy Bob', age: '21', gender: 'male' },
{ id: 2, name: 'Mary May', age: '5', gender: 'female' },
{ id: 3, name: 'Christine Lobowski', age: '42', gender: 'female' },
{ id: 4, name: 'Brendon Philips', age: '80', gender: 'male' },
]
const calcAvg = (values, data, calcParams) => {
let selected = data.filter((row) => row.isSelected)
values = selected.map((i) => i.age)
let avg = values.reduce((a, b) => Number(a) + Number(b), 0) / values.length
return avg ? avg : ''
}
const table = new Tabulator('#table', {
data: dataSet1,
columns: [
{
formatter: 'rowSelection',
titleFormatter: 'rowSelection',
cellClick: (e, cell) => {
cell.getRow().toggleSelect()
}
},
{ title: 'Name', field: 'name' },
{ title: 'Age', field: 'age', bottomCalc: calcAvg },
{ title: 'Gender', field: 'gender' },
{ title: '', field: 'isSelected', visible: false } // Selection placeholder column
]
})
const selection = (row) => {
row.update({ isSelected: row.isSelected() })
table.recalc()
}
table.on('rowSelected', selection)
table.on('rowDeselected', selection)
<html>
<head>
<link href="https://unpkg.com/tabulator-tables#5.2.2/dist/css/tabulator.min.css" rel="stylesheet">
<script type="text/javascript" src="https://unpkg.com/tabulator-tables#5.2.2/dist/js/tabulator.min.js"></script>
</head>
<body>
<div id="table"></div>
</body>
<html>
#Tim's answer got me 95% of the way there.
Note that some of his responses don't work on Tabulator v4.9:
const selection = (row) => {
row.update({ isSelected: row.isSelected() })
table.recalc()
}
table.on('rowSelected', selection)
table.on('rowDeselected', selection)
I thought that figuring out a way round this might take longer than updating, so I plunge and updated to 5.2.2, which was less painful than expected. I had multiple columns to calculate, so rather than running a different function for each one, I passed the field name into the function via the bottomCalcParams, thus:
const calcAvg = (values, data, calcParams) => {
let selected = data.filter((row) => row.isSelected)
// Add your calcParams here:
values = selected.map((i) => i[calcParams.field])
let avg = values.reduce((a, b) => Number(a) + Number(b), 0) / values.length
return avg ? avg : ''
}
const table = new Tabulator('#table', {
data: dataSet1,
columns: [
{
formatter: 'rowSelection',
titleFormatter: 'rowSelection',
cellClick: (e, cell) => {
cell.getRow().toggleSelect()
}
},
{ title: 'Name', field: 'name' },
{ title: 'Age', field: 'age', bottomCalc: calcAvg, bottomCalcParams:{field:"age"} },
{ title: 'Remaining Teeth', field: 'teeth', bottomCalc: calcAvg, bottomCalcParams:{field:"teeth"} },
{ title: 'Personality Quirks', field: 'quirks', bottomCalc: calcAvg, bottomCalcParams:{field:"quirks"} },
{ title: 'Gender', field: 'gender' },
{ title: '', field: 'isSelected', visible: false } // Selection placeholder column
]
})
I have my data objects that I need to fetch, looking like this:
const products = {
one: {
id: 1,
name: 'One',
image: oneImage,
chair: {
name: 'ChairName',
image: myImage,
colors: {
white: {
name: 'White',
image: myImage,
},
black: {
name: 'Black',
image: myImage,
},
},
},
},
},
two: {
id: 2,
name: 'Two',
image: twoImage,
chair: {
name: 'Chair,
image: myImage,
colors: {
white: {
name: 'White',
image: myImage,
},
black: {
name: 'Black',
image: myImage,
},
},
},
},
};
I am fetching them with Object.value
const ProductsData = Object.values(products).map((data) => {
return (
<>
<div className="box" onClick={() => setSelectedData(data)}>
<img src={data.image} />
</div>
);
});
This code above works just fine, pointing out to selected data like this:
{selectedData ? (
<h1>{selectedData.name}</h1>
) : null}
But now I would like to map through the chair colors of selected Data, which causes errors.
What I tried to do was to just {selectedData.chair.colors.name}, which prints nothing and by console.log is underfined
How can I print selectedData of chair colors and how I can set the picked color as new selectedData? I am getting lost.
If you want to choose color, then you need to store it in another state variable.
const [selectedColor, setSelectedColor] = React.useState();
Use Object.values to iterate chair.colors
{Object.values(selectedData.chair.colors).map(val => {
return <div onClick={() => setSelectedColor(val.name)}>{val.name}</div>
})
}
Check this sandbox
You don't have selectedData.chair.colors.name, look again in your structure. There is selectedData.chair.colors.white.name or selectedData.chair.colors.black.name
colors is an object again. It does not have a property name. It has properties like white and black which are objects themselves.
Map through:
Object.values(selectedData.chair.colors)
let selectedChairColors = Object.values(selectedData.chair.colors)
;
console.log(selectedChairColors[0])
console.log(selectedChairColors[1])
You can log selectedChairColors to see that this will give you an array of values of colors property in chair of selectedData.
Looking at your sandbox it seems you are using no checks while running selectedData and hence the error. (Initially, selectedData is undefined).
This should work:
<div>{selectedData && Object.values(selectedData.chair.colors).map((x)=>
JSON.stringify(x)
)}</div>
Here is sandbox forked out of yours.
[![Firefox Console][1]][1]In my Vue app I am trying to use mdb-datatable, the table reads data() and sets the rows accordingly. I am setting the row data programmatically after my data is loaded with Ajax. In one column I need to add a button and it needs to call a function. I am trying to add onclick function to all buttons with "status-button" class but something weird happens.
When I print HtmlCollection it has a button inside, which is expected but I can't reach proceedButtons[0], it is undefined. proceedButtons.length also prints 0 length but I see the button in console.
I also tried to add onclick function but probably "this" reference changes and I get errors like "proceedStatus is not a function" it does not see anything from outer scope.
<mdb-datatable
:data="tableData"
:searching="false"
:pagination="false"
:responsive="true"
striped
bordered/>
export default {
name: "Applications",
mixins: [ServicesMixin, CommonsMixin],
components: {
Navbar,
Multiselect,
mdbDatatable
},
data () {
return {
statusFilter: null,
searchedWord: '',
jobRequirements: [],
applications: [],
options: ['Awaiting', 'Under review', 'Interview', 'Job Offer', 'Accepted'],
tableData: {
columns: [
{
label: 'Name',
field: 'name',
sort: 'asc',
},
{
label: 'Date',
field: 'date',
sort: 'asc'
},
{
label: 'Compatibility',
field: 'compatibility',
sort: 'asc'
},
{
label: 'Status',
field: 'status',
sort: 'asc'
},
{
label: 'Proceed Application Status',
field: 'changeStatus',
}
],
rows: []
}
}
}
fillTable(applications) {
let statusButtonId = 0;
applications.forEach(application => {
this.tableData.rows.push({
name: application.candidateLinkedIn.fullName,
date: this.parseDateFromDateObject(application.applicationDate),
compatibility: this.calculateJobCompatibility(application.candidateLinkedIn.linkedInSkillSet),
status: application.applicationStatus,
changeStatus: '<button type="button" class="btn-indigo btn-sm m-0 status-button"' +
' style="margin-left: 1rem">' +
'Proceed Status</button>',
candidateSkillSet: application.candidateLinkedIn.linkedInSkillSet
});
statusButtonId++;
});
},
addEventListenersToButtons() {
let proceedButtons = document.getElementsByClassName("status-button")
console.log(proceedButtons);
console.log(proceedButtons[0])
console.log(proceedButtons.item(0))
/*
proceedButtons.forEach(button => {
button.addEventListener("click",this.proceedStatus);
});
*/
},
[1]: https://i.stack.imgur.com/zUplv.png
From MDN:
Get the first element with a class of 'test', or undefined if there is no matching element:
document.getElementsByClassName('test')[0]
So undefined means no match, even if length is 0...
Since this is not an array, you do not get out-of-bounds exceptions.
https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName
Regarding Arrays
You can't index the list returned from getElementsByClassName.
You can turn it into an array though, and then index it.
ES6
let proceedButtons = document.getElementsByClassName("status-button")
const arr = Array.from(proceedButtons);
console.log(arr[0]);
Old School
const arr = []
Array.prototype.forEach.call(proceedButtons, function(el) {
arr.push(el);
});
console.log(arr[0]);
First of all i am very new to React JS. So that i am writing this question. I am trying this for three days.
What I have to do, make a list of category, like-
Category1
->Sub-Category1
->Sub-Category2
Categroy2
Category3
.
.
.
CategoryN
And I have this json data to make the listing
[
{
Id: 1,
Name: "Category1",
ParentId: 0,
},
{
Id: 5,
Name: "Sub-Category1",
ParentId: 1,
},
{
Id: 23,
Name: "Sub-Category2",
ParentId: 1,
},
{
Id: 50,
Name: "Category2",
ParentId: 0,
},
{
Id: 54,
Name: "Category3",
ParentId: 0,
},
];
I have tried many open source examples, but their json data format is not like mine. so that that are not useful for me. I have build something but that is not like my expected result. Here is my jsfiddle link what i have done.
https://jsfiddle.net/mrahman_cse/6wwan1fn/
Note: Every subcategory will goes under a category depend on "ParentId",If any one have "ParentId":0 then, it is actually a category, not subcategory. please see the JSON
Thanks in advance.
You can use this code jsfiddle
This example allows to add new nested categories, and do nested searching.
code with comments:
var SearchExample = React.createClass({
getInitialState: function() {
return {
searchString: ''
};
},
handleChange: function(e) {
this.setState({
searchString: e.target.value.trim().toLowerCase()
});
},
isMatch(e,searchString){
return e.Name.toLowerCase().match(searchString)
},
nestingSerch(e,searchString){
//recursive searching nesting
return this.isMatch(e,searchString) || (e.subcats.length && e.subcats.some(e=>this.nestingSerch(e,searchString)));
},
renderCat(cat){
//recursive rendering
return (
<li key={cat.Id}> {cat.Name}
{(cat.subcats && cat.subcats.length) ? <ul>{cat.subcats.map(this.renderCat)}</ul>:""}
</li>);
},
render() {
let {items} = this.props;
let {searchString} = this.state;
//filtering cattegories
if (searchString.length) {
items = items.filter(e=>this.nestingSerch(e,searchString))
console.log(items);
};
//nesting, adding to cattegories their subcatigories
items.forEach(e=>e.subcats=items.filter(el=>el.ParentId==e.Id));
//filter root categories
items=items.filter(e=>e.ParentId==0);
//filter root categories
return (
<div>
<input onChange={this.handleChange} placeholder="Type here" type="text" value={this.state.searchString}/>
<ul>{items.map(this.renderCat)}</ul>
</div>
);
}
});