Hello,
I need help with the following scenario:
I bind an igGrid to OData and use SignalR to get information about data changes.
I want to reflect those changes in the grid.
I tried Knockout but there are two problems. First, I cannot bind an igGrid with Knockout extensions to OData. Second, even if I fill an ObservableArray with JSON data manually, it is very slow when it reaches 1000 records.
I tried using "setCellValue" of igGridUpdating, but also two problems: First, the grid looses its selection when calling "setCellValue". (It should not have any impact on what the user is doing.) Second, it creates a transaction with is not nesseccary.
I tried changing the data in the data source (no OData for the test) and called "dataBind" - worse - selection, filter, sorting gets lost.
For my question, imagine the following example:
- A grid bound to OData: Id, Description, Value
JavaScript gets notified with a change:
- Id = 10, Value = 100
What I want to achieve:
- Lookup the record with Id = 10 in the DataSource and / or Grid, change its value to 100 and reflect this value in the visible grid, without affecting what the user has done or is doing with the grid - like selection(s), sorting.
I was thinking of implementing a custom DataSource but I have not found a way to tell the grid "the row with Id = 10 has changes - get its new values and update the DOM".
Any idea?
Btw, the same scenario should be quite common: Display some properties from the OData source in the grid (using $select), an Edit button opens a Dialog, fetches the complete object, the user edits the data, saves it to the data store... and then the grid should reflect the changes that the user just performed in the dialog.
Best regards,
Peter
Hello Peter,
You seem to have already tried a few different approaches and I'll try to go over them and possibly help you with implementing the most appropriate one.
First of all, I should say that if you simply obtain a new version of the OData data source on regular intervals, calling dataBind is the most straightforward and efficient method. Its downside is, as you observed, losing the sorting and filtering states. Those, however, can be stored and then restored using Grid's API. What's more, the ability to restore these states automatically is very high in priority on our backlog and we are looking to deliver this functionality as early as the 14.1 release. A sample of how to restore them manually is the following:
var grid = $("#grid1"), ds = $("#grid1").data("igGrid").dataSource, filtering = ds.settings.filtering.expressions; ds.dataBind(); grid.igGridFiltering("filter", filtering, true); grid.igGridSorting("sortMultiple");
Similarly you can restore the selection and scroll position (the latter achievable directly through the scrollTop() jQuery method). Please let me know if you need help with that!
Using Updating's API to apply the changes without data binding would be more efficient if you receive the differences between two subsequent calls directly and not having to find them by slow comparison methods. On a separate note, I couldn't reproduce the issue you described with setCellValue removing your Selection state. Could you please share which version of Ignite UI you are using?
Finally, to remove the unnecessary transaction log entry, you can follow the setCellValue call with a pop() call on the allTransacations array which is obtainable through Grid's API:
$("#grid1").igGridUpdating("setCellValue", <row id>, <column key>, 'some value');$("#grid1").igGrid("allTransactions").pop();
I hope this helps! I am looking forward to hearing from you!
Stamen Stoychev
Hello Stamen,
without actually trying it - but wouldn't your workaround
ds.dataBind(); grid.igGridFiltering("filter", filtering, true); grid.igGridSorting("sortMultiple");
produce two or three calls to the OData source? (One with each method call above)
Anyway, calling dataBind() is too slow and too performance expensive if I only want to update a single row and already have the data available.
I'll try the Updating API again and I will let you know when and how the grid lost selection.
I am wondering if the source of Ignite UI is available after purchasing the subscription? (I mean the source that is not minified and hopefully with some comments. The product description is not quite clear if C# source and / or JavaScript source is included.) At the end, I might implement my own data source and I could not find documentation - the Ignite UI source would help in those cases and when debugging. I also noticed that the RESTDataSource only produces PUT and does not support PATCH and MERGE updates on OData. So I might need to extend it as well and would like to look at the RESTDataSource source code.
The code snippet in question assumes your grid's Sorting and Filtering are configured to be local (and therefore they can't produce any remote calls). If your OData endpoint supports filtering and sorting you could also set the grid to sort and filter remotely. By default an igGrid bound to a remote URL will use OData compliant URI parameters and setting this up could be as simple as configuring the grid's features like this:
$("#grid").igGrid({
...
features: [ { name: "Sorting", type: "remote" }, { name: "Filtering", type: "remote" } ]
});
Data binding in this case (if done directly on the DataSource object like shown in my first post) will not clear the filter and sort states and will make the ajax call with them intact, which should solve your issue with state persistence for at least these two features.
This, however, will work if you bind the grid directly to the OData service.
As for your other question - yes, purchasing a license will provide you with the C# and JS source code for the product.
The RESTDataSource is an extension to the RemoteDataSource which alters the saveChanges routine to provide REST-compliant updating (PUT, POST and DELETE verbs). With the source code you should be able to extend it to support PATCH/MERGE as well. You could also submit a feature request to add this functionality in future releases. We base our development almost entirely on user feedback.
Please, let me know if you have any other questions and/or issues you need help with!
thanks for your help!
I followed your suggestions:
- Binding to OData directly does indeed keep filtering and sorting when calling dataBind().
- I implemented restoring the current scroll position according to these forum thread:
http://es.infragistics.com/community/forums/p/69132/386278.aspx#386278
It does work - but not with virtualization.
At the end, calling dataBind() is too slow if only a single row has changed.
So I implemented igGridUpdating('updateRow', ...), with the following observations:
- Without virtualization selection does work nicely.
- With virtualization and mode = 'fixed', the grid loses selection. If the updated row and the selection is visible, it does seem to work, but it does not. Turn on checkboxes in Row Selector and select another row after the update: The row is rendered selected but checkbox is cleared. Might be a bug.
- With virtualization and mode = 'continuous', the grid does not lose selection. It seems to be ok.
- If a row is not visible due to paging a call to igGridUpdating('updateRow', ...) raises a script error.
Result:
Without virtualization it does work but it is slow with many rows.
With virtualization and mode = 'continuous', it seems to work.
Can you confirm this behavior?
Are my observations the intended behavior in 'fixed' mode or it is a bug?
Is it ok that a call to igGridUpdating('updateRow', ...) with a row ID that is not loaded due to paging raises an error? Bug? What would be the workaround?
(Virtualization with "continous" mode seems to have a couple of problems with multiple row selections and rendering. I will post it on another thread.)
I can't reproduce the issue you are experiencing with fixed virtualization. Which version of Ignite UI are you using?
Version: Infragistics.Web.ClientUI Grid 13.2.20132.1010
To reproduce:
Grid:
features: [ { name: 'Paging', pageSize: 500, showPageSizeDropDown: false }, { name: 'Sorting', applySortedColumnCss: false, featureChooserSortAsc: 'Sort A to Z' }, { name: 'RowSelectors', enableCheckBoxes: true, enableRowNumbering: false}, { name: 'Selection', multipleSelection: true }, { name: 'Updating' }],
bound to OData with RESTDataSource
I have a button that updates the first row:
$('#grid1').igGridUpdating('updateRow', 1, { Name: 'Test 1' });
Steps:
- Scroll down one page
- Select a couple of rows
- Click the button that updates the row that is not visible
- The grid renders and it looks ok
- Select a different row
- The grid looks like the attached screenshot
I've been trying to reproduce this exact fixed virtualization issue you are seeing but with no avail. I do believe I managed to get the important parts of your scenario based on your steps to reproduce, screenshot and feature options, however, there is probably something small I am missing and because of that I'll ask you to provide a small sample that is reproducing it on your side with the steps described which I can take a look at. Thanks in advance!
Hello Peter,Sorry for the late reply! I did notice that selection will persist through paging when virtualization is enabled incorrectly and it does look somewhat similar to the screenshot you provided, however, I wasn't sure you actually switch between pages to reproduce it. In any case I logged the issue I noticed with a Development ID of 160027. It will get resolved with the next service release.About the previous points you raised -
Restoring the scroll position should be fairly straightforward with the updated "virtualScrollTo" grid method. For fixed virtualization you can store and pass it the index of the topmost rendered row. For continuous you should store the scrollTop position of the scroll container:
var a = $("#grid1_scrollContainer").scrollTop();
And then apply it with:
$("#grid1").igGrid("virtualScrollTo", a + "px");
The exception from calling updateRow on a row being out of view due to paging or filtering is a regression which has already been fixed and the fix will be available with the next service release. Until then you could check if the row you wish to update is rendered and if not - call the corresponding data source function directly. The update will then be available the next time the row comes into view. The solution might look similar to the following:
if ($("#grid1").find("tr[data-id='" + rowID + "']").length > 0) { // row can be updated directly ...} else { $("#grid1").data("igGrid").dataSource.updateRow(rowID, rowObject, true);}
I hope this helps! Please, let me know if you have any other questions and/or concerns!
can you post your sample that you used to reproduce the problem?
I will look into it and match it to my code.
(My sample page is part of a Durandal app, uses TypeScript and a none-public OData source which makes it difficult to send it to you.)
If I cannot reproduce it with your sample, I will produce a new sample myself.