In my app I import a JSON file and then display it in a table. The table has 3 columns.
Two issues with this:
The table also has sorting and CRUD operations, so using the array index for the row key is not best practice.
Similar with above, I am trying to implement the functionality to edit a row, and doing so by index is finicky because they may have shifted from sorting or CRUD.
I came up with some potential solutions, but they all seem weak:
Uniquely identify a row by a combination of its visible columns. This has problems because while it's extremely unlikely there will be duplicate rows for this data set, I suppose it's possible.
Uniquely identify a row by fields that are relatively guaranteed to be unique. For example, each row has a creation date, and since all rows are generated manually in the program, I believe this could function as an ID for uniquely identifying rows? It kinda feels like identifying a row by a date is bad for some reason though.. Not sure.
Uniquely identify a row by a combination of all its fields (visible and hidden). May be slow or needlessly complex?
Upon row creation, assign an ID to the row that isn't shown to the user and is persisted in the saved file. Would also probably need to have a global counter variable saved (because if a row is deleted we wouldn't want to re-use that ID and we need to know where we left off from).
Assign a GUID to each row? Wouldn't need to store an index counter but more space would be required (although the files are relatively small so I'm not sure how much this matters).
Are there any other or better ways that I'm missing? How is this normally handled?
I'd go with 4 or 5, but with a minor change:
You can keep the JSON as is. Upon importing the JSON, you map each item and assign them an ID or GUID - I'd use ID for simplicity, but it's up to you. Within the execution of your program, this field will be used to the CRUD operations and/or sorting.
When your program is done, map again your data, and save back in the same format you've received (removing the new prop you've added).
Related
I've been recently studying the importance of elements' keys in React and I'm still a little confused about it.
I have this case where there is datagrid component responsible for presenting data in rows. There is implemented sorting, filtering and pagination. I fetch the rows data from api.
And the question is:
How should I properly choose keys for map function elements (rows)?
The thing is that the already fetched row data can change between refreshes (by being edited by other user).
Should I use unique ids for key properties (for instance nanoid) or use row.id?
If I understand it correctly, using row.id would result in no row rerendering for already loaded rows even if some of row data were changed.
On the other hand, using unique ids (like nanoid) would make negative impact on performance while sorting, filtering etc...?
Do I get this right, and how to do this properly then?
I agree to study the key in more details. Here's my understanding.
If I understand it correctly, using row.id would result in no row rerendering for already loaded rows even if some of row data were changed.
This is not true, the purpose of the key is to identify the item location, so when it comes to the reconciliation (convert element into a node), React knows if a node (fiber) can be reused to speed up the update process.
Let's make an example, if initially the the key order is
1 2 3
And somehow after a re-order, it becomes the following in the new update
2 1 3
Then React is guided to use the node with key 1 to update the item. The item is updated, and in this case, to the right place. BTW, React doesn't know by default the order of items, to React, they look all similar ;)
I'm only giving you a basic case. But you can make a guess for other cases, ex. with one key missing, or a new key added.
Keys should always be unique, stable (as mentioned above by Brian), and never manipulated in your code (hence stable).
A unique ID is preferred. I've seen people pass an entire user object as the key. Let along that there might be duplicate users, this could also be an enormous key.
Do not use the index of any array as your key.
I've created a database-driven hierarchy table with 3 hierarchy levels. It works almost exactly how I want it to, but the javascript code that drives its functionality is UGLY. I would like to re-write some of it, but I don't quite know how. I imagine I'll have to use recursive functions, but there are some strange business rules that may make it more difficult than I imagined. Can you make any suggestions to simplify my current code (in particular, the ActivateRow() function)? See fiddle.
Note that there is some funky use of hidden fields due to ASP.NET Web Forms postbacks and losing input values, but there are some useful data-attributes written into the HTML such as data-region-id, data-subregion-id, data-market-id, and data-hierarchy-id. the main requirements are below:
There are two tables - the first is linked to the second, so all actions on the first table should be carried out on the second table as well (though the second table is slightly different).
Three levels of hierarchy. The highest level (Region), a middle level (Sub Region), and a final level (Market)
Row activation enables all controls in a given row. If the activated row is a Sub Region row, it deactivates its parent Region row controls and its sales values sum up to the Region level. This does not apply to activating a Market row.
Similarly, row deactivation should disable and clear all controls within that row. If the row is a parent row, it should clear all children rows and disable their controls as well.
Deactivating all children of a parent row should deactivate the parent row and clear all parent row controls.
Surely, there's a better alternative. Am I reinventing the wheel? Is there anything out there that I could use to improve my spaghetti code? I realize this isn't the best question for Q&A format - is there somewhere else I should ask my question?
It is not entirely clear what you are doing but from what I gather you have some kind of table you are filtering.
Also, you are using ASP.NET webforms.... so sorry for you.
I would not use any kind of form binding controls offered by ASP WebForms, because it is now obsolete, incorrect and very painful.
Instead, create an AJAX enabled page [WebMethod] that returns all the data or filtered with a parameter, what ever, in JSON (Because JSON is easier to read and debug, and much faster than XML)
Go and find the jQuery plugin DataTables. Everykind of functionality is built in and extentable, it works great, super efficient client side, with varios filtering and searching capabilities.
You either create a new model on the Server side and remap the data server side, or dump your existing model and remap it on the client, either way, you just plug JSON data into datatables.
Saving back to webforms is slightly more tricky (compared to MVC/Razor) because you have to take the String and deserialise it to your model, its a few extra lines but I do this all the time and you can carry on with your business logic.
How to hide specific rows in Handsontable.
I have buttons in DOM, each of them should hide specific rows.
For example: click button with class `alarm' should shide all rows which second column has value 'alarm'.
For now i do ugly thing. Every button click i loop overy my tableData and delete datas with 'alarm' then just load data and render table. But i can't do that becouse i have some dynamic datas so after render their disapear.
eveGrid.loadData(tableData);
eveGrid.render();
Dynamically hiding rows is quite a complex task which is not documented in the Handosntable documentation. However, there is plenty of functionality available to implement it ourselves. As a matter of fact, I had to do this just last week so I can share with you a potential approach. It's really quite simple and similar to your solution, which is not ugly by the way!
What you want to do is keep two copies of your data. The first we can call data, and the second activeData. Initially, they both equal each other. Now this part is tricky and not easy to grasp but what you have to make sure is that these two arrays are DIFFERENT OBJECTS, but have the SAME REFERENCED ELEMENTS. What this means is that the arrays themselves are not clones, so an equality test would fail. However, their elements are clones. Your activeData elements are just references to the elements on data.
Once we have this set up, it's simple to implement the hiding of rows. Your click should look through data and set a new activeData based on the matching rows you want to display. Then just update handsontable with something like:
hotInstance.updateSettings({data: activeData});
And that's it! Note that that updating method will automatically trigger a render().
Let me know how it goes, I'm curious to see if other people can use this approach.
Is there a way to bypass the necessity for an ID column? My goal is to display 100,000+ results dynamically. Currently, the only way I have found to do this is to create an "id" column on the table and then loop through it (which is quite costly). If this is the case, is there a more efficient way of doing this? How can I hide the column when the grid is displayed?
Since the usage of a dataview is causing the unique id requirement, then using a simple array as your data would suffice in removing the restriction.
If the advanced functionality of a dataview is required then you have the option of providing a field/property within the setItems call that will provide/override the id field (the field must be present within each data object and have uniqueness across all the data elements). If you cannot guarantee those two conditions, only two options are left.
customize the source code of the dataview to provide a UUID during the processing of updateIdxById
manually iterate the data and inject a UUID (what you are currently doing)
Regarding the column displaying:
Only those fields for which you have provided a column definition are rendered within the grid. Thus, as long as you don't provide the field in a column definition it will not be rendered. You can see in this example that each data object contains an id property but none of the elements of the columns array has a field that points to that property, as such it does not appear as a column.
Maybe this information is out there and my Google-fu is failing me, however I can't seem to find the answer. How can I get the number of rows being currently displayed in a jqGrid?
Every question and answer I've found on this topic tells you how to get either the total number of rows (displayed or not) or the number of rows loaded by an external service. Instead, I'm trying to get how many rows are being displayed in the current page of the jqGrid. One of my jqGrid attributes is rowList:[10,20,30], but I'm not sure how to access which one is selected myself.
All I want is how many rows are being currently dislpayed on each page of the jqGrid. The closest thing I've found so far has been this Q&A, but this displayed how many <tr>s there are and wasn't really what I needed.
$('.ui-pg-selbox').val()
Tested on the latest jqGrid (4.4.1)
Of course, if you have more than jqGrid per page, you can use an wrapper to ensure that it is the one you're looking for.
$('#myjqGridWrapper .ui-pg-selbox').val()
Not sure whether it's the best way, but it gets the job done.
The space means a descendant selector, that is it looks for elements containing the class ui-pg-selbox which are descendant of an wrapper #myjqGridWrapper. That would require having a div or some other wrapper around your table.
UPDATE: Also, if you have the table ID or a reference, you can use a more sturdy way of querying its jqGrid instance's .ui-pg-selbox:
$('#jqgridTableId').closest('.ui-jqgrid').find('.ui-pg-selbox').val()
The following will return you the number of displayed rows on a grid's page:
$('#myjqGridWrapper').getGridParam('reccount');
You shouldn't rely on the view for information. You should pull this information out of the JQGrid model. You can do so by calling the getGridParam method like so:
var rowNum = jqGrid.getGridParam('rowNum');
See here for more information: http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options