1. #1
    Sencha Premium Member
    Join Date
    Nov 2011
    Location
    Portland, Oregon
    Posts
    18
    Vote Rating
    0
    Answers
    1
    isiphil is on a distinguished road

      0  

    Default Unanswered: Design question on best practice for handling process flow based on ajax response.

    Unanswered: Design question on best practice for handling process flow based on ajax response.


    A colleague and I were parallel programming in a concerted effort to find a usable solution for our use case. Ultimately we both accompished the task, but with two different approaches. The discussion ensued as to which one we should proceed with. As we are both fairly new to sencha we don't have much to base our opinions on. I was hoping the community could provide some input and help us decide if one is better than the other, or if we should be going a totally different direction. Our main goal is to establish a pattern that we can continue with for the life cycle of the project and keep the code optimal, easy to follow, and sustainable.


    This is the gist of our scenario. We have a search button that loads a store with vehicles. In the callback we check to see if there are any records. If there are not we assume they are adding a new vehicle and display an Ext.Msg.prompt to get the vehicle_id from the user. When they hit ok we then make another method call to create the vehicle. That method call contains an Ext.Ajax.request to insert the vehicle. We need to evaluate the response and navigate differenty based on the values. Here is where we are looking for some input.


    In my code I had the success function decode the response and set a class level variable to true or false. I think be setting the async: false on the ajax request I could then utilize that variable to determine proper navigation when the first method call was done.


    My Colleague went a different route. She elected to go with an event based solution. From the success function on the ajax request she fires an application level event. Her idea was that our main controller would listen for this event and be responsible for the navigation control. We thought having a main controller that did all the main navigation control may be a good idea.




    If anyone has any thoughts or ideas on these two approaches, I would appreciate it. If we should be going a totally different route that would be good to know as well.

    Here is a code snippet from my solution:
    Code:
    onSearch : function(field) {
        this.getVehicleGrid().getStore().getProxy().setUrl('/webservice/vehicleList');
        this.getVehicleGrid().getStore().load({
            callback: function(records, options, success) {
                if (records.length < 1) {
                    Ext.Msg.prompt(
                            "NEW VEHICLE ID",
                            "No search results found. Cancel and modify search criteria or start new vehicle with ID:",
                            function(answer, vehicle_id) {
                                if (answer=='ok') {
                                    
                                    this.createVehicle(vehicle_id);
                                    
                                    if (ajaxVariable == true) {
                                        if (!this.newVehiclePanel) {
                                            this.newVehiclePanel = Ext.create('greeter.view.NewVehicle');
                                        }
                                        this.getVehicleSearchView().hide();
                                        Ext.Viewport.add(this.newVehiclePanel);
                                        this.newVehiclePanel.show(); 
                                    } else {
                                        Ext.Msg.alert('ERROR!', 'In Progress', Ext.emptyFn);
                                    }
                                }
                            },
                            this,
                            false,
                            null,
                            {
                                maxLength: 13,
                                placeHolder: 'Enter Vehicle ID:',
                                autoCapitalize: true
                            }
                      );
                }
            },
            scope: this
        });              
    }
    
    
    createVehicle : function(vehicle_id){
        vehicle_id = vehicle_id.toUpperCase();
        Ext.Ajax.request({
            url: 'webservice/vehicle', 
            method: 'POST',
            async:false,
            scope: this,
            jsonData: {
                vehicleId: vehicle_id
            },
            success: function(response, opts){    
                var decodedResponse = Ext.decode(response.responseText); 
                var success = decodedResponse.success;
                if (success) {
                    workorder_id = decodedResponse.recnum;
                    ajaxVariable = true;
                }else {
                    ajaxVariable = false;
                }
             },
            failure: function(response, opts){
            Ext.Msg.alert("Error", "Failed: " + vehicle_id);
            }
          });    
    },
    Here is a code snippet from her solution:
    Code:
    onSearch : function(field) {
        this.getVehicleGrid().getStore().getProxy().setUrl('/webservice/vehicleList');
        this.getVehicleGrid().getStore().load({
            callback: function(records, options, success) {
                if (records.length < 1) {
                    Ext.Msg.prompt(
                            "NEW VEHICLE ID",
                            "No search results found. Cancel and modify search criteria or start new vehicle with ID.",
                            function(answer, vehicle_id) {
                                if (answer=='ok') {
                                    this.createVehicle(vehicle_id);
                                }
                            },
                            this,
                            false,
                            null,
                            {
                                maxLength: 13,
                                placeHolder: 'Enter Vehicle ID:',
                                autoCapitalize: true
                            }
                        );
                }
            },
            scope: this
        });              
    },
    
    
    createVehicle : function(vehicle_id){
        vehicle_id = vehicle_id.toUpperCase();
        var me = this;
        Ext.Ajax.request({
            url: '/webservice/vehicle', 
            method: 'POST',
            async: false,
            jsonData: {
                vehicleId: vehicle_id
            },
            success: function(response, opts){    
                var decodedResponse = Ext.decode(response.responseText); 
                var success = decodedResponse.success;
                if (success) {
                    workorder_id = decodedResponse.recnum;
                    me.getVehicleSearchView().hide();
                    me.getApplication().fireEvent('createdNewWorkorderEvent', isNewVehicle);
                }
                else {
                    me.handleWorkorderInProgress();
                }
             },
            failure: function(response, opts){
    //            handle failure!
            }
          });        
    },
    handleWorkorderInProgress : function() {
        var me = this;
        Ext.Msg.alert('ERROR!', 'Workorder in progress', function (btn){
            if (btn == 'ok'){
                me.getApplication().fireEvent('startOverEvent');
            }
        });
    },

  2. #2
    Sencha User bluehipy's Avatar
    Join Date
    Mar 2010
    Location
    Romania
    Posts
    599
    Vote Rating
    26
    Answers
    66
    bluehipy will become famous soon enough bluehipy will become famous soon enough

      0  

    Default


    My thoughts:

    on both solutions you ask for vehicle ids which is an integer right, ids ? that is strage
    on both solutions you are using not async Ajax calls, I wonder why?

    on your solution async:false makes sense because you are testing the ajaxVariable just after, but I don't like the non async approach in javascript I think it is better to make things async let process flows paralel ways

    her solutioin though it sets the async to false, is event driven and from that aspect is better in my point of view


    so her solutoin is better than yours, for a js perspective, but I wouldn't do it her way either


    Firing events its noce but, events can be listen from all over the application and in a large app that might be dangerous. It might be a good approach if you put together some rules, maybe, like, all events are only routed trough application or that controller, and only there, so one will not die while debuging where some event is handled So if you force some event routing rule set, event driven solutions are ok, I would say.


    Another way would be to directly call the desired method in the callbacks of course.

    Code:
    controller
    
    btnSearchHandler: function(btn)
    {
            this.isBusy = true;
            Ext.Ajax.request(
                    success : Ext.bind(this, this.searchSuccessHandler),
                    failure : Ext.bind(this, this.searchFailureHandler)
            );
    },
    searchFailureHandler : function()
    {
             this.isBusy = false;
             //alert thingy
    },
    searchSuccessHandler : function(response)
    {
             this.isBusy = false;
           //decode thingy
          if(success)
          {
                  this.showAddVehiclePanel({id:decoded.vehcle_id, params:other decoded_params});
           }
    },
    showAddVehiclePanel:function(config)
    {
            //add or update
             if(!this.getVehiclePanel())
             {
                   this.setVehiclePanel( 
             Ext.Viewport.setActiveItem(
                  {
                         xtype:'that_vehicle_panel_xtype,
                         params:config.params_etc
                  }
             );
                );
            }else{
                    this.getVehiclePanel().someUpdateMethod( config );
                   Ext.setActiveItem( this.getVehiclePanel() );
            }
    }

    Regarding the event driven approach you or her, might be interested to read about ST2 routing system. Read about routes in controller and redirectTo method

    http://docs.sencha.com/touch/2-0/#!/api/Ext.app.Controller-cfg-routes
    http://docs.sencha.com/touch/2-0/#!/...hod-redirectTo

  3. #3
    Sencha Premium Member
    Join Date
    Nov 2011
    Location
    Portland, Oregon
    Posts
    18
    Vote Rating
    0
    Answers
    1
    isiphil is on a distinguished road

      0  

    Default


    bluehipy,
    Just wanted to say thanks for taking the time to offer your thoughts. It is much appreciated.

    I think we have elected to stay with the event based design. We do have multiple controllers and will try to adhere to set rules and how each will handle different events.
    In her scenario I have removed the async: false.

    We actually changed the "Enter New Vehicle id" Ext.msg.prompt to an Ext.ActionSheet. The look and feel seems to be better and allowed our process flow to be a little more intuitive.

    Thanks again,
    Phil

  4. #4
    Sencha User bluehipy's Avatar
    Join Date
    Mar 2010
    Location
    Romania
    Posts
    599
    Vote Rating
    26
    Answers
    66
    bluehipy will become famous soon enough bluehipy will become famous soon enough

      0  

    Default


    You are welcome Phil