0

I'm developing a new proyect using angular and I have separated the: App (main module), controller and services in diferent files:

The responsabilities are:

indexApp.js

And them code is:

(function(indexApp) {

    indexApp.App = {};

    indexApp.Init = function() {
        indexApp.App = angular.module("MainAppModule", ["MainControllerModule", "MainServiceModule"]);
    };

}(window.indexApp = window.indexApp || {}));

indexController.js

And them code is:

(function (indexController) {

    indexController.App = {};

    indexController.MainController = function (service) {
        var self = this;

        var dataRetrieved = service.Login();

        self.movie = {
            title: dataRetrieved.Id,
            director: dataRetrieved.Name,
            date: dataRetrieved.LastName,
            mpaa: "PG-13",
            id: 0,
            clickCommand: function () {
                alert(self.movie.director);
            },
            loadData: function (id) {

                console.log(id);

                if (id !== 0) {
                    self.movie.title = "Titulo";
                    self.movie.director = "Director";
                    self.movie.date = "Mayo 16 de 2015";
                    self.movie.mpaa = "PG-25";
                    self.movie.id = id;
                }
            }
        }
    };

    indexController.SetUrl = function (data) {
        indexController.Redirect = data.Redirect;
    };

    indexController.Init = function () {
        indexController.App = angular.module("MainControllerModule", []);
        indexController.App.controller("MainController", indexController.MainController);
        indexController.MainController.$inject = ["MainService"];
    };

}(window.indexController = window.indexController || {}));

indexService.js

Them code is:

(function (indexService) {

    indexService.App = {};

    indexService.MainService = function () {
        var self = this;

        self.Login = function () {
            return {
                Id: 1,
                Name: "Freddy",
                LastName: "Castelblanco"
            };
        };
    };

    indexService.SetUrl = function (data) {
        indexService.Login = data.Login;
    };

    indexService.Init = function () {
        indexService.App = angular.module("MainServiceModule", []);
        indexService.App.service("MainService", indexService.MainService);
    };

}(window.indexService = window.indexService || {}));

At the end in my view I call the follow methods:

@using System.Web.Optimization

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
    var id = 20;
}

<div ng-app="MainAppModule">
    <div ng-controller="MainController as vm">
        <div ng-init="vm.movie.loadData(@id)">
            <div class="row">
                <div class="col-md-12">{{vm.movie.title}}</div>
                <input type="text" ng-model="vm.movie.title"><br>
            </div>
            <div class="row">
                <div class="col-md-12">{{vm.movie.director}}</div>
            </div>
            <div class="row">
                <div class="col-md-12">{{vm.movie.date}}</div>
            </div>
            <div class="row">
                <div class="col-md-12">{{vm.movie.mpaa}}</div>
            </div>
            <div class="row">
                <div class="col-md-12">
                    <button type="button" ng-click="vm.movie.clickCommand()">Click me !!</button>
                </div>
            </div>
        </div>
    </div>
</div>



@section scripts
{
    @Scripts.Render("~/bundles/index")

    <script type="text/javascript">

        indexApp.Init();
        indexService.Init();
        indexController.Init();


    </script>
}

Is a correct way to use angular ?? Im using dependency injection.

  • If you are using angular you don't need to use iife's to start your app. All this functionality can be achieved with modules. This also prevent pollution of the global scope wich you are doing using `window.indexApp = window.indexApp || {}` – devconcept Jul 07 '15 at 16:41
  • @devconcept might you give an example of the suggestion that you have mentioned ?? I mean, how wrote the code ?? – Freddy Castelblanco Macias Jul 07 '15 at 16:55
  • I check your code and you have several inconsistencies. Are you learning angular? It looks like you have background in other frameworks like knockout – devconcept Jul 07 '15 at 17:21
  • Hehehe, yes, I come from knockout ... And, yes Im learning angular too ... And I want continue use MVVM pattern ... – Freddy Castelblanco Macias Jul 07 '15 at 17:22

1 Answers1

2

How you define an angular app is up to you but angular provides modules to deal with code organization, prevent global scope pollution, dependency injection among other things

Angular apps don't have a main method. Instead modules declaratively specify how an application should be bootstrapped

You are using a common method found in other frameworks of using var self = this to add functionality to your app but angular comes with a nice gift scopes. Scopes are extremely useful because all angular apps have one and only one $rootScope wich you can use to store commonly used functionality all across your application. Also scope are organized in a hierarchy wich give you the abitity to nest scopes and make some logic work only on specific DOM elements.

Scopes are arranged in hierarchical structure which mimic the DOM structure of the application. Scopes can watch expressions and propagate events.

To glue your application you should use $watch on the scope to be notified of changes but usually you use any of the predefined directives that do this automatically for simple task like binding and changing attributes eg. ngBind, ngClick, etc.

Scope is the glue between application controller and the view. During the template linking phase the directives set up $watch expressions on the scope. The $watch allows the directives to be notified of property changes, which allows the directive to render the updated value to the DOM.

I personally don't use IIFE when I'm using angular but this is a personal choice. The iife allows you to prevent global scope pollution by wrapping variables inside a function scope so you don't have name collisions but angular introduces providers which can help you to create functionality using factories and services so basically you wrap all your functionality in one of them (read which is the most suitable for your task) and you have already included dependency injection in the mix for free.

Finally there are three ways to use dependency injection (or ways to anotate it).

  1. Inline Array Annotation

    mymodule.controller('MyController', ['$scope', function($scope) {
          // your code
    }]);
    
  2. $inject Property Annotation

    var MyController = function($scope) {
        // ...
    }
    MyController.$inject = ['$scope'];
    someModule.controller('MyController', MyController);
    
  3. Implicit Annotation

    someModule.controller('MyController', function($scope) {
        // ...
    });
    

You are free to use the way that you feel more confortable with but you should be aware that the last alternative is dangerous if you plan to minify your code because angular rely in variable names to find the dependencies and those will get renamed in the minification process. Personaly I use the first and it seems the most popular since you don't need the extra variable used in the second alternative.

Your code can be rewritten as follows

angular.module('services', []).service('MainService', function () {
    return {
        Login: function () {
            return {
                Id: 1,
                Name: "Freddy",
                LastName: "Castelblanco"
            };
         }
    };
});
angular.module('controllers', []).controller('MainController', ['$scope', 'MainService', function ($scope, service) {
    var dataRetrieved = service.Login();

    $scope.movie = {
        title: dataRetrieved.Id,
        director: dataRetrieved.Name,
        date: dataRetrieved.LastName,
        mpaa: "PG-13",
        id: 0
    };
    $scope.clickCommand = function () {
       alert($scope.movie.director);
    };
    $scope.loadData = function (id) {
        if (id !== 0) {
            $scope.movie.title = "Titulo";
            $scope.movie.director = "Director";
            $scope.movie.date = "Mayo 16 de 2015";
            $scope.movie.mpaa = "PG-25";
            $scope.movie.id = id;
        }
    }
 }]);

 angular.module('MainAppModule', ['controllers', 'services']);

And your html

<div ng-app="MainAppModule">
    <div ng-controller="MainController">
        <div ng-init="loadData(@id)">
            <div class="row">
                <div class="col-md-12">{{movie.title}}</div>
                <input type="text" ng-model="movie.title">
                <br>
            </div>
            <div class="row">
                <div class="col-md-12">{{movie.director}}</div>
            </div>
            <div class="row">
                <div class="col-md-12">{{movie.date}}</div>
            </div>
            <div class="row">
                <div class="col-md-12">{{movie.mpaa}}</div>
            </div>
            <div class="row">
                <div class="col-md-12">
                    <button type="button" ng-click="clickCommand()">Click me !!</button>
                </div>
            </div>
        </div>
    </div>
</div>

{Update}

You can also check AngularJS: Understanding design pattern for guidelines on how you should structure your angular app

Community
  • 1
  • 1
devconcept
  • 3,665
  • 1
  • 26
  • 40
  • Perfect ... Thanks a lot ... It is very helpful, I would like to know if is still good practice have the: modules, controllers, services, directives, filters, etc ... In separated files ... Should I have all of them on separated files ?? – Freddy Castelblanco Macias Jul 07 '15 at 19:24
  • 1
    Well really the answer depends on the size of the project. You could use require.js for bigger projects, separate your logic by features or use separate files for controllers, services and directives but remember to wrap them in modules so can inject them easily later. – devconcept Jul 07 '15 at 19:35
  • 1
    @FreddyCastelblancoMacias check my edit on a good SO article that will help ypu on your learning – devconcept Jul 07 '15 at 19:45
  • Thanks a lot ... I come from knockout ... I like that, that is the reason why I have built angular code a little similar to knockout ... But its time to learn more ... However I will never leave knockout ... – Freddy Castelblanco Macias Jul 07 '15 at 19:59
  • 1
    @FreddyCastelblancoMacias just a note in the other answer by Ederson. John Papa is a smart guy, no doubt about it, but he make some opinionated answers in the referenced article that may have to do with his own learning process. I'm not saying he is wrong, i'm saying that you will probably found that most angular developers write code very different than him. I come from knockout just as you and probably John Papa as well so I know from experience that enforce all those rules on a team that learned angular the old way is going to be difficult and many times innecesary. – devconcept Jul 07 '15 at 20:02
  • I was watching that for example he uses IIFE, leaves the functions declarated implicity, really I like IIFE, but I dont like declare the function implicity, my main goal is keep using MVVM pattern, and all the good helps that I could find for build a good code will be very helpful, really I do not like the angular API. I like more books like: [link](http://www.amazon.com/Pro-AngularJS-Experts-Voice-Development-ebook/dp/B00HX4PJ9I/ref=sr_1_2?ie=UTF8&qid=1436300134&sr=8-2&keywords=angularjs) – Freddy Castelblanco Macias Jul 07 '15 at 20:17
  • 1
    The reason why he uses IIFE is because he uses named over anonymous functions claiming that is more readable but yet I never found an angular developer that write code like that. This is readable sometimes, not always because is not readable when you are chaining stuff. Also understanding `this` is the nightmare of every new javascript developer and he prefer that notation over the standard $scope whose meaning will be obvious to any reader – devconcept Jul 08 '15 at 11:54