1

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
6
  • It depends. Is 'url' the same in all cases? Does $http request in 'viewData' should be executed on every state resolve or only once? Commented Nov 25, 2015 at 20:10
  • After trying to understand what you meant, I noticed I had completely forgotten the service code. This may need a broader example as currently it's extremely trivial. So yes, the URL is the same regardless if it's the resolve object calling it or the view controller. In terms of the every vs once question, I'm not sure I follow. It wouldn't be cached if that's what you mean. Commented Nov 25, 2015 at 20:25
  • Possible duplicate of Angular Authentication : Avoid multiple resolve for different routes Commented Nov 25, 2015 at 20:31
  • I guess it is pretty much the same case of route resolver. Commented Nov 25, 2015 at 20:32
  • That isn't an issue for me as I am using a parent state to handle any inherited resolved dependencies. This particular viewData request is unique to the view, meaning no other route/state would utilize this. The duplication is in how the resolved dependency and the subsequent controller request are nearly identical. Again a very trivial example but I'm trying to be as concise as possible Commented Nov 25, 2015 at 20:36

1 Answer 1

1

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();
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

I'm going to mark this as the answer since it is correct, I just wish I could find a better means to encapsulate this when there might be logic that needs to be performed outside of the service call (e.g. pulling $stateParams) but w.o having to pass that logic into the service.
@jusopi Passing parameters from the outside as viewDataService function arguments looks fine to me, this ensures testability. But maybe I misunderstood you, feel free to post a question with current code if you still got issues on the subject.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.