Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    Removing a set of events from Timeline

    Hi. We have a timeline where admins can see scheduled users during a time period. Admins can do usual crud operations.

    A feature that has been requested is to be able, as an admin, to click on an event for a certain user and say "delete all events for this user after this event".

    Everything is finished insofar as we perform a delete operation on the event, passing an operationid to indicate whether to delete the single event, all events, or all future events for that user, depending on what the user wants to do.

    Everything works, except for the timeline itself. Naturally, only the event that was clicked on in the timeline disappears. All the other events that are now deleted (since i have done multi-delete on the server) are still showing in the timeline in the client.

    My question is: Is there a way for me to perform logic in the timeline client-side, i.e. manually remove the events, so that i don't have to re-fetch them, or is a data-reload of the timeline my only option?

    Thankful for pointers.
    Last edited by mathias; 21st Mar 2020, 12:59.

    #2
    Hi mathias,

    I assume you could either send a DSResponse with invalidateCache: true or (better) send a lot of relatedUpdates-DSResponse on your main DSResponse with operationType: "remove", affectedRows: 1, id: oneRemovedID.

    Best regards
    Blama

    Comment


      #3
      Or from the client-side, if you have all the PK values, use DataSource.updateCaches().

      Comment


        #4
        Thanks for input. Well i don't have the pk values, since there might be hundreds or more items, so for memory and performance reasons i do a "delete from schedule where repeatId = X", without returning the id of every row that was deleted.

        What i, in an optimal fantasy, would like to do is to delete items locally, according to some criteria of fields in the datasource backing the timeline, although i understand perfectly that it's a fringe use case.

        I suppose the easiest is invalidateCache() and fetchData() on the timeline in the DSCallback? That's at least what i do now, seems to work.
        Last edited by mathias; 22nd Mar 2020, 23:25.

        Comment


          #5
          Your fantasy is achievable, since Timeline.data is a ResultSet and you can just grab all the loaded rows, apply AdvancedCriteria to them to find the ones that you need to get rid of, then use the PKs from all matching records with DataSource.updateCaches().

          Or, as Blama mentioned, you can add related updates on the server side, to tell the client there has been a series of removes on the server - this is a server-side API that basically does the same thing DataSource.updateCaches() can do on the client side.

          But yes, invalidateCache() is an easy one-liner to achieve the same thing slightly less efficiently. You should find that just calling invalidateCache() does the job, without the need for a fetchData() call, since the fetch will be automatic if the Timeline is still visible - it will fetch in order to have events to display for the current range.

          Comment


            #6
            Hi mathias,

            for my suggestion: Do a fetch with outputs="PKField" before your delete with the same criteria, then use this data to build the related updates - only two SQL needed then.

            If you go for the invalidateCache, then I think that you only need to set it on the response and the client will issue the fetch automatically - no need for a CallBack.

            Best regards
            Blama

            Comment


              #7
              Hi, thanks for great responses! I went with Isomorphics suggestion, since i want to avoid any extra calls to the server if i can avoid it.

              I have it working already, but i have a question.

              I actually have two components showing the same datasource, although they might show slightly different data sets. I have solved it with GWT eventbinders, i.e. both the timeline and my listgrid listen for "delete" events. If one of the components do a delete, they will both get an event, and clean up the data when an ok response comes from the server.

              However, is there any synchronization risk if they both do the "advancedcriteria" and updatecaches on the datasource? To simplify things, the timeline might have records 1,2,5,7 and the grid records 2,5,7,10,12. What happens if they both call updateCaches at around the same time and where some of the records are the same?

              This is a typical race condition risk if there is no way to synchronize, if you see what i mean. As you can see, i'm not super read up on how the excecution thread environment actually work in the browser... :)

              Comment


                #8
                We're not sure how there could be a "race condition", that's normally reserved for asynchronous actions. You just use DataSource.updateCaches() and the items will be removed from both caches. If you want the caches treated separately (only remove from one), just given them different operationIds (see ResultSet docs about cache sync).

                The only "race condition" we can imagine here is if you trigger a fetch for new records, then while that fetch is outstanding, you start issuing updateCaches() requests. Those would do nothing - you'd just get whatever came back from the fetch. But presumably that's already correct if deletion has occurred?

                Comment


                  #9
                  Yes i hear you. However, in my example, i would need to update caches twice: The timeline only has events 1,2,5,7, and the grid has loaded 2,5,7,12. This means that item 1 only exists in the timeline, and item 12 only exists in the grid - but i want all of them removed in the client. Therefor, i must call updatecaches from both widgets. So i was wondering if there was a problem with the timeline and grid both calling updatecaches with *almost* the same data at basically the same time. If it's not, great!

                  Comment


                    #10
                    Hi mathias,

                    to clarify, the relatedUpdate solution also only requires 1 request:
                    • Client Request operationId: "removeAllEventsOfThisSeries", data: {seriesId: 17}
                    • Server: SELECT id FROM events WHERE seriesId=17
                    • Server: DELETE FROM events WHERE seriesId=17
                    • Server: Build relatedUpdate from SELECT
                    • Server: Send relatedUpdates with DSResponse
                    • Client: Automatically do updateCaches() and remove events wherever appropriate
                    Best regards
                    Blama

                    Comment


                      #11
                      Gotcha. Still, have to fetch and return all those ids. But would work great too.

                      Comment


                        #12
                        There’s no need to call updateCaches() from both widgets as it’s a global action.

                        Theres no race condition because it’s synchronous.

                        Comment


                          #13
                          Good to hear it synchronous, but excuse me if i go through the "two components" thing again.

                          The usecase is that i'm deleting a "series" of events. They can be displayed both in a timeline and a grid. These series can span several months, and depending on what the user does, the grid and the timeline might be in a state where they don't show every event in the series, and maybe slighty different parts of the total set.

                          So, the timeline contains 1,2,5,7 in the series
                          the grid contains 5,7,12,18 in the same series, i.e. some similar, but some not. More specifically ID 12 and 18 are in the grid, but not in the timeline.

                          The code i run in the client on a successful response from server is this:
                          Code:
                          AdvancedCriteria crit = new AdvancedCriteria(ClientServerConstants.FIELD_SERIES_ID, OperatorId.EQUALS, event.sRepId);
                          Record[] all = findAll(crit);
                          DSResponse resp = new DSResponse();
                          resp.setOperationType(DSOperationType.REMOVE);
                          resp.setData(all);
                          getDataSource().updateCaches(resp);
                          Now, the problem is that the findall() on the timeline will return 1,2,5,7 but NOT items 12,18 that only are shown in the grid, so they will remain in the grid even though they do not exist on the server anymore. It would have been great if i could somehow use the AdvancedCriteria directly on the datasource, but since that's not the case, I need to do the same excercise above for the list grid aswell, in order to also get rid of items 12 and 18 from the grid in my example above.

                          I hope this makes sense and please let me know if i have misunderstood something.

                          Comment


                            #14
                            You can use AdvancedCriteria on the DataSource to get all matching IDs, that’s just fetchData(). It’s just that that will require a server trip since the DataSource doesn’t have a cache of the data, only components do (unless you set ds.cacheAllData to true).

                            About calling it from both widgets: if there are disjoint cached records across the two widgets, you will need to call updateCaches() for the whole set. But you need only call it once per unique ID - that will remove the matching record from both widget’s caches.

                            Comment


                              #15
                              Hey, thanks for quick response. Your response tells me that i am, for me, doing the right thing, since this whole excercise is about avoiding that extra server trip.

                              Yeah, i understand that updateCaches(), but is it a problem that one of the components might call updatecaches with id's that just was deleted by the other?

                              Since i'm using the GWT eventbus to broadcast to the timeline and grid that they need to delete the elements, they don't know about what the other has deleted. They'll just get their respective sets out from each component and call updatecaches from both, even if some id's are the same.

                              Comment

                              Working...
                              X