Search code examples
angularjscode-duplication

Refactor similar controllers in different modules


My Application depends on multiple AngularJS modules but each module has to deal with similar data. The modules are used in different places on my page.

I've created a bunch of controllers which are basically responsible for assigning data to $scope variables. I think there is a lot of "code smell" in there and i have bad feelings with all the duplicated code. But currently i've no idea how to prevent it.

The Attributes documentations and infomaterial are resolved and injected in my $routeProvider.

What is a better way to deal with such cases?

Controller 1

angular.module('MyApp.selectorDocumentations')
    .controller('SelectorDocumentationsCtrl', function ($scope, FacetService, Attributes, documentations) {

        $scope.documentationsData = documentations.data;
        $scope.documentations = documentations.data.hitlist.content;

        $scope.currentPage = documentations.data.hitlist.page.number;
        $scope.totalPages = documentations.data.hitlist.page.totalPages;
        $scope.hitlistContent = documentations.data.hitlist.content;
        $scope.totalElements = documentations.data.hitlist.page.totalElements;

        FacetService.prepare(documentations.data);

        $scope.hardReset = function () {
            FacetService.hardReset(false, documentations.data);
        };

        $scope.manufacturer = function (item) {
            return Attributes.getManufacturer(item);
        };

        $scope.project = function (item) {
            return Attributes.getProject(item);
        };

        $scope.projectBookVersion = function (item) {
            return Attributes.getProjectBookVersion(item);
        };
    });

Controller 2

angular.module('MyApp.selectorInfomaterial')
    .controller('SelectorInfomaterialCtrl', function ($scope, FacetService, Attributes, infomaterial) {

    $scope.informaterialData = infomaterial.data;
    $scope.infomaterials = infomaterial.data.hitlist.content;

    $scope.currentPage = infomaterial.data.hitlist.page.number;
    $scope.totalPages = infomaterial.data.hitlist.page.totalPages;
    $scope.hitlistContent = infomaterial.data.hitlist.content;
    $scope.totalElements = infomaterial.data.hitlist.page.totalElements;

    FacetService.prepare(infomaterial.data);

    $scope.hardReset = function () {
        FacetService.hardReset(false, infomaterial.data);
    };

    $scope.mediaType = function (item) {
        return Attributes.getMediaType(item);
    };

    $scope.mediaTitle = function (item) {
        return Attributes.getMediaTitle(item);
    };

    $scope.mediaSubline = function (item) {
        return Attributes.getMediaSubline(item);
    };

});

Solution

  • Wow, those controllers are basically identical. I'd move all that code into a factory, and initialize it with either documentation or infomaterial.

    app.controller('SelectorDocumentationsCtrl', function ($scope, documentations, MyDataHandler) {
      $scope.myDataHandler = new MyDataHandler(documentations);      
    });
    
    
    app.controller('SelectorInfomaterialCtrl', function ($scope, infomaterial, MyDataHandler) {
      $scope.myDataHandler = new MyDataHandler(informaterial);
    });
    

    Those could be initialized in a state in ui-router also. If you need help to build the factory/service, let me know.