5 Replies Latest reply on Dec 16, 2015 5:21 PM by ckulak RSS
    ckulak Apprentice

    Refreshing the Repeater only if the data actually changed

    Hello ThingWorx wizards,

     

    In my mashup I execute a service every ten seconds, and then use the returned InfoTable to render a Repeater. The data changes are rare, so in 90% of the cases the returned InfoTable is the same.

     

    My problem is that the repeater gets visibly re-rendered every time the service returns, even if the data didn't actually change. Is there any reasonably elegant way to avoid refreshing the Repeater in this case?

     

    / Constantine

      • Re: Refreshing the Repeater only if the data actually changed
        aanjan Heavyweight Champ

        Constantine, I don't believe there is a way to actually stop the repeater from refreshing, as it is simply rendering your Mashup. What is your ItemLoadBehavior set to? You can stop the repeater from re-renedering your rows if you set it to Load/ No Unload.

         

        A quick band-aid would be to uncheck 'ShowDataLoading'. That would stop the repeater from displaying the loading bar, hence giving the effect of 'not refreshing every couple seconds'

        • Re: Refreshing the Repeater only if the data actually changed
          carlesc Ninja

          Why don't you create a service which checks if there's updates or not, if there isn't any update don't call the real pick data service.

          • Re: Refreshing the Repeater only if the data actually changed
            vladimirros Creator

            I would say the best way to do this, right now, would be the following (pasted from an older blog of mine):

            Edit

             

            Most of the time when we want to see new data in a Mashup we use the familiar AutoRefresh widget, set with a interval not too high or low, so it makes the page feel responsive but also not generating lots of traffic.

            Also, there are some problems if you trigger services which take some time in order to execute.

            This can be mitigated in a simple way, if the architecture allows it, with a simple workaround, involving the use of a DirtyFlag:

            Presumption: you have a mashup with a service called Query.... which supplies information for a grid or map.

            1. Create a property called DirtyFlag, located anywhere you want

            2. Add a GetProperty service which gets the value of the DirtyFlag in the mashup.

            3. In your mashup, add a Validator, configure an Input Parameter called "DirtyFlag", and type boolean. In the expression write "DirtyFlag == true". Check the AutoEvaluate checkbox.

            4. Set/bind the Validator input parameter value to the value of the DirtyFlag property from the GetProperty service.

            5. Bind the Autorefresh event to the GetProperties service.

            Explanation: untill now, we make sure that the True event of the validator fires each time when the DirtyFlag property is set to true.

            6. Bind the True event of the Validator to the Query type services

            7. Create a new service (located anywhere you want) that sets the DirtyFlag property to true. Let's call this service "ResetDirtyFlag"

            8. Add the new Service in the mashup

            9. Bind the ServiceInvokeCompleted event of the Query service to the ResetDirtyFlag service

            10.Done? Not quite yet!

            11. Now you must make sure you also set the DirtyFlag property (we still didn't do that yet). Ideally you should do this where you add/update rows to that datatable/stream/infotable etc.

            12. Now it's done

            So, we have now lots of requests only for small amounts of data (the GetProperties), and only when we see lots of data.

            • Re: Refreshing the Repeater only if the data actually changed
              alessiomar Explorer

              Constantine,

               

              It would be best if you could avoid transferring data 90% of the times if you don't need it; however, this might not be possible in case it's a third party service that doesn't provide caching or boolean state change information.

              In this case you should write a proxy thing implementing a service (e.g. Query) that calls the remote service, persists the data locally only if it has changed (LocalData property), and sets a boolean property to true if the data has changed.

               

              At this point you implement an HasChanged service in the proxy (that returns the value of the boolean property) as well as a GetData service to read the local copy of the data.

               

              On the mashup side, you do the following:

              1. Bind the Autorefresh widget to the Query service. Every 10 seconds or so it will call the remote service and set a boolean property if data has changed, in which case it will also persist the data locally for GetData to use.
              2. Bind GetData to a Validator, like Vlad mentioned
              3. Bind the True event of the Validator to the call of the GetData service

               

              Core to this approach is the use of a Validator that acts like a diode: if the boolean property is true, then the validator fires its True event, which calls the GetData service; if the boolean property is false, then the Validator does nothing: the GetData service is not called, and the widget is not refreshed.

               

              HTH,

              Alessio

              • Re: Refreshing the Repeater only if the data actually changed
                ckulak Apprentice

                Hello Gentlemen,

                 

                Thank you all for good suggestions! All of that definitely makes sense.

                 

                My situation was a bit exotic:

                 

                1. My "GetData" service is very light and returns just a small InfoTable, so it wasn't really necessary to optimize it from the performance point of view. What I wanted to do is avoid refreshing the UI component, which basically misbehaved on refresh;
                2. To be honest, our mashup is already far too complicated, so I was looking for the "smallest" solution, aiming at minimizing the number of services/bindings in a mashup and avoiding creating additional services on the server side;
                3. I believe that "HasChanged" / "DirtyFlag" solution is a bit more complex than it looks, because you also need to store the timestamp when you updated this data last time. As far as I understand, both of those services will take a timestamp parameter, something more like boolean HasChangedSince(timestamp). Otherwise this won't work when two mashups will try to "look" at the same thing at the same time -- one will be resetting "dirty" flag, and the second will never update. So instead of the dirty flag I'd need to look at lastUpdated property and reset a timestamp in the mashup. I hope it makes sense and please correct me if I'm wrong, maybe I don't see something.

                 

                I figured out that in my case a simple browser-side cache would be the most efficient, but I couldn't find an elegant solution to keep this InfoTable somewhere in the browser and compare it with the returned value.

                 

                At the end of the day the solution was really dumb -- we just recreated the repeater mashup and for some reason it stopped blinking. I still don't know why, now when we update the number of repetitions it redraws instantaneously, without erasing the old image, so if the number didn't change -- I wouldn't see the refresh.

                 

                But if I had to do this "cache", I would probably go with the timestamp-based solution for checking the changes, similar to what Vladimir and Alessio suggested. I will mark Vladimir answer "correct", because he was the first

                 

                Thank you for an interesting discussion!

                 

                Regards,

                Constantine