How to return column that will be sorted by number within component in React Table? - reactjs

I am creating a table with React Table library and I don't know how to format returning number for cells and to have working sorting by numbers. When I return something different that number sorting is no longer working as expected It works by alphabetical order not by numerical.
One of columns:
{
Header: "Ocena",
accessor: row => {
const votes = row["usersVote"].reduce(
(acc, r) => acc + (r.vote === "up" ? 1 : -1),
0
);
return (
votes > 0 && (
<StyledVote color="rgb(48, 131, 115)">
+{Number(votes)}
</StyledVote>
)
);
return votes;
},
When I comment out returning of component and leave only return: votes sorting is working properly. How to return a component and have fully working sorting by numerical order?

Ok, I found an answer.
accessor function is calling before data is moved to the table and in that place we should prepare our data to be sortable (in my case I need numbers):
accessor: row => +row['usersVote']
And later when we want to render that data in other way we need to call Cell function
Cell: row => <NumberComponent row={row} />
And do whatever you want to do with that data
Source: https://react-table.tanstack.com/docs/api/useTable#column-options

Related

Google App Script: Dynamically add new rows in Google Sheets

I'm working on a sheet to build a list of products to import into Shopify.
For this, I have a pdf of some basic data (that is irrelevant here) out of which I build a string to crawl the product supplier's website and format the data in a way suitable for import in Shopify.
The products have a varying number of images (1 - 8), so I'm trying to build my script in a way that if a product has more than one image, I am trying to add additional rows under it and add every image past the first into a new row.
Here is my code:
function iterateThroughRows() {
// get spreadsheet
const sheet = SpreadsheetApp.getActive().getSheetByName("MySheet");
const data = sheet.getDataRange().getValues();
// Loop over rows
data.forEach( (row, rowIndex) => {
const imageSrcArray = [ /* list of image URLs, fetched from remote server */ ]
imageSrcArray.forEach( (img, arrayIndex) => {
if(arrayIndex == 0) { // for the first array item, just add it to the current row
const imageCell = sheet.getRange(rowIndex + 1, 24)
imageCell.setValue( imageSrcArray[arrayIndex] )
} else { // for each array item past the first one, add a new row and enter the value there
sheet.insertRows(rowIndex)
const imageCell = sheet.getRange(rowIndex + arrayIndex + 1, 24)
imageCell.setValue( imageSrcArray[arrayIndex] )
}
})
// adding some more values to other cells
});
}
As is this doesn't really work.
I worked on this all day yesterday and had a version using insertRowAfter() that did add additional rows, but added them all lumped together (i.e. there would be 15 rows after the first product, but none after any of the others). But since Google App Script doesn't have version control I lost that version.
I think the problem was that the forEach seems to move on to the newly created rows and keeps adding things from there rather than moving on to the initial next row.
So I'm more or less at the end of my wit with this. Any advise on how to properly do this would be highly appreciated.
I can understand your frustration, it is indeed because you care calculating the row based on the sheet in its version before you added new rows to it.
So my proposal would be to do this, as the currentRow allows you to track the current row you are working on. I also updated the insertRowAfter(), as I assume this is what you actually wanted to do.
let currentRow = 1;
data.forEach( (row, rowIndex) => {
const imageSrcArray = [ "img1URL", "img2URL"]
if( !imageSrcArray.length ) return
imageSrcArray.forEach( (img, arrayIndex) => {
if( arrayIndex == 0 ){
sheet.getRange(currentRow, 24).setValue( img )
} else {
sheet.insertRowAfter(currentRow)
sheet.getRange(currentRow+1, 24).setValue( img )
}
// New rows in between were created
currentRow++
})
});

Adding a custom "ALL" (Total) row to the top of an ag-grid that is selectable like any other row

I have an ag-grid table with 2 columns - one text and one number.
I need to add a custom row to the top of my ag-grid table with the total value of the number column and the word "ALL" in the text column.
This needs to be on the top. And should not change its position even if the table is sorted.
Also, the row should be selectable.
Any help in this regard will be highly appreciated!
Sounds like you are describing Row Pinning which is already a feature in AG Grid. However, since you've also stated that row selection is a requirement, this will not be possible with Row Pinning as it's not supported.
Instead what I'd recommend is adding an extra row object inside the rowData for the custom row, and handling the update of the number column and the custom row position yourself when necessary:
If you want to handle the total value of the number column then you can use the following logic:
function updateTotalRowNode() {
let totalRowNode;
let sum = 0;
gridOptions.api.forEachNode((node) => {
if (node.data.totalRow) {
totalRowNode = node;
} else {
sum += node.data.gold;
}
});
totalRowNode.setDataValue('gold', sum);
}
If you want to keep the custom row always on the top row then you can implement the postSort callback:
postSort: (rowNodes) => {
// here we put All row on top while preserving the sort order
let nextInsertPos = 0;
for (let i = 0; i < rowNodes.length; i++) {
const athlete = rowNodes[i].data.athlete;
if (athlete === 'All') {
rowNodes.splice(nextInsertPos, 0, rowNodes.splice(i, 1)[0]);
nextInsertPos++;
}
}
},
See the following plunker for the implementation.

How to change value in the select option of an array in the Yii2 view?

I use Yii2 Framework and I have this array filter for the 'Ordine' column:
[
'attribute' => 'Ordine',
'filterType' => GridView::FILTER_SELECT2,
'filter' => ArrayHelper::map($ordine_nome,'id','ordine'),
'filterWidgetOptions'=>['pluginOptions'=>['allowClear'=>true]],
'filterInputOptions'=>['placeholder'=>'Tutti...'],
'label' => "Ordine",
'width' => '2%',
],
Now, the array is built in this manner:
$ordini=Elenchi::find()->asArray()->orderby(['Ordine' => SORT_ASC])->all();
foreach($ordini as $l){
$ordine_nome[] = ['id'=>$l['Ordine'],'ordine'=>$l['Ordine']];
}
It's all ok. But now I want to change the value in the array select option. For example, if the value is 'OFMCap', in the array selection I want to show 'OFMCap - Ordo fratrum minorum capuccinorum'. At the moment the various selection shows only the acronim (for example OFMCap, etc....)
Anyone can help me to build this type of search?
Thank you very much, I hope to be clear.
You have mapped the same column for id and description
assuming your Elenchi models contains at least two column ordine and description
with values :
ordine description
----- -----------
OFMCap, Ordo fratrum minorum capuccinorum
so the find() return the collection of (at least) these two values
$ordini=Elenchi::find()->asArray()->orderby(['Ordine' => SORT_ASC])->all();
then you should prepare you array as
foreach($ordini as $l){
$ordine_nome[] = ['id'=>$l['ordine'],'description'=>$l['description']];
}
and you map as
'filter' => ArrayHelper::map($ordine_nome,'id','description'),
I have use lower case name for db attribure .. so manage/adapted teh case to your needs
But if you need map directly .you can wrok on array result for map()
$myMap = ArrayHelper::map($ordine_nome,'id','description'),
$myMap['OFMCap'] = 'OFMCap - Ordo fratrum minorum capuccinorum';
'filter' => $myMap,

Why is removing an item from a list with the key as index working as expected?

I have a component in which you can add or remove an option item. When I remove an option item, it is simply removed from an options list stored in state using the index value.
I would have thought that because I am using an index as the key, whenever I deleted an option item, the last element would incorrectly be removed however it seems to be working as expected.
displayedOptions = options.map((option, optionIndex) => (
<DropdownOption
option={option}
onRemoveOption={() => onRemoveOption(optionIndex)}
onChange={onChangeOption(optionIndex)}
key={optionIndex}
/>
));
const onRemoveOption = (taskIndex: number) => (optionIndex: number) => {
const newTaskFields = [...taskFields];
newTaskFields[taskIndex].options = newTaskFields[taskIndex].options.filter(
(_option, index) => {
return optionIndex !== index;
}
);
setTaskFields(newTaskFields);
};
Are there any risks to doing it this way?
Would anyone know why this is working as expected?
I thought the behaviour in my app would have been similar to what was reported here: React - Deleting from middle of list removes last element instead
That is, if I had an list that used indexes as keys containing the following values:
[a, b, c]
and I removed index 0 ('a'), I thought the diff would have been between:
Original:
[0:a, 1:b, 2:c]
and
Updated:
[0:b, 1:c]
In this case, React would see that keys 0 and 1 still exist and would continue to render a and b as it would assume these haven't changed. This would result in c disappearing (not a).
Thank you.
Your onRemoveOption is partially correct. You should shallowly copy all elements of the array/object you intend to update (mutate/remove/etc...).
Your onRemoveOption handler would then become something like:
const onRemoveOption = (taskIndex: number) => (optionIndex: number) => {
setTaskFields((tasks) =>
tasks.map((task, index) =>
index === taskIndex
? {
...task,
options: task.options.filter((_, index) => index !== optionIndex)
}
: task
)
);
};
Uses a functional state update
Maps the tasks to a new array object
If the task index matches the one you need to delete an option from, shallow copy to new object and update the options property, otherwise return the task object
If deleting an option, filter the options by index
Issue will raise while implementing sorting and Removing based on map index.
for example
let Options = [d,a,e,y];
right now Options and index looks like this way.
d 0
a 1
e 2
y 3
Removing item always apply changes from last item. Because you are not passing unique key to the item. Read diff algorithm.
But if you implement sorting and removing - it will failed in removing specific element
after sorting index will change
a 0
d 1
e 2
y 3
You can send option name instead of index.

Laravel 5.5 - Updating a pivot table with a custom field given two input arrays

I have 2 input arrays, one for ingredients and one for the amount of the ingredient that is required for an associated recipe. My pivot table has four columns - id, recipe_id, ingredient_id and amount. I want to use the sync method to update the pivot table, however I can't work out how I would go about passing the second 'amounts' array values and ensuring they are synced with the correct record?
$ingredients = $request->ingredients;
$ingredientAmounts = $request->ingredients_amount;
$project->ingredients()->sync( $ingredients => ['amount' => $ingredientAmounts] );
The ingredient and its amount will both have the same key so I guess I could loop through them manually and update the pivot table, but I feel like there will be a simpler way which will make better use of eloquent.
The two input arrays need to be merged to be in the format required:
$user->roles()->sync([1 => ['expires' => true], 2, 3]);
From https://laravel.com/docs/5.5/eloquent-relationships#updating-many-to-many-relationships
$array = [];
foreach ($ingredients as $key => $ingredient) {
$array[$ingredient->id] = ['amount' => $ingredientAmounts[$key]];
}
$project->ingredients()->sync($array);

Resources