Hamid Barani
Hamid Barani

Reputation: 191

Angular - Using one controller for many coherent views across multiple HTTP requests

I have a simple Angular JS scenario. I show a list of experts in one view, and that list contains actions to edit an expert, which would be done in another view. These views are coming from server and are not in one file. They don't load together.

<!-- experts.html -->
<div ng-controller='expertController'>
    <!-- showing the list of experts here -->
</div>

And in another file on the server I have:

<!-- expert.html -->
<div ng-controller='expertController'>
    <!-- a form to edit/add an expert -->
</div>

And my controller is:

app.controller('expertController', function ($scope) {
    $scope.getExperts = function () {
        _.get('/expert/getexperts/', null, function (data) {
            $scope.$apply(function () {
                $scope.experts = data;
            });
        });
    };

    $scope.editExpert = function (index) {
        _.get('/expert/getexpert/', { id: $scope.experts[index].Id }, function (data) {
                $scope.$apply(function () {
                    $scope.expert = data;
                });
         });
    };
});

However, no data would be shown in the edit form. I inspected scopes using Batarang, but expert object won't be shown.

The problem seems to be that I use one controller for two (and optionally more than two) views. However, as I've read some other questions on SO, it seems that the best practice is to have one controller per HTML view.

However, I think it's more coherent and consistent to have one expertController to do all CRUD operations, alongside other actions related to expert. I think it's a little ugly to have expertEditController for edit form and expertListController for the list HTML.

What is the best practice here? How can I have a coherent and semantically named controller, and at the same time support many views. In any MVC framework that I've seen till now, it's something routine to support many views via one controller.

Upvotes: 12

Views: 26772

Answers (3)

Sreekanth Karini
Sreekanth Karini

Reputation: 1285

Actually when we use same controller for other view, it will reloads that controller whenever the view loads. At that moment scope will lose it's data.To avoid this i used $rootScope instead of $scope. I don't know whether this approach is correct or not but it works.

$rootScope.expert instead of $scope.expert.

Upvotes: 0

AronVanAmmers
AronVanAmmers

Reputation: 1666

Here's an example project (not created by me) that illustrates how to use a single controller with two views: one for showing a list of items and one for editing or adding a single item: http://embed.plnkr.co/jAK31F/

The basic principle used in the controller is to check whether an id of a single item has been passed and run the applicable logic for that situation:

controllers.controller('MainController', function( $scope, $location, $routeParams, ItemService)  {
  if ($routeParams.itemid) {
    // do stuff for single item
    if ($routeParams.itemid == 0) {
      // do stuff for adding item
    } else {
      // do stuff for editing item
    }
  } else {
    // do stuff for listing multiple items
  }
});

The different views are configured in the routes like so:

app.config(['$routeProvider', function ($routeProvider) {
        // routes
        $routeProvider.
        when('/', {
            templateUrl: 'item_list.html',
            controller: 'MainController'
        }).
        when('/:itemid', {
            templateUrl: 'item_single.html',
            controller: 'MainController'
        });
    }]);

So an url like baseurl/ will open the list view, and an url like baseurl/1 will open the detail view of the item with id 1.

With regard to this being a best practice or not, for most situations I don't think this method offers an advantage over using two controllers: one for the list, and one for a single item. In my experience a controller to view multiple items has different concerns than one for editing a single item. Any shared logic can be placed in a service as suggested in earlier answers.

Upvotes: 7

artur grzesiak
artur grzesiak

Reputation: 20348

Of course you can use many views with the same controller. For example: for editing and adding new items.

But you have to remember that each time the view is loaded the controller is initialized and fresh, new $scope is injected.

In your case it would be better to just use two separate controllers (one for experts and one for expert) and use -- optionally -- some service to communicate between those and maybe provide some caching mechanism.

UPDATE In case you want to provide some common/shared functionality between controllers the best way to go is to create and then inject a separate service. It keeps the code DRY.

Upvotes: 18

Related Questions