0

I have a typical projects/tasks/subtasks CRUD app, and one can navigate from a top level project listing all the way down to a subtask.

All resources are routed, e.g.

/projects to get all projects,

/projects/:id to get a specific project,

/projects/:id/tasks to get all tasks for a specific project, and so on.

I render tasks like so:

<ul>
  <li ng-repeat="task in tasks">
    <a href="/tasks/{{task.id}}">
      {{task.name}}</a> ...

The controller responsible for the /tasks/:id route gets the data using the $routeParams from the backend API, but I was wondering how to load the task from the information I already have in the scope I link from, e.g. something like:

<ul>
  <li ng-repeat="task in tasks">
    <a href="/tasks/{{task.id}}" ng-click="useThisTaskInstead(task)">
    <!--                                   ^^^^^^^^^^^^^^^^^^       -->
    <!--                                   set this in the
                                             target scope.          --> 
      {{task.name}}</a> ...

I want the target controller to only contact the backend API if the task isn't in scope.

The URL in the address bar should also still show http://example.org/tasks/5, for example.

UPDATE

Something I tried which I'm unsure about:

I have a top-level ApplicationController in which I define:

$scope.cacheTask: function (task) {
  $scope.task = task;
};

...and then the link becomes:

<a href="/tasks/{{task.id}}" ng-click="cacheTask(task)">

...and in my TaskController:

    if (typeof $scope.task !== 'undefined'  && $scope.task.id == $routeParams.id) {
        // nothing to do -- task already set in scope.
        console.log("task already in scope");
    } else {
        console.log("fetching task");
        // load task
        $q.when(taskService.get($routeParams.id).$promise).then(function(task) {
            console.log("task fetched from backend", task);
            // set the task in scope
            $scope.task = task;
        });
    }

1 Answer 1

1

This should be handled in your model/persistence system. Your model access layer's API should abstract the caching away, and the controllers/views can get on with life (any use of $scope for non-presentational stuff is a bit of a smell IMHO).

Controllers and views should be completely ignorant of persistence state. Have them use a method like Task.get(id) than returns a promise. Clean, and the rest of your app is none the wiser whether the promise was fulfilled from cache or a fresh HTTP request.

Sign up to request clarification or add additional context in comments.

4 Comments

Right, so instead of getting cacheTask to set the scope, it sets a cache field on the task service singleton, which is then checked with every call to taskService.get(id)?
Yes - if task is a data access layer (or an ActiveRecord-y thing). Otherwise it'd be handled in the persistence layer. Both $http and $resource` have really simple ways of enabling caching.
BTW - no need to suffix a service with Service (or Factory etc) - services are a concept for ng's module system, not something to put into your naming.
Thanks for pointing out the caching feature. I'll see if it's easy to pre-populate the cache with the cacheTask concept I discuss in my answer.

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.