3
\$\begingroup\$

I've created a modular structure for my Angular application.

The main idea is to have a folder of modules which may be reusable later by simple copying them to the new project. With help of Gulp I created a tasks which iterates over each folder in modules and makes a final build.

Here is my source and build

I would appreciate if you could point my weak parts and suggest how I may optimize my code to footer-proof its logic and maintainability.

Here is my angular.app:

var app = angular.module('store', [
    'ngRoute',
    'catalog',
    'store-gallery',
    'store-panel',
    'contact',
    'scopeTest',
    'cart'
]);

app.config(['$routeProvider', function ($routeProvider) {
    $routeProvider
        // Home
        .when("/", {templateUrl: "layout/home.html", controller: "PageCtrl"})

        // main page modules
        .when("/catalog", {templateUrl: "layout/catalog.html" })
        .when("/contact", {templateUrl: "layout/contact.html" })
        .when("/cart", {templateUrl: "layout/cart.html" })
        .when("/test", {templateUrl: "layout/test.html" })

        // else 404
        .otherwise("/404", {templateUrl: "layout/404.html" })
}]);

app.controller('PageCtrl', function (/* $scope, $location, $http */) {
    console.log("Page Controller reporting on duty.");
});


app.service('productService', function() {

    var productList = [];

    var addProduct = function(obj) {
        productList.push(obj);
    };

    // TODO create a callback func
    var getProducts = function(){
        return productList;
    };

    return {
        addProduct: addProduct,
        getProducts: getProducts
    };

});
app.factory('getProductsJson', ['$http', function ($http) {
        return $http.get('products.json');
}]);

(function () {

    var app = angular.module('cart', []);

    app.controller('CartCtrl', function ($scope, productService) {

            $scope.products = productService.getProducts();
            this.products = $scope.products;
            this.qty = 1;

            console.log(this.products.length);

        });
}());
(function () {

    var app = angular.module('catalog', []);

    app.controller('CatalogController', function (getProductsJson) {
        var store = this;
        store.products = [];
        getProductsJson.success(function (data) {
            store.products = data;
        });
    });

}());


(function () {
   angular.module('contact', [])
       .controller('ContactCtrl', function () {
           // Activates Tooltips for Social Links
           $('.tooltip-social').tooltip({
               selector: "a[data-toggle=tooltip]"
           });
       });
}());
angular.module('scopeTest', [])

    .controller('FirstCtrl', function () {

    }).controller('SecondCtrl', function () {

});


(function () {
    var app = angular.module('store-gallery', []);
    app.directive('productGallery', function () {
        return{
            restrict: 'A',
            templateUrl: 'layout/product-gallery.html',
            controller: function () {
                this.pic = 1;
                this.setPic = function(pic){
                    if (pic !== null) {
                        this.pic = pic;
                    } else {
                        this.pic = 0;
                    }
                };
            },
            controllerAs: 'gallery'
        };
    });
}());
(function(){

    var app = angular.module('store-panel', []);

    app.controller('ProductController', function($scope, productService) {
        this.sendToCart = function(product){
            var productNew = product;
            var alreadyInCart = productService.getProducts();
            var existInCart = jQuery.inArray(productNew, alreadyInCart);

            function checkExist() {
                if (existInCart === -1 ){
                    productService.addProduct(productNew);
                }
            }
            checkExist();
            console.log(alreadyInCart);

        };
    });

    app.directive('productPanel', function () {
        return{
            restrict: 'A',
            templateUrl: 'layout/product-panel.html',
            controller: function () {
                this.tab = 1;
                this.selectTab = function(setTab) {
                    this.tab = setTab;
                };
                this.isSet = function (checkTab) {
                    return this.tab === checkTab;
                };
            },
            controllerAs: 'panel'
        };
    });

    app.directive('productDescription', function(){
        return {
            restrict: 'E',
            templateUrl: 'layout/product-description.html'
        };
    });

    app.directive('productSpecs', function () {
        return{
            restrict: 'E',
            templateUrl: 'layout/product-specs.html'
        };
    });

    app.directive('productReview', function () {
        return{
            restrict: 'E',
            templateUrl: 'layout/product-review.html',
            controller: function () {
                this.review = {};
                this.addReview = function(product){
                    this.review.createdOn = Date.now();
                    product.reviews.push(this.review);
                    this.review = {};
                };
            },
            controllerAs: 'reviewCtrl'

        };
    });

}());
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Looks good I think. Using separate folders for functionality instead of per file type is definitely a good thing (and something I want to do as well if I find the time).

Now a couple of points I think could be improved:

You should definitely use minification safe injection all the time.

console.log should use $console to be safe.

Sometimes the controllers have the suffix Controller, sometimes Ctrl; it's better to choose one of those and stick with it.

Since you're fetching data it could useful to expose that fact by using promises, so e.g. instead of relying on having the list of products ready you could just return a promise to have a bit more safety. In a sense you get more correct code, because you can just wait until all data is available instead of hacking around the fact that not everything is loaded yet.

\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.