1 Reply Latest reply on Dec 31, 2007 10:24 AM by paulfeuer

    Design Pattern / Best Practice Question

    wbailey4
      Hi,

      I have been using Flex for a while now, but there is a scenario which I still have not found a solution I'm entirely happy with. I'm wondering if anyone else out there might have suggestions on a design pattern or best practice.

      Suppose I have a view which depends on model data which resides in some back end systems. That model data may or may not have been loaded (e.g. via a web service or remote object call) at the time the view is displayed.

      I don't know if the user will ever visit this part of the application so I would prefer to defer retrieval of the data until the user actually navigates to this view. Or I want to retrieve the data each time the view is displayed because the data is dynamic and could change between one presentation of the view and the next.

      Because the data comes from several systems, I cannot simply make one service call and display the view when it completes and all the data is available. I need to call several services which could complete in any order but I only want to display my view after I know all of them have completed and all of the model data is available. Otherwise, I can present the user an incomplete view (e.g. some combo boxes are empty until the corresponding service call to get the data completes).

      The solution I like best so far is to dispatch a single event (I am using Cairngorm) handled by a single command which acts as the caller and responder for all of the services. This command then remembers which responses it has received and dispatches another event to navigate to the view once all the results have returned.

      If the services being called are used in different combinations on different screens, this results in proliferation of events and commands. An event and command for each service and additional events and commands to bundle the services and the handling of their responses in the right combinations for each of the views.

      Another approach is to have some helper class listen for all of the model changes and only display the view when the model enters some state that is acceptable. It is sometimes difficult to determine just by looking at the model whether it is in the right state (e.g. how can I tell that a collection is the new collection that should just have been requested versus an old one lingering from a previous call). The logic required can get kind of convoluted and brittle.

      Basically, all of the solutions I've come up with so far seem less than ideal and a little hackish. I keep thinking there is some elegant solution out there that I am just missing ... but so far, no luck finding it. Thoughts?

      Thanks.

      Bill
        • 1. Re: Design Pattern / Best Practice Question
          paulfeuer Level 1
          i think a service class is right - to coordinate your calls. i would have 1 event per call (so you could listen to individual responses if you wanted to).

          then i would use a flag. if you want to check for staleness, you would probably want two objects to map your service flag to lastRequested and lastCompleted. when you check, check if it's completed, and if it's not stale and that your lastRequested is less than lastCompleted (meaning that you're not currently waiting, i.e. you've returned since making a request). then make the request and update your lastRequested.

          here's a snippet of what i mean.

          ./paul

          public static const SVC1_LOADED:int = 1;
          public static const SVC2_LOADED:int = 2;
          public static const SVC3_LOADED:int = 4;
          public static const SVCALL_LOADED:int = 7;
          private var completedFlag:int = 0;

          then each call would have it's own callback.

          private function onSvc1Complete( evt:Event):void {
          completedFlag |= SVC1_LOADED;
          lastCompleted[ SVC1_LOADED ] = getTimer();
          dispatchEvent( new Event("svc1complete") );
          checkDone();
          }
          private function checkDone():void{
          if( completedFlag == SVCALL_LOADED )
          dispatchEvent(new Event( "allLoaded" ));
          }