Git Product home page Git Product logo

angular-styleguide's Introduction

Angular Style Guide

Versions

There are multiple versions of Angular, and thus there are multiple versions of the guide. Choose your guide appropriately.

Angular 1 Style Guide

The Angular 1 Style Guide.

Angular 2 Style Guide

The Angular 2 Style Guide.

Angular Team Endorsed

Special thanks to Igor Minar, lead on the Angular team, for reviewing, contributing feedback, and entrusting me to shepherd this guide.

Purpose

Opinionated Angular style guide for teams by @john_papa

If you are looking for an opinionated style guide for syntax, conventions, and structuring Angular applications, then step right in. These styles are based on my development experience with Angular, presentations, Pluralsight training courses and working in teams.

The purpose of this style guide is to provide guidance on building Angular applications by showing the conventions I use and, more importantly, why I choose them.

If you like this guide, check out my Angular Patterns: Clean Code course at Pluralsight which is a companion to this guide.

Angular Patterns: Clean Code

Community Awesomeness and Credit

Never work in a vacuum. I find that the Angular community is an incredible group who are passionate about sharing experiences. Many of my styles have been from the many pair programming sessions Ward Bell and I have had. My most excellent friend Ward has helped influence the ultimate evolution of these guides.

Contributing

Open an issue first to discuss potential changes/additions. If you have questions with the guide, feel free to leave them as issues in the repository. If you find a typo, create a pull request. The idea is to keep the content up to date and use github’s native feature to help tell the story with issues and PR’s, which are all searchable via google. Why? Because odds are if you have a question, someone else does too! You can learn more here at about how to contribute.

By contributing to this repository you are agreeing to make your content available subject to the license of this repository.

Process

1. Discuss the changes in a GitHub issue.
2. Open a Pull Request, reference the issue, and explain the change and why it adds value.
3. The Pull Request will be evaluated and either merged or declined.

License

tldr; Use this guide. Attributions are appreciated.

Copyright

Copyright (c) 2014-2016 John Papa

(The MIT License)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Back to top

angular-styleguide's People

Contributors

7upcat avatar albertoimpl avatar angelochiello avatar bensinther avatar binggg avatar bogatinov avatar ccschmitz avatar djyde avatar ericlemerdy avatar ewertoncodes avatar gaboesquivel avatar ingilniero avatar irvandoval avatar jedgell avatar jlcarvalho avatar jodytate avatar johnpapa avatar lucious7 avatar mazhekin avatar michaelbazos avatar noritamago avatar prayagverma avatar richardlitt avatar robertd avatar tomoyukikashiro avatar vinicius-sabadim avatar vinicius33 avatar wardbell avatar zachlysobey avatar zirho avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

angular-styleguide's Issues

Bindable members up top issue

As per the example:

  /* recommended */
  function Sessions() {
    var vm = this;

    vm.gotoSession = gotoSession;
    vm.refresh = refresh;
    vm.search = search;
    vm.sessions = [];
    vm.title = 'Sessions';

    ////////////

    function gotoSession() {
      /* */
    }

    function refresh() {
      /* */
    }

    function search() {
      /* */
    }
  }

You will get jshint errors like:

^ 'gotoSession' was used before it was defined.
^ 'refresh' was used before it was defined.
^ 'search' was used before it was defined.

Factory vs Service

I know the subject has been beaten to death, and I might be thick.
I've read this http://stackoverflow.com/questions/13762228/confused-about-service-vs-factory/13763886#13763886 and this http://stackoverflow.com/a/15666049

I still don't understand in which situation you should use one instead of the other. Since both returning a singleton, why not just pick the one you prefer (either Factory or Service) and exclusively use that one?

Why did the angularjs team feel it was necessary to support both ways?

Filters?

Should there be a section on filters?

Add promises

Style guide tips for using promises, both wrapped in angular services and using $q

DataService Ravioli

how did I forget to add a data service example!?!? using $http and a promise

How to layout vm values that need calculations?

For example see this gist here: https://gist.github.com/Siyfion/4783b72942f89ef2a805

The view model variable labelCountOptions and stockLabels both need to be calculated. Somehow doing them inline in the definition list seems messy and makes the controllers vm property list harder to skim-read. However, doing them where I've done them now doesn't seem quite right either...

The only other option I can see would be to create functions to initialize them, ie.

    vm.cancel = cancel;
    vm.filterInfo = {
      text: '',
      labelCount: ''
    };
    vm.labelCountOptions = calculateCountOptions();  // For example
    vm.user = AuthenticationService.getUser();
    vm.userLabels = labels;
    vm.selectLabel = selectLabel;
    vm.stockLabels = [];

    //////////////////////

    function calculateCountOptions () {
      return _.chain(vm.userLabels)
        .uniq('labelsPerSheet')
        .map('labelsPerSheet')
        .sort(function(a, b) {
          return a - b;
        })
        .value();
    }

Modularity section

How do you generally split the code to modules to prevent code duplication?

I've made an Angular module that adds support for class extensibility (angular-class-extender), but I'd love to hear more suggestions!!

Vendors

I would like to propose adding that you should make all libraries injectable for testability and consistency. For example, if you use momentjs, don't rely on the global exposure of the moment variable, instead, register it as a constant and inject it anywhere it's used. (Especially since moment in particular will be depricating the global variable in an upcoming release).

Prototyping providers

Rather than place all provider (e.g. service, controller, etc) code in the constructor method, it can be more readable, result in better generated API documentation (e.g. using jsdoc) and is generally more performant to use prototypes over closures.

Example of this is below.

This may seem picky, but as this is a guide on good practice I think this deserves consideration. :)

Controller:

// foo-controller.js

/**
 * @constructor
 * @ngInject
 * @param {angular.Window} $window
 */
var FooController = function($window)
{
   /**
    * @type {angular.Window}
    * @private
    */
    this.window_ = $window;

    /**
     * @type {String}
     */
    this.alertMessage = '';
};

/**
 * Contrived example of a controller method...
 */
FooController.prototype.alert = function()
{
    this.window_.alert(
        this.alertMessage
    );
};
// foo-module.js

// Method of loading FooController is omitted. Use RequireJS, Browserify, Google Closure, etc...

angular.module('foo', [])
    .controller('FooController', FooController);
<!-- 
    foo.html 

    Assume this has been loaded using `FooController as foo` syntax.
-->

<input type="text" data-ng-model="foo.alertMessage" />

<button type="button" data-ng-click="foo.alert()">
    Alert!
</button>

If you agree, then I'd be happy to put a PR in to update the existing docs, plus add in examples for anything that's missing (e.g. directives).

[Q] The mechanics of the Rule of 1

I'm not questioning the "Rule of 1", as you aptly put it. Rather, I've always tried to use the approach you suggest in my angular projects and struggled with it.. so, here's the question:

As you recommend, separating over multiple files:

// app.module.js
angular
    .module('app', ['ngRoute']);

// someController.js
angular
    .module('app')
    .controller('SomeController' , SomeController);
function SomeController() { }

// someFactory.js
angular
    .module('app')
    .factory('someFactory' , someFactory);

function someFactory() { }

But, doesn't this make all the parts less transportable/reusable?
The name of the app module ("app", in this case) now appears in all of the files, and if I wanted to reuse some of these components in a different project (where, to give in to our wildest side, we decided NOT to name the app module "app") I'd have to go on a hunt...

Am I silly in thinking of re-using Controllers in a different app?
Or should we look for a better organization?
For instance.. assuming we load the files in the right order (someController.js, someFactory.js before app.module.js), could we push the registrations into the app module file?
Should we?

// app.module.js
angular
    .module('app', ['ngRoute'])
.controller('SomeController', SomeController)
.factory('SomeFactory', SomeFactory);

// someController.js
function SomeController() { }

// someFactory.js
function someFactory() { }

Question: How to inject from resolve after refactoring to follow style guide

Thanks for the style guide. I really like it overall and have been busy refactoring.
I have run across an issue using ui-router resolve and the different $inject syntax.

here is my state definition (using ui-router). No change to this (except "as vm"):

{
state: 'sample',
config: {
templateUrl: 'app/sample/templates/sample.html',
controller: 'Sample as vm',
resolve: {
sampleService: 'sampleService',
sampleItem: function ($stateParams, sampleService) {
return sampleService.getItem($stateParams.id).$promise;
}
}
}
}

I refactored the controller from this:

var sampleController = sampleModule.controller('sampleController',
function ($location, $scope, $state, $stateParams, sampleService, sampleItem)
{
...
}

To this:

(function () {
'use strict';

angular
    .module('sampleModule')
    .controller('sampleController', sampleController);

sampleController.$inject = ['$location', '$scope', '$state', '$stateParams', 'sampleService'];

function sampleController($location, $scope, $state, $stateParams, sampleService, sampleItem) {
   .....
}

But sampleItem is always null now (even though I can see through the $state.$current that the sampleItem object has been resolved.

Is there a way to inject it as a parameter as it was done previously?
looks like something missing from here:
sampleController.$inject = ['$location', '$scope', '$state', '$stateParams', 'sampleService', ??????];

Controller as 'vm'

Hi John,

I'm not seeing the benefits of declaring 'ExampleCtrl as vm'. What is the intention by prefixing all template bindings with the same prefix, although their origin differs from each other ?

What do you think about declaring it semantically useful like 'ExampleCtrl as example' ? This way I can quickly identify the controller in use for the current html template just by looking at it. (Useful for example when maintaining multiple views and their respective controllers in multiple tabs).

Performance

Include watchers, bindonce, templatecache, and a slew of other fun stuff

Service injection in the routeProvider

In this example from the doc, is the injection of movieService in the resolve minification safe?

// route-config.js
angular
  .module('app')
  .config(config);

function config ($routeProvider) {
  $routeProvider
    .when('/avengers', {
      templateUrl: 'avengers.html',
      controller: 'Avengers',
      controllerAs: 'vm',
      resolve: {
        moviesPrepService: function (movieService) {
            return movieService.getMovies();
        }
      }
    });
}

Best practice for injecting providers?

Hi,

My excuses if I missed it, but how do you inject for exemple $http into a service/factory definition?

edit: to expand, should it be done like this?

// service

angular
    .module('app')
    .service('logger',[ '$http', '$sce', logger]);

function logger ($http, $sce) {
  this.logError = function (msg) {
    /* */
  };
}

[Question] Thoughts on multiple apps on same page

Not sure if this is something that needs to be added into the style guide or not, or whether this is just a general question, so apologises if this is the latter.

What are your thoughts on doing this:

http://stackoverflow.com/questions/24867578/multiple-apps-and-controllers-in-the-same-file/24867989#24867989

The reason that this has come up for us is that we are using Angular within SharePoint WebParts. This is working really well for us, until we need to add two webparts to the same page. Since angular will only bootstrap the first app that it finds, we have had to workaround the initial bootstrap and do this manually. While this works, it has a slight "smell" to it, and wondered what your thoughts are on this.

If it is frowned upon, do you have any suggestions for a better approach?

Best way to handle a global actions bar?

Each view is a form. And the save and other action buttons are on top and is same everywhere. What will be the best approach for this?
A global directive for the action buttons and passing a method param to the directive?

Thanks in advance

ngAnnotate - ngInject not required in example...

In the ngAnnotate example below, I thought I'd just point out that the /* @ngInject */ isn't actually required in this specific instance.

angular
  .module('app')
  .controller('Avengers', Avengers);

/* @ngInject */
function Avengers (storageService, avengerService) {
  var vm = this;
  vm.heroSearch = '';
  vm.storeHero = storeHero;

  function storeHero(){
    var hero = avengerService.find(vm.heroSearch);
    storageService.save(hero.name, hero);
  }
}

Using Javascript strict mode

I know this is more of a general Javascript best practice, but having 'use strict;' in the IIFE template in the guide can help people avoid a lot of headaches (especially if they weren't aware of strict mode yet).

I also do things of the form:

(function(global){
   'use strict';
 ...
})(this);

To temper my usage of the global namespace except when necessary.

Why IIFE

Hi,
why do we need IIFE if each file only contains one function ?

(function () {
    angular
        .module('app')
        .factory('logger', logger);

    function logger () { }
})();

Isn't this enough ?

/* Global var anyway*/
angular
    .module('app')
    .factory('logger', logger);

/* The rest of the code is in this function */
function logger () { }

Routing

guidelines for creating routing structures

how to call $scope.$broadcast when use vm=this?

TypeError: vm.$broadcast is not a function

when publishing and subscribing events using $emit, $broadcast, or $on consider moving these uses to a factory and invoke from the controller.

is there an example?

Using controllerAs in isolate scope directive

I want to bind scope max in vm. Here is sample code.

var directive = {
    restrict: 'EA',
    templateUrl: 'example.html',
    scope: {
        max: '='
    },
    controller : function($scope){
        var vm = this;
        vm.max = $scope.max; //is it true ? I want to show max value in example.html
    },
    controllerAs: 'vm'
}

introduce IIFE from the very beginning

Your note about IIFE deserves to be introduced from the very beginning, IMHO. It could be the first bullet in the existing Modules section, or, why not, perhaps even introduce a first "Basics" section where general/common patterns like this could be included.

Missing Commas in Modules

I noticed a few missing Commas in the Modules Section. Thank you for creating this awesome guide.

/* avoid */
var app = angular.module('app', [
    'ngAnimate',
    'ngRoute',
    'app.shared', // Add comma here
    'app.dashboard'
]);
/* recommended */
angular
    .module('app', [
    'ngAnimate',
    'ngRoute',
    'app.shared', // Add comma here
    'app.dashboard'
]);

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.