Search code examples
angularjsangularjs-scopeangular-ui-routersingletonangularjs-service

Getting data and passing it to another state with ui-router in AngularJS


I know the topic of passing data between controllers has been discussed here, but I've been a bit confused about what seems like a common problem and I was wondering if anyone had a 'best practice' for this type of use case.

The scenario is when the user clicks a link or submits a form which calls a service to get an object by its ID. If the object is found, the state is changed and the object is returned to the controller of the new state. If the object is not found, an error is returned, i.e. 'we can't find that record'.

In the example below, an email is passed to the controller through a form and sent to 'RsvpService':

var MainController = function($state, $http, GuestListService, RsvpService){

    var mnCtrl = this;
    mnCtrl.submitEmail = submitEmail;

    function submitEmail(email){

        mnCtrl.error = "";
        mnCtrl.emailEntry = "";

        RsvpService.getGuestsByEmail(email)
        .then(function(res){
            //if an error comes back and it's 404, set an error message
            if(res === 404){
                mnCtrl.error = 'We can\'t find you :( Sure you got the right email?';
            }
        })
    }   
}

The factory returns an $http.post...

(function(){
'use strict';

var RsvpService = function($http, $state){

    var Rsvp = {};

    Rsvp.getGuestsByEmail = function(email){
        return $http.post('/getGuestsByEmail', {email : email})
        .then(function(res){
            //if there's a record, set it to Rsvp.guests and redirect to the next state
            Rsvp.guests = res.data;
            $state.go('rsvp-enter');
        }).catch(function(err){
            //if there's no record found, server returns a 404 error
            return err.status;
        });
    }

    return Rsvp;

}

angular.module('mainApp')
.factory('RsvpService', [
    '$http',
    '$state',
    RsvpService
])

})();

In state 'rsvp-enter' the record is set to the scope by retrieving the Rsvp.guests property from RsvpService.

var RsvpEnterController = function($state, RsvpService){

    var reCtrl = this;
    reCtrl.guests = RsvpService.guests
}

This feels like a very roundabout way of doing things for a simple problem, and I feel like I'm probably misusing promises and introducing a lot of bad practices into my code. For example, the error handling is being done in the service, and the response in the controller is really doing error handling. Surely this is wrong? I was just curious if anyone had any insight into this type of use case with angularjs and ui-router, and had any suggestions on how to make it better? Thanks in advance for your help.


Solution

  • I think it would be better to move the routing logic into the controller. So the service RsvpService will work more like a data controller or data modal just for Rsvp. You can even add setter function and update function.

    Even better, inside RsvpService you could check if the variable Rsvp is empty of not, if not then return it instead of fetching again.

    //a simple example
    angular.module('mainApp')
        .factory('RsvpService', ['$http', '$state', '$q',
            function($http, $state, $q){
    
                var Rsvp = {};
    
                Rsvp.getGuestsByEmail = function(email) {
                    //if the guests is already fetched
                    if(Rsvp.guests) {
                       var deferred = $q.defer();
                       deferred.resolve(Rsvp.guests); 
                       return deferred.promise;
                    }
    
                    //call loadGuestsByEmail() function and chain the promise object
                    return Rsvp.loadGuestsByEmail(email);
                };
    
                Rsvp.loadGuestsByEmail = function(email) {
                    return $http.post('/getGuestsByEmail', {email : email})
                .then(function(res){
    
                    Rsvp.guests = res.data;
    
                }).catch(function(err){
                //if there's no record found, server returns a 404 error
                    return err.status;
                });
            }
    
            return Rsvp;
    
    }]);
    

    For a more complex situation you could have a look at the link below, a good article here: http://www.webdeveasy.com/angularjs-data-model/