jusopi
jusopi

Reputation: 6813

Angular: UI.Router resolves & controller code duplication

I've been refactoring my app to make use of UI.Router's state.resolve to clean up some controller logic. But then I started running into the following issue: How do you avoid the code-duplication found in fetching dependencies in the resolved assets and also found in updating data inside a controller?

state

$stateProvider.state 'someState', state =
    controller: 'SomeController'
    controllerAs: 'vc'
    resolve: { viewData: [
        '$http'
        '$q'
        '$stateParams'
        'someService'
        ($http, $q, $stateParams, someService)->
           someService.get $stateParams.id
           .then (rsp)-> rsp
           .catch (err)-> $q.reject err
]}

view controller

class SomeController
    constructor: (@$http, @$q, @$stateParams, @someService, @viewData)->
        # non-Coffee FYI - @arg is the same as "this.arg = arg"

    getViewData: ->
        someService.get @$stateParams.id
        .then (rsp)-> @viewData = rsp
        .catch (err)-> $q.reject err

** some service**

class SomeService
    constructor: (@$http, @$q)->

    get: (id)->
        $http.get "/url/#{id}"
        .then (rsp)-> rsp.data?.data
        .catch (err)-> $q.reject err

The state's resolved viewData function is nearly identical to the contoller's getViewData call. That seems awfully redundant. Any tricks on leveraging the same code?

I was even thinking of passing a function back in the resolved object that could be assigned to the controller that it could leverage when it needed to execute the same logic but I couldn't figure out the (non-ng) scope issues.

real life

  1. entering state, resolve object fetches initial viewData
  2. state's controller & UI render with current viewData already set
  3. view controller polls get service to check for updates on viewData every x minutes

Upvotes: 1

Views: 277

Answers (1)

Estus Flask
Estus Flask

Reputation: 222780

The common piece of code has to be separated into a service and wrapped in function:

app.factory('viewDataService', function ($http, $q, $stateParams, someService) {
  return function () {
    return someService.get($stateParams.id).then(function(rsp) {
      return rsp;
    })["catch"](function(err) {
      return $q.reject(err);
    });
  }
});

As it was shown here, this way someService.get can be called each time the service is being injected

resolve: {
  viewData: function (viewDataService) {
    return viewDataService();
  }
}

Upvotes: 1

Related Questions