How to filter the columns? Here I need a date filter column, When we click the header of the date, it automatically sorts the column.
Actually, they asked like this "Need to sort by date and stick the 6 newest on this one as well"
Can you please help with this?
Here is the code I used.
You need to use a helper function in order to parse the string to Date object.
Then you can apply the sorting
Check the code snippet.
I store the Date object into another property in order not to break anything. You can of course replace it with the current property and format it accordingly inside your table cell.
function parseStr(str) {
let parts =str.substring(0, 10).split('.');
return new Date(parts[2], parts[1] - 1, parts[0]);
}
let array = [
{
"number":"5421787",
"amount":1391.74,
"duedate":"28.08.2020 00.00.00",
"voucherdate":"14.08.2020 00.00.00",
"invoicelink":"",
"status":"Betalt"
},
{
"number":"5499047",
"amount":499.0,
"duedate":"29.09.2020 00.00.00",
"voucherdate":"15.09.2020 00.00.00",
"invoicelink":"",
"status":"Betalt"
},
{
"number":"5574780",
"amount":499.0,
"duedate":"29.10.2020 00.00.00",
"voucherdate":"15.10.2020 00.00.00",
"invoicelink":"",
"status":"Betalt"
}
]
console.log(array.map(obj => ({ ...obj, voucherdate2: parseStr(obj.voucherdate)})).sort((a,b) => b.voucherdate2.getTime() - a.voucherdate2.getTime()))
So in your code
const invoiceData = useSelector((state) => state.userReducer.invoices)
let sortableInvoiceData = invoiceData.map(obj => ({ ...obj, voucherdate2: parseStr(obj.voucherdate)})).sort((a,b) => b.voucherdate2.getTime() - a.voucherdate2.getTime())
const renderInvoices = sortableInvoiceData.map((invoice, index) => {
Related
I have an API. When I click on a button, I want to filter the hashtag data which are arrays and those arrays are in their
objects. This is what I did. It doesn't return anything in this code. I need any help you can do.
This is my code :
const hashtagsHandler = (event, title) => {
const eventData = event.target.innerText;
console.log(eventData);
const filter = bookData.filter((items) => {
items.hashtags.map((item) => item === eventData);
});
console.log(filter);
if (filter.length !== 0) {
setHashtag(filter);
setAllFilter((prevState) => [...prevState], hashtag);
}
};
My API is something like this:
"data": [
{
"id": 1,
"name": "name",
"typename": "book",
"hashtags": [
"a",
"b",
],
}
]
Your filter function doesn't work because it doesn't return anything, the function should return a Boolean value so it can know what to filter out and what to keep. Like this:
function isBigEnough(value) {
return value >= 10;
}
const filtered = [12, 5, 8, 130, 44].filter((value) => {
return value >= 10;
});
Read more about it here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter.
To correct your code you can do it this way:
const filter = bookData.filter((item) => item.hashtags.includes('a'));
const filteredData = bookData.filter(
(items) => items.hashtags.filter((item) => item === eventData).length !== 0
);
console.log(filteredData);
It' s simply a syntax problem of array function that returns new array from original array, like filter, map, ...
Full syntax (with curly bracket): arr.arrFunc((param1, param2) => {/* your logic with return statement */}).
Use when you need to perform complex modification with if or for statement
Short hand (without curly bracket): arr.arrFunc((param1, param2) => /* <your logic> */. Use when performing inline modification
Example: jsFiddle
I get a csv with multiple columns from the backend, but I would like to change the data in a column before exporting this csv as a report.
Today I am using the react-csv library to export the report.
The column I want to modify is the Type. Currently she returns the values Product and Service. Instead of displaying Product I would like to display New Product and instead of Service I would like to display Used Product
report:
"Title","Type","Advertiser","Category"
"2 plots of 15x35 - R $ 15,000.00 each","product","LUIZ FABIANO DE OLIVEIRA0","Properties"
"3 Industrial machines","service","GISELE SANTANA","services"
code:
export default function exem() {
const [dataExport, setDataExport] = React.useState([]);
function getCSV() {
request
.get(urlGetCSV() + `&page=${page}`)
.text()
.then(response => {
setDataExport(response)
});
}
return (
<>
<CSVLink
data={dataExport}
filename={`report-${new Date().toLocaleString()}.csv`}
onClick={getCSV}
>
<Button>
Report
<Button.Icon>
<ReportIcon />
</Button.Icon>
</Button>
</CSVLink>
</>
)
}
If response is an array you could remap it before calling setDataExport:
const typeMappings = {
'product': 'New Product',
'service': 'Used Product'
}
.then(response => {
// find the "Type" column
const headers = response[0]; // assumes headers in the first row
const typeColumnIndex = headers.indexOf('Type'); // index of the column with 'Type' header
response.forEach(item => { // iterate over each row
// get the type from the row
const originalType = item[typeColumnIndex];
// replace it with the corresponding mapping.
// if no mapping exists, leave the original value.
item[typeColumnIndex] = typeMappings[originalType] || originalType;
})
setDataExport(response)
});
How can I make a summary row like this using a material table?
Please help me, thank you.
If by "Summary row" you're referring to table title, that's a prop "title" you just add to the <MaterialTable /> component.
However, I suspect you need the row with Total result, which I couldn't find in the examples, either.
Here's a custom function you could use to calculate a total by your own, add it to your data set and achieve similar result:
const addTotal = (data, byColumn) => {
let keys = Object.keys(data[0]);
let total = data.reduce((acc, el) => {
return acc += +(el[byColumn]);
}, 0);
let totalRow = {};
let emptyRow = {};
for (let key of keys) {
if (key === keys[0]) {
totalRow[key] = 'Total';
} else if (key === byColumn) {
totalRow[key] = total;
} else {
totalRow[key] = '';
}
emptyRow[key] = '';
}
return [...data, emptyRow, totalRow];
}
This will add an empty row and a total with the argument you put as byColumn. You need to be careful about the values you are summing (i.e. add type checking or validate the column name with hasOwnProperty).
I might be a little late, but here’s another question that reminded me that material table happen to have a footer row api.
You can use it alongside a specific method to sum values (or else) that you can call before setting the datasource for example, or on demand.
I know that firestore doesn't support full text search and it giving us solution to use third party services. However I found a simple solution to simple "full text search" and I think this might help others who doesn't want to use third party services as me for such a simple task.
I'm trying to search for company name which is saved in firestore collection under my companyName which can be in any format for example "My Awesome Company". When adding new company with companyName or updating a value in companyName I'm also saving searchName with it which is the same value as company name but in lower case without spaces
searchName: removeSpace(companyName).toLowerCase()
removeSpace is my simple custom function which remove all spaces from a text
export const removeSpace = (string) => {
return string.replace(/\s/g, '');
}
That turns our company name to myawesomecompany which is saved in searchName
Now I've got a firestore function to search for company which indexing through searchName and returning companyName. Minumum search value is a searched value without last character and maximum search value is a searched value with added "zzzzzzzzzzzzzzzzzzzzzzzz" transformed to lower case. That means if you search for My Aw then min value will be mya and max value will be myawzzzzzzzzzzzzzzzzzzzzzzz
exports.handler = ((data) => {
const searchValue = data.value.replace(/\s/g, '').toLowerCase()
const minName = searchValue.substr(0, searchName.length-1)
const maxName = searchValue + "zzzzzzzzzzzzzzzzzzzzzzzz"
let list = []
const newRef = db.collection("user").where("profile.searchName", ">=", minName).where("profile.searchName", "<=", maxName)
return newRef.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
list.push({ name: doc.data().profile.companyName})
})
return list
})
})
I didn't have time to fully test it but so far it works without any problems. Please let me know if you spot anything wrong with it. Now the question is
Is "z" character the highest value character in firestore or is there any other more decent way to add into the search value maximum amount without adding "zzzzzzzzzzzzz"?
I like your decision to preprocess the text so that it can be queried, but you could provide for a more flexible search by storing lowercase keywords with the users and searching those. In other words, transform:
"My Awesome Company"
to...
{ my: true, awesome: true, company: true }
...and test against that.
When adding/updating the property:
// save keywords on the user
let keywords = {}
companyName.split(' ').forEach(word => keywords[word.toLowerCase()] = true)
When querying:
let searchKeywords = userInputString.split(' ').map(word => word.toLowerCase())
let collection = db.collection("user")
searchKeywords.forEach(keyword => {
collection = collection.where(`keywords.${keyword}` , '==' , true);
});
With a little modification of previous answer I have made another simple text search. I'm saving keyword to an array instead of saving it in object like this
nameIndex: textIndexToArray(companyName)
where textIndexToArray is my custom function
export const textIndexToArray = (str) => {
const string = str.trim().replace(/ +(?= )/g,'')
let arr = []
for (let i = 0; i < string.trim().length; i++) {
arr.push(string.substr(0,i+1).toLowerCase());
}
return arr
}
which transfer a text into array. For example
"My Company"
will return
[m, my, my , my c, my co, my com, my comp, my compa, my compan, my company]
with nameIndex saved in firestore we can simply query the data thorough nameIndex and return companyName
exports.handler = ((data) => {
const searchValue = data.value.toLowerCase()
let list = []
const newRef = db.collection("user").where("nameIndex", "array-contains", searchValue)
return newRef.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
list.push({ name: doc.data().companyName, })
})
return list
})
})
On submitting a form with some updated values, I need to update the state to reflect these changes, but I am new to Immutable.js and am unsure how to do so.
Is it possible to pass a function as a 2nd argument to set or update to update values based on certain criteria.
I have a function which receives state and an array of objects called values. The data in values looks like this:
[
{
key: 'name',
value: 'fred'
},
{
key: 'height',
value: '201'
},
{
key: 'weight',
value: '78'
}
]
I need to map over this data, and the state list, and update the corresponding values in the state list with the values array.
How can I do this. I have put together a function which the Reducer calls to update the state with the new data, but unsure exactly how to get the end result
function updateValue(state, values = []) {
const items = state.get('items').map((i) => {
const key = i.get('key');
values.map(v => {
if (v.key === key) {
return state.update('value', v.value);
}
})
});
return state.update('items', /* Can I use a function here to replace the code above.. to update all of the items in the state List that correspond to the items in the measurements array (which have new values) */);
}
Thank you very much.
Update
Tried the following, but getting the error: Expected [K, V] tuple: i
function updateValue(state, values = []) {
const items = state.get('items').map((i) => {
const key = i.get('key');
values.map(v => {
if (v.key === key) {
return state.update('value', v.value);
}
})
});
return state.update('items', items);
}
More details on the error from Immutable:
function validateEntry(entry) {
if (entry !== Object(entry)) {
throw new TypeError('Expected [K, V] tuple: ' + entry);
}
}
You can use 'merge' to return new object:
return state.merge({
items: values,
});