Author Archives: admin

Facebook SDK API

Fuente: https://developers.facebook.com/docs/javascript/quickstart/v2.3

Quickstart: Facebook SDK for JavaScript

The Facebook SDK for JavaScript provides a rich set of client-side functionality that:

  • Enables you to use the Like Button and other Social Plugins on your site.
  • Enables you to use Facebook Login to lower the barrier for people to sign up on your site.
  • Makes it easy to call into Facebook’s Graph API.
  • Launch Dialogs that let people perform various actions like sharing stories.
  • Facilitates communication when you’re building a game or an app tab on Facebook.

The SDK, social plugins and dialogs work on both desktop and mobile web browsers.

This quickstart will show you how to setup the SDK and get it to make some basic Graph API calls. If you don’t want to setup just yet, you can use our JavaScript test console to use all of the SDK methods, and explore some examples (you can skip the setup steps, but the rest of this quickstart can be tested in the console).

Basic Setup

The Facebook SDK for JavaScript doesn’t have any standalone files that need to be downloaded or installed, instead you simply need to include a short piece of regular JavaScript in your HTML that will asynchronously load the SDK into your pages. The async load means that it does not block loading other elements of your page.

The following snippet of code will give the basic version of the SDK where the options are set to their most common defaults. You should insert it directly after the opening <body> tag on each page you want to load it:

    <script>
      window.fbAsyncInit = function() {
        FB.init({
          appId      : 'your-app-id',
          xfbml      : true,
          version    : 'v2.3'
        });
      };

      (function(d, s, id){
         var js, fjs = d.getElementsByTagName(s)[0];
         if (d.getElementById(id)) {return;}
         js = d.createElement(s); js.id = id;
         js.src = "//connect.facebook.net/en_US/sdk.js";
         fjs.parentNode.insertBefore(js, fjs);
       }(document, 'script', 'facebook-jssdk'));
    </script>

This code will load and initialize the SDK. You must replace the value in your-app-id with the ID of your own Facebook App. You can find this ID using the App Dashboard.

Advanced Setup

As mentioned, the code above uses the common defaults for the options available when initializing the SDK. You can customize some of these options, if useful.

Changing SDK Language

In the basic setup snippet, the en_US version of the SDK is initialized, which means that all of the Facebook-generated buttons and plugins used on your site will be in US English. (However, pop-up dialogs generated by Facebook like the Login Dialog will be in the language the person has chosen on Facebook, even if they differ from what you’ve selected.) You can change this language by changing the js.src value in the snippet. Take a look at Localization to see the different locales that can be used. For example, if your site is in Spanish, using the following code to load the SDK will cause all Social Plugins to be rendered in Spanish.

    <script>
      (function(d, s, id){
         var js, fjs = d.getElementsByTagName(s)[0];
         if (d.getElementById(id)) return;
         js = d.createElement(s); js.id = id;
         js.src = "//connect.facebook.net/es_LA/sdk.js";
         fjs.parentNode.insertBefore(js, fjs);
       }(document, 'script', 'facebook-jssdk'));
    </script> 

Login Status Check

If you set status to true in the FB.init() call, the SDK will attempt to get info about the current user immediately after init. Doing this can reduce the time it takes to check for the state of a logged in user if you’re using Facebook Login, but isn’t useful for pages that only have social plugins on them.

You can use FB.getLoginStatus to get a person’s login state. Read on for more about using Facebook Login with the JavaScript SDK.

Disabling XFBML Parsing

With xfbml set to true, the SDK will parse your page’s DOM to find and initialize any social plugins that have been added using XFBML. If you’re not using social plugins on the page, setting xfbml to false will improve page load times. You can find out more about this by looking at Social Plugins.

Triggering Code when the SDK loads

The function assigned to window.fbAsyncInit is run as soon as the SDK has completed loading. Any code that you want to run after the SDK is loaded should be placed within this function and after the call to FB.init. Any kind of JavaScript can be used here, but any SDK functions must be called afterFB.init.

Debugging

To improve performance, the JavaScript SDK is loaded minified. You can also load a debug version of the JavaScript SDK that includes more logging and stricter argument checking as well as being non-minified. To do so, change the js.src value in your loading code to this:

js.src = "//connect.facebook.net/en_US/sdk/debug.js";

More Initialization Options

The reference doc for the FB.init function provides a full list of available initialization options.

Using the SDK to add Social Plugins

Now that you’ve got the SDK setup, we can use it to perform a few common tasks. Social Plugins such as the Like Button and Comments Plugin can be inserted into HTML pages using the JavaScript SDK.

Let’s try adding a Like button, just copy and paste the line of code below anywhere inside the <body> of your page:

<div
  class="fb-like"
  data-send="true"
  data-width="450"
  data-show-faces="true">
</div>

Reload your page, and you should see a Like button on it.

Using the SDK to trigger a Share dialog

The Share Dialog allows someone using a page to post a link to their timeline, or create an Open Graph story. Dialogs displayed using the JavaScript SDK are automatically formatted for the context in which they are loaded – mobile web, or desktop web.

Here we’ll show you how the FB.ui() method of the SDK can be used to invoke a really basic Share dialog. Add this snippet after the FB.init() call in the basic setup code:

FB.ui(
 {
  method: 'share',
  href: 'https://developers.facebook.com/docs/'
}, function(response){});

Now when you reload your page, you’ll see a Share dialog appear over the top of the page. Let’s add a few extra parameters to the FB.ui call in order to make the Share dialog make a more complex call to publish an Open Graph action:

    FB.ui({
     method: 'share_open_graph',
     action_type: 'og.likes',
     action_properties: JSON.stringify({
      object:'https://developers.facebook.com/docs/',
     })
    }, function(response){});

Now when you reload your page, you’ll see a Share dialog again, but this time with a preview of the Open Graph story. Once the dialog has been closed, either by posting the story or by cancelling, the response function will be triggered.

Read the FB.ui reference doc to see a full list of parameters that can be used, and the structure of the response object.

Using the SDK for Facebook Login

Facebook Login allows users to register or sign in to your app with their Facebook identity.

We have a full guide on how to use the JS SDK to implement Facebook Login. But for now, let’s just use some basic sample code, so you can see how it works. Insert the following after your original FB.init call:

FB.getLoginStatus(function(response) {
  if (response.status === 'connected') {
    console.log('Logged in.');
  }
  else {
    FB.login();
  }
});

Read the Login guide to learn exactly what is happening here, but when you reload your page you should be prompted with the Login dialog for you app, if you haven’t already granted it permission.

Using the SDK to call the Graph API

To read or write data to the Graph API, you’ll use the JS SDK’s FB.api() method. The version parameter in the FB.init call is used to determine which Graph API version is used.

We have another quickstart guide for the Graph API, however here we’ll show you how the FB.api() method can publish a story on your behalf.

First, we need to get publish_actions permission in order to make publishing API calls. So add a line after FB.init like this:

FB.login(function(){}, {scope: 'publish_actions'});

This will trigger a login dialog that’ll request the relevant permissions. Next, now that your app can, let’s make the API call to publish. Add the API code into the response function of the FB.login call you added above:

FB.login(function(){
 FB.api('/me/feed', 'post', {message: 'Hello, world!'});
}, {scope: 'publish_actions'});

Now, when you reload your page, you’ll be asked for permissions (if you haven’t granted them already) and then a status message will be posted to your profile:

Congratulations, you’ve learned how to use the JavaScript to perform a number of common tasks. Dig deeper into the guides linked in each section to learn more about specific methods, or other parts of Facebook Platform.
[Fuente : https://developers.facebook.com/docs/facebook-login/login-flow-for-web/v2.3]

Facebook Login for the Web with the JavaScript SDK

Facebook apps can use one of several login flows, depending on the target device and the project. This guide takes you step-by-step through the login flow for web apps. The steps in this guide use Facebook’s JavaScript SDK, which is the recommended method to add Facebook Login to your website.

If for some reason you can’t use our JavaScript SDK you can also implement login without it. We’ve build a separate guide to follow if you need to implement login manually.

Quickstart

Later in this doc we will guide you through the login flow step-by-step and explain each step clearly – this will help you if you are trying to integrate Facebook Login into an existing login system, or just to integrate it with any server-side code you’re running. But before we do that, it’s worth showing how little code is required to implement login in a web application using the JavaScript SDK.

You will need a Facebook App ID before you start using the SDK, which you can create and retrieve on the App Dashboard. You’ll also need somewhere to host HTML files. If you don’t have hosting, you can get set up quickly with Parse.

This code will load and initialize the JavaScript SDK in your HTML page. Use your app ID where indicated.

<!DOCTYPE html>
<html>
<head>
<title>Facebook Login JavaScript Example</title>
<meta charset="UTF-8">
</head>
<body>
<script>
  // This is called with the results from from FB.getLoginStatus().
  function statusChangeCallback(response) {
    console.log('statusChangeCallback');
    console.log(response);
    // The response object is returned with a status field that lets the
    // app know the current login status of the person.
    // Full docs on the response object can be found in the documentation
    // for FB.getLoginStatus().
    if (response.status === 'connected') {
      // Logged into your app and Facebook.
      testAPI();
    } else if (response.status === 'not_authorized') {
      // The person is logged into Facebook, but not your app.
      document.getElementById('status').innerHTML = 'Please log ' +
        'into this app.';
    } else {
      // The person is not logged into Facebook, so we're not sure if
      // they are logged into this app or not.
      document.getElementById('status').innerHTML = 'Please log ' +
        'into Facebook.';
    }
  }

  // This function is called when someone finishes with the Login
  // Button.  See the onlogin handler attached to it in the sample
  // code below.
  function checkLoginState() {
    FB.getLoginStatus(function(response) {
      statusChangeCallback(response);
    });
  }

  window.fbAsyncInit = function() {
  FB.init({
    appId      : '{your-app-id}',
    cookie     : true,  // enable cookies to allow the server to access 
                        // the session
    xfbml      : true,  // parse social plugins on this page
    version    : 'v2.2' // use version 2.2
  });

  // Now that we've initialized the JavaScript SDK, we call 
  // FB.getLoginStatus().  This function gets the state of the
  // person visiting this page and can return one of three states to
  // the callback you provide.  They can be:
  //
  // 1. Logged into your app ('connected')
  // 2. Logged into Facebook, but not your app ('not_authorized')
  // 3. Not logged into Facebook and can't tell if they are logged into
  //    your app or not.
  //
  // These three cases are handled in the callback function.

  FB.getLoginStatus(function(response) {
    statusChangeCallback(response);
  });

  };

  // Load the SDK asynchronously
  (function(d, s, id) {
    var js, fjs = d.getElementsByTagName(s)[0];
    if (d.getElementById(id)) return;
    js = d.createElement(s); js.id = id;
    js.src = "//connect.facebook.net/en_US/sdk.js";
    fjs.parentNode.insertBefore(js, fjs);
  }(document, 'script', 'facebook-jssdk'));

  // Here we run a very simple test of the Graph API after login is
  // successful.  See statusChangeCallback() for when this call is made.
  function testAPI() {
    console.log('Welcome!  Fetching your information.... ');
    FB.api('/me', function(response) {
      console.log('Successful login for: ' + response.name);
      document.getElementById('status').innerHTML =
        'Thanks for logging in, ' + response.name + '!';
    });
  }
</script>

<!--
  Below we include the Login Button social plugin. This button uses
  the JavaScript SDK to present a graphical Login button that triggers
  the FB.login() function when clicked.
-->

<fb:login-button scope="public_profile,email" onlogin="checkLoginState();">
</fb:login-button>

<div id="status">
</div>

</body>
</html>

Now you can test your app by going to the URL where you uploaded this HTML. Open your JavaScript console, and you’ll see the testAPI() function display a message with your name in the console log.

Congratulations, at this stage you’ve actually built a really basic page with Facebook Login. You can use this as the starting point for your own app, but it will be useful to read on and understand what is happening in the code above.
vcx
vcx
vcxv
cxv
cxv
cxv
cxvcx
vcx
vcx
vcx

AngularJS: Modules

[Fuente: https://docs.angularjs.org/guide/module]

What is a Module?

You can think of a module as a container for the different parts of your app – controllers, services, filters, directives, etc.

Why?

Most applications have a main method that instantiates and wires together the different parts of the application.Angular apps don’t have a main method. Instead modules declaratively specify how an application should be bootstrapped. There are several advantages to this approach:

  • The declarative process is easier to understand.
  • You can package code as reusable modules.
  • The modules can be loaded in any order (or even in parallel) because modules delay execution.
  • Unit tests only have to load relevant modules, which keeps them fast.
  • End-to-end tests can use modules to override configuration.

The Basics

I’m in a hurry. How do I get a Hello World module working?

index.html

<div ng-app="myApp">
  <div>
    {{ 'World' | greet }}
  </div>
</div>

scripts.js

// declare a module
var myAppModule = angular.module('myApp', []);

// configure the module.
// in this example we will create a greeting filter
myAppModule.filter('greet', function() {
 return function(name) {
    return 'Hello, ' + name + '!';
  };
});

protractor.js

it('should add Hello to the name', function() {
  expect(element(by.binding("'World' | greet")).getText()).toEqual('Hello, World!');
});

sd
sd
sds
ds
ds
dsd
sd
sd
sds
d
sds
ds
ds
dsd

AngularJS: Directive resolve dependencies

If we want to wait for some server data for directive loading this is the pattern:

angular.module('busuuApp.translations')
    .directive('trs', ['trs','$http', '$q', 'wordbee', function(trs,$http, $q,wordbee,wordbeeStrings) {

  'use strict';

  var translateArgs = function(str) {
    try {
      if (str[0] != '"' && str[0] != "'") {
        return trs.call(null, str);
      } else {
        // Strips the " or ' on the start and end
        // Used to be eval("trs(" + str + ")");
        return trs(str.slice(1, str.length-1));
      }
    } catch (err) {
      $log.error('Reference error, trs directive shouldn\'t have dynamic vars: ' + args);
      throw err;
    }
  };

  //store the data so you don't load it twice.
  var directiveData,
  //declare a variable for you promise.
      dataPromise;

  //set up a promise that will be used to load the data
  function loadData(){

    //if we already have a promise, just return that
    //so it doesn't run twice.
    if(dataPromise) {
      return dataPromise;
    }

    var deferred = $q.defer();
    dataPromise = deferred.promise;

    if(!_.isEmpty(wordbeeStrings)) {
      //if we already have data, return that.
      deferred.resolve(directiveData);
    } else {
      console.log("TRS directive loadlanguage");
      wordbee.loadLanguage(interfaceLanguage)
                  .then(function(data) {
                    directiveData = data;
                    wordbeeStrings = directiveData;
                    _.each(wordbeeStrings, function (val, key) {

                      val = val.replace(/&lt;/g, '<');

                      val = val.replace(/&gt;/g, '>');

                      wordbeeStrings[key] = val;

                    });


                    console.log("trs directive Language loaded!!!");
                    deferred.resolve(directiveData);
                  });
    }
    return dataPromise;
  }

  return {
    restrict: 'EA',
    scope: false,
    link: function(scope, elm, attrs) {
      //load the data, or check if it's loaded and apply it.
      loadData().then(function(data) {
        //success! set your scope values and
        // do whatever dom/plugin stuff you need to do here.
        // an $apply() may be necessary in some cases.
        //console.log("TRS directive --> ",attrs);
        if (attrs.hasOwnProperty('trs')) {
          elm.html(translateArgs(attrs.trs));
        } else {
          // otherwise we use <trs> </trs> syntax
          elm.replaceWith(translateArgs(elm.text()));
        }
      }, function() {
        //failure! update something to show failure.
        // again, $apply() may be necessary.
        scope.data = 'ERROR: failed to load data.';
      });
    }
  };
}]);

AngularJS UI router

[Fuente: https://github.com/angular-ui/ui-router]

The de-facto solution to flexible routing with nested views

AngularUI Router is a routing framework for AngularJS, which allows you to organize the parts of your interface into a state machine. Unlike the $route service in the Angular ngRoute module, which is organized around URL routes, UI-Router is organized around states, which may optionally have routes, as well as other behavior, attached.

States are bound to namednested and parallel views, allowing you to powerfully manage your application’s interface.

Check out the sample app: http://angular-ui.github.io/ui-router/sample/

Note: UI-Router is under active development. As such, while this library is well-tested, the API may change. Consider using it in production applications only if you’re comfortable following a changelog and updating your usage accordingly.

Get Started

(1) Get UI-Router in one of the following ways:

  • clone & build this repository
  • download the release (or minified)
  • via Bower: by running $ bower install angular-ui-router from your console
  • or via npm: by running $ npm install angular-ui-router from your console
  • or via Component: by running $ component install angular-ui/ui-router from your console

(2) Include angular-ui-router.js (or angular-ui-router.min.js) in your index.html, after including Angular itself (For Component users: ignore this step)

(3) Add 'ui.router' to your main module’s list of dependencies (For Component users: replace'ui.router' with require('angular-ui-router'))

When you’re done, your setup should look similar to the following:

<!doctype html>
<html ng-app="myApp">
<head>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.min.js"></script>
    <script src="js/angular-ui-router.min.js"></script>
    <script>
        var myApp = angular.module('myApp', ['ui.router']);
        // For Component users, it should look like this:
        // var myApp = angular.module('myApp', [require('angular-ui-router')]);
    </script>
    ...
</head>
<body>
    ...
</body>
</html>

Nested States & Views

The majority of UI-Router’s power is in its ability to nest states & views.

(1) First, follow the setup instructions detailed above.

(2) Then, add a ui-view directive to the <body /> of your app.

<!-- index.html -->
<body>
    <div ui-view></div>
    <!-- We'll also add some navigation: -->
    <a ui-sref="state1">State 1</a>
    <a ui-sref="state2">State 2</a>
</body>

(3) You’ll notice we also added some links with ui-sref directives. In addition to managing state transitions, this directive auto-generates the href attribute of the <a /> element it’s attached to, if the corresponding state has a URL. Next we’ll add some templates. These will plug into the ui-view within index.html. Notice that they have their own ui-view as well! That is the key to nesting states and views.

<!-- partials/state1.html -->
<h1>State 1</h1>
<hr/>
<a ui-sref="state1.list">Show List</a>
<div ui-view></div>
<!-- partials/state2.html -->
<h1>State 2</h1>
<hr/>
<a ui-sref="state2.list">Show List</a>
<div ui-view></div>

(4) Next, we’ll add some child templates. These will get plugged into the ui-view of their parent state templates.

<!-- partials/state1.list.html -->
<h3>List of State 1 Items</h3>
<ul>
  <li ng-repeat="item in items">{{ item }}</li>
</ul>

5) Finally, we’ll wire it all up with $stateProvider. Set up your states in the module config, as in the following:

myApp.config(function($stateProvider, $urlRouterProvider) {
  //
  // For any unmatched url, redirect to /state1
  $urlRouterProvider.otherwise("/state1");
  //
  // Now set up the states
  $stateProvider
    .state('state1', {
      url: "/state1",
      templateUrl: "partials/state1.html"
    })
    .state('state1.list', {
      url: "/list",
      templateUrl: "partials/state1.list.html",
      controller: function($scope) {
        $scope.items = ["A", "List", "Of", "Items"];
      }
    })
    .state('state2', {
      url: "/state2",
      templateUrl: "partials/state2.html"
    })
    .state('state2.list', {
      url: "/list",
      templateUrl: "partials/state2.list.html",
      controller: function($scope) {
        $scope.things = ["A", "Set", "Of", "Things"];
      }
    });
});

(6) See this quick start example in action.

Go to Quick Start Plunker for Nested States & Views

(7) This only scratches the surface

Dive Deeper!

er
errw
rewr
ewr
ewr
ewr
ewr
ewrew
rew
rwer
ew
rwer
ewr

React: A javascript library for building user interfaces

[Fuente: http://facebook.github.io/react/index.html]

JUST THE UI

Lots of people use React as the V in MVC. Since React makes no assumptions about the rest of your technology stack, it’s easy to try it out on a small feature in an existing project.

VIRTUAL DOM

React uses a virtual DOM diff implementation for ultra-high performance. It can also render on the server using Node.js — no heavy browser DOM required.

DATA FLOW

React implements one-way reactive data flow which reduces boilerplate and is easier to reason about than traditional data binding.

Getting Started

JSFiddle

The easiest way to start hacking on React is using the following JSFiddle Hello World examples:

Starter Kit

Download the starter kit to get started.

In the root directory of the starter kit, create a helloworld.html with the following contents.

<!DOCTYPE html>
<html>
  <head>
    <script src="build/react.js"></script>
    <script src="build/JSXTransformer.js"></script>
  </head>
  <body>
    <div id="example"></div>
    <script type="text/jsx">
      React.render(
        <h1>Hello, world!</h1>,
        document.getElementById('example')
      );
    </script>
  </body>
</html>

The XML syntax inside of JavaScript is called JSX; check out the JSX syntax to learn more about it. In order to translate it to vanilla JavaScript we use <script type="text/jsx"> and include JSXTransformer.js to actually perform the transformation in the browser.

Separate File

Your React JSX code can live in a separate file. Create the following src/helloworld.js.

React.render(
  <h1>Hello, world!</h1>,
  document.getElementById('example')
);

Then reference it from helloworld.html:

<script type="text/jsx" src="src/helloworld.js"></script>

Offline Transform

First install the command-line tools (requires npm):

npm install -g react-tools

Then, translate your src/helloworld.js file to plain JavaScript:

jsx --watch src/ build/

The file build/helloworld.js is autogenerated whenever you make a change.

React.render(
  React.createElement('h1', null, 'Hello, world!'),
  document.getElementById('example')
);

Update your HTML file as below:

<!DOCTYPE html>
<html>
  <head>
    <title>Hello React!</title>
    <script src="build/react.js"></script>
    <!-- No need for JSXTransformer! -->
  </head>
  <body>
    <div id="example"></div>
    <script src="build/helloworld.js"></script>
  </body>
</html>

Want CommonJS?

If you want to use React with browserifywebpack, or another CommonJS-compatible module system, just use the react npm package. In addition, the jsx build tool can be integrated into most packaging systems (not just CommonJS) quite easily.

Next Steps

Check out the tutorial and the other examples in the starter kit’s examples directory to learn more.

We also have a wiki where the community contributes with workflows, UI-components, routing, data management etc.

Good luck, and welcome!

A Simple Component

React components implement a render() method that takes input data and returns what to display. This example uses an XML-like syntax called JSX. Input data that is passed into the component can be accessed by render() via this.props.

JSX is optional and not required to use React. Try clicking on “Compiled JS” to see the raw JavaScript code produced by the JSX compiler.

This code displays “Hello John”:

var HelloMessage = React.createClass({
  render: function() {
    return <div>Hello {this.props.name}</div>;
  }
});

React.render(<HelloMessage name="John" />, mountNode);

A Stateful Component

In addition to taking input data (accessed via this.props), a component can maintain internal state data (accessed via this.state). When a component’s state data changes, the rendered markup will be updated by re-invoking render().

var Timer = React.createClass({
  getInitialState: function() {
    return {secondsElapsed: 0};
  },
  tick: function() {
    this.setState({secondsElapsed: this.state.secondsElapsed + 1});
  },
  componentDidMount: function() {
    this.interval = setInterval(this.tick, 1000);
  },
  componentWillUnmount: function() {
    clearInterval(this.interval);
  },
  render: function() {
    return (
      <div>Seconds Elapsed: {this.state.secondsElapsed}</div>
    );
  }
});

React.render(<Timer />, mountNode);

An Application

Using props and state, we can put together a small Todo application. This example uses state to track the current list of items as well as the text that the user has entered. Although event handlers appear to be rendered inline, they will be collected and implemented using event delegation.

var TodoList = React.createClass({
  render: function() {
    var createItem = function(itemText) {
      return <li>{itemText}</li>;
    };
    return <ul>{this.props.items.map(createItem)}</ul>;
  }
});
var TodoApp = React.createClass({
  getInitialState: function() {
    return {items: [], text: ''};
  },
  onChange: function(e) {
    this.setState({text: e.target.value});
  },
  handleSubmit: function(e) {
    e.preventDefault();
    var nextItems = this.state.items.concat([this.state.text]);
    var nextText = '';
    this.setState({items: nextItems, text: nextText});
  },
  render: function() {
    return (
      <div>
        <h3>TODO</h3>
        <TodoList items={this.state.items} />
        <form onSubmit={this.handleSubmit}>
          <input onChange={this.onChange} value={this.state.text} />
          <button>{'Add #' + (this.state.items.length + 1)}</button>
        </form>
      </div>
    );
  }
});

React.render(<TodoApp />, mountNode);

A Component Using External Plugins

React is flexible and provides hooks that allow you to interface with other libraries and frameworks. This example uses Showdown, an external Markdown library, to convert the textarea’s value in real-time.

var converter = new Showdown.converter();

var MarkdownEditor = React.createClass({
  getInitialState: function() {
    return {value: 'Type some *markdown* here!'};
  },
  handleChange: function() {
    this.setState({value: this.refs.textarea.getDOMNode().value});
  },
  render: function() {
    return (
      <div className="MarkdownEditor">
        <h3>Input</h3>
        <textarea
          onChange={this.handleChange}
          ref="textarea"
          defaultValue={this.state.value} />
        <h3>Output</h3>
        <div
          className="content"
          dangerouslySetInnerHTML={{
            __html: converter.makeHtml(this.state.value)
          }}
        />
      </div>
    );
  }
});

React.render(<MarkdownEditor />, mountNode);

More info

 http://facebook.github.io/react/docs/tutorial.html

http://facebook.github.io/react/docs/getting-started.html

https://facebook.github.io/react/downloads.html

https://github.com/react-bootstrap/react-bootstrap

Cross Site Request Forgery (CSRF)

[Fuente: http://es.wikipedia.org/wiki/Cross_Site_Request_Forgery]

El CSRF (del inglés Cross-site request forgery o falsificación de petición en sitios cruzados) es un tipo de exploit malicioso de un sitio web en el que comandos no autorizados son transmitidos por un usuario en el cual el sitio web confía. Esta vulnerabilidad es conocida también por otros nombres como XSRF, enlace hostil, ataque de un click, cabalgamiento de sesión, y ataque automático.

Ejemplo

Un ejemplo muy clásico se dá cuando un sitio web, llamemoslo “example1.com”, posee un sistema de administración de usuarios. En dicho sistema, cuando un administrador se loguea, y ejecuta el siguiente REQUEST GET, elimina al usuario de ID: “63”:http://example1.com/usuarios/eliminar/63

Una forma de ejecutar la vulnerabilidad CSRF, se daría si otro sitio web, llamemos “example2.com”, en su sitio web añade el siguiente código HTML: <img src="http://example1.com/usuarios/eliminar/63">

Cuando el usuario administrador (logueado en example1.com), navegue por este sitio atacante, su browser intentará buscar una imagen en la URL y al realizarse el REQUEST GET hacia esa URL eliminará al usuario 63.

404 on jquery min map file

If Chrome DevTools is reporting a 404 for a .map file (maybe jquery-1.10.2.min.mapjquery.min.map or jquery-2.0.3.min.map, but can happen with anything) first thing to know is this is only requested when using the DevTools. Your users will not be hitting this 404.

Now you can fix this or disable the sourcemap functionality.

Fix: get the files

Next, it’s an easy fix. Head to http://jquery.com/download/ and click the Download the map filelink for your version, and you’ll want the uncompressed file downloaded as well.

enter image description here

Having the map file in place allows you do debug your minified jQuery via the original sources, which will save a lot of time and frustration if you don’t like dealing with variable names like a andc.

More about sourcemaps here: An Introduction to JavaScript Source Maps

Dodge: disable sourcemaps

Instead of getting the files, you can alternatively disable JavaScript source maps completely for now, in your settings. This is a fine choice if you never plan on debugging JavaScript on this page. Use the cog icon in the bottom right of the DevTools, to open settings, then: enter image description here

Pusher: adding realtime bi-directional functionality via WebSockets to web and mobile apps

[Fuente: https://pusher.com/docs]

Understanding Pusher

Pusher is a simple hosted API for quickly, easily and securely adding realtime bi-directional functionality via WebSockets to web and mobile apps, or any other Internet connected device.

We offer a rich suite of libraries that you can use within your applications, including a JavaScript client library for web and HTML5 apps.

Our event based abstraction makes it simple to bind UI interactions to events that are triggered from any client or server.

We use WebSockets (with fallbacks to Flash and HTTP in the JavaScript client library) to future proof your applications and make it easy for you to add bi-directional communication to your apps whilst keeping data usage to a minimum.

As well as a WebSockets API, we have a REST API for publishing your messages. This is ideally suited to web server technologies and we have a set of REST API libraries in many common languages to help you to do this.

Pusher with bi-directional WebSockets and REST API
 

We have a simple Publish/Subscribe model based on channels that allows you to filter and control how people receive your messages.

We supply functionality such as authentication mechanisms for private channels, and presence functionality for keeping track of who’s online.

We give you tools for debugging your applications, and if you get stuck, you can always get in touch with us for a chat.

Getting Started

To get started check out the JavaScript quick start guide, the Client API Overview or the Server API Overview. Alternatively have a look at some of the examples of Pusher in use, or checkout some of the resources we have collected.

Getting started with Pusher is very easy. However, if you have any questions get in touch.

This guide uses the JavaScript client API and a selection of Server API libraries. We also have a guide for our iOS client.

Get your free API keys

Create an account, and make a note of your app_idapp_key and app_secret.

Include the Pusher Client library

Open a connection to Pusher

You first need to establish a connection to Pusher. This is done by using your application key (app_key).

var pusher = new Pusher('YOUR_APP_KEY');

Subscribe to a Channel

Now you should subscribe to your first channel.

Note: more info on choosing channel names is available here.

var channel = pusher.subscribe('my-channel');

Listen for events on your channel

Now you can define callbacks that bind to events on a channel, coming in via the connection to Pusher:

channel.bind('my-event', function(data) {
  alert('An event was triggered with message: ' + data.message);
});

Trigger events from your server

In the examples below we trigger an event named my-event to Pusher on a channel called my-channel. For each example below a server library deals with the server communication. If there isn’t an example in a language that you are familiar with then have a look on our server libraries page to see if anyone has created one in your language.

require('Pusher.php');

$pusher = new Pusher($key, $secret, $app_id);
$pusher->trigger('my-channel', 'my-event', array('message' => 'hello world') );

Where next?

Find out about all the cool stuff you can do with channels, Investigate the JavaScript client library or learn how toexcluding event recipients when publishing events.

Channels

Channels are a fundamental concept in Pusher. Each application has a number of channels, and every client can choose which channels it connects to.

Channels provide:

  • A way of filtering data. For example, in a chat application there may be a channel for people who want to discuss ‘dogs’
  • A way of controlling access to different streams of information. For example, a project management application would want to authorise people to get updates about ‘secret-projectX’

We strongly recommend that channels are used to filter your data and that it is not achieved using events. This is because all events published to a channel are sent to all subscribers, regardless of their event binding.

Channels don’t need to be explicitly created, and are instantiated on client demand. This means that creating a channel is easy. Just tell a client to subscribe to it.

Channel Types

There are 3 types of channels at the moment:

  • Public channels can be subscribed to by anyone who knows their name
  • Private channels should have a private- prefix. They introduce a mechanism which lets your server control access to the data you are broadcasting
  • Presence channels should have a presence- prefix and are an extension of private channels. They let you ‘register’ user information on subscription, and let other members of the channel know who’s online

Channel Naming Conventions

Channel names may contain a maximum of 164 characters. This limit includes channel prefixes (i.e. private-and presence- are included in the character count).

Channel names should only include lower and uppercase letters, numbers and the following punctuation_ - = @ , . ;

As an example this is a valid channel name:

foo-bar_1234@=,.;

Accessing channels

If a channel has been subscribed to already it is possible to access channels by name, through the pusher.channelfunction:

var channel = pusher.channel(channelName);
  • channelName (String)
    • The name of the channel to retrieve

Debugging Pusher

We offer a number of really useful features that can help you during development and whilst trying to get to the bottom of problems with your application.

Viewing application events in the Pusher Debug Console

The Pusher Debug Console can be found within the Pusher dashboard and can be used to help you understand what’s happening within your Pusher application.

It will initially indicate if you can connect or not – if you can connect you might briefly see a connection warning dialog. If you can’t connect the connection warning dialog will stay visible.

Once you have connected you can check that connections are being opened and closed, subscriptions are being made, channels are becoming occupied and vacated and that messages are being received by our API for your application. This feature can be really handy during development or when trying to troubleshoot why certain features in your application might not be working.

Sending test events using the Event Creator

The Event Creator is a really handy tool that lets you trigger an event on any channel with any event data directly from your Pusher app dashboard. This feature means you can write your client code to subscribe to a channel and consume an event without the need to write any server code to start off with. Or it can simply be used for checking that your client application is behaving as expected.

Enable logging in the Pusher JavaScript library

To make Pusher a bit more chatty about what is coming in via the socket connection, you can turn on debugging before you initialise your Pusher object. The most common use of this feature is to output all the logging from the Pusher library to the browser console as follows:

Pusher.log = function(message) {
  if (window.console && window.console.log) {
    window.console.log(message);
  }
};

This should create output like the following in your browser (Chrome in this example): 

Automated Diagnostics

We have a Pusher Diagnostics application that runs a number of tests related to the runtime environment (the browser) and the features offered by the Pusher JavaScript library. If you still can’t get to the bottom of a problem running the diagnostics and then getting in touch with support is a good next step.

AngularJS : E2E Testing : Protractor

[Fuente: https://github.com/angular/protractor]

Protractor Build Status

Protractor is an end-to-end test framework for AngularJS applications. Protractor is a Node.js program built on top of WebDriverJS. Protractor runs tests against your application running in a real browser, interacting with it as a user would.

Test Like a User

Protractor is built on top of WebDriverJS, which uses native events and browser-specific drivers to interact with your application as a user would.

For AngularJS Apps

Protractor supports Angular-specific locator strategies, which allows you to test Angular-specific elements without any setup effort on your part.

Automatic Waiting

You no longer need to add waits and sleeps to your test. Protractor can automatically execute the next step in your test the moment the webpage finishes pending tasks, so you don’t have to worry about waiting for your test and webpage to sync.

Protractor vs Angular Scenario Runner

The new, preferred end-to-end testing framework is called Protractor. Unlike the Angular scenario runner, Protractor is built on Selenium’s WebDriver, which is an API, written as extensions, for controlling browsers.

WebDriver has extensions for all sorts of different browsers, including the most popular. We gain speed and stability in our tests by developing against true web browsers.

Luckily, Protractor is built atop the Jasmine framework, so we don’t need to learn a new framework in order to use it. We can also install it as a standalone test runner or embed it in our tests as a library.

Use Protractor in a non-AngularJS app

you only need to access the webdriver instance by using browser.driver:

browser.driver.find(by.css('[data-ptor="submit-btn"]'));		

Getting Started

The Protractor documentation for users is located in the protractor/docs folder.

To get set up and running quickly:

Once you are familiar with the tutorial, you’re ready to move on. To modify your environment, see the Protractor Setup docs. To start writing tests, see the Protractor Tests docs.

To better understand how Protractor works with the Selenium WebDriver and Selenium Sever see the reference materials.

Choosing a Framework

Protractor supports three behavior driven development (BDD) test frameworks: Jasmine, Mocha, and Cucumber. These frameworks are based on JavaScript and Node.js and provide the syntax, scaffolding, and reporting tools you will use to write and manage your tests.

Prerequisites

Protractor is a Node.js program. To run, you will need to have Node.js installed. You will download Protractor package using npm, which comes with Node.js. Check the version of Node.js you have by running node --version. It should be greater than v0.10.0.

By default, Protractor uses the Jasmine test framework for its testing interface. This tutorial assumes some familiarity with Jasmine.

This tutorial will set up a test using a local standalone Selenium Server to control browsers. You will need to have theJava Development Kit (JDK) installed to run the standalone Selenium Server. Check this by running java -version from the command line.

Setup

Use npm to install Protractor globally with:

npm install -g protractor

This will install two command line tools, protractor and webdriver-manager. Try running protractor --version to make sure it’s working.

The webdriver-manager is a helper tool to easily get an instance of a Selenium Server running. Use it to download the necessary binaries with:

webdriver-manager update

Now start up a server with:

webdriver-manager start

This will start up a Selenium Server and will output a bunch of info logs. Your Protractor test will send requests to this server to control a local browser. You can see information about the status of the server at http://localhost:4444/wd/hub.

Write a test

Open a new command line or terminal window and create a clean folder for testing.

Protractor needs two files to run, a spec file and a configuration file.

Let’s start with a simple test that navigates to the todo list example in the AngularJS website and adds a new todo item to the list.

Copy the following into todo-spec.js:

describe('angularjs homepage todo list', function() {
  it('should add a todo', function() {
    browser.get('http://www.angularjs.org');

    element(by.model('todoText')).sendKeys('write a protractor test');
    element(by.css('[value="add"]')).click();

    var todoList = element.all(by.repeater('todo in todos'));
    expect(todoList.count()).toEqual(3);
    expect(todoList.get(2).getText()).toEqual('write a protractor test');
  });
});

The describe and it syntax is from the Jasmine frameworkbrowser is a global created by Protractor, which is used for browser-level commands such as navigation with browser.get.

Configuration

Now create the configuration file. Copy the following into conf.js:

exports.config = {
  seleniumAddress: 'http://localhost:4444/wd/hub',
  specs: ['todo-spec.js']
};

This configuration tells Protractor where your test files (specs) are, and where to talk to your Selenium Server (seleniumAddress). It will use the defaults for all other configuration. Chrome is the default browser.

Run the test

Now run the test with:

protractor conf.js

You should see a Chrome browser window open up and navigate to the todo list in the AngularJS page, then close itself (this should be very fast!). The test output should be 1 test, 2 assertions, 0 failures. Congratulations, you’ve run your first Protractor test!

Learn More

Learn more with the Tutorial.

The WebDriver Control Flow

The WebDriverJS API is based on promises, which are managed by a control flow and adapted for Jasmine. A short summary about how Protractor interacts with the control flow is presented below.

Promises and the Control Flow

WebDriverJS (and thus, Protractor) APIs are entirely asynchronous. All functions return promises.

WebDriverJS maintains a queue of pending promises, called the control flow, to keep execution organized. For example, consider this test:

  it('should find an element by text input model', function() {
    browser.get('app/index.html#/form');

    var username = element(by.model('username'));
    username.clear();
    username.sendKeys('Jane Doe');

    var name = element(by.binding('username'));

    expect(name.getText()).toEqual('Jane Doe');

    // Point A
  });

At Point A, none of the tasks have executed yet. The browser.get call is at the front of the control flow queue, and thename.getText() call is at the back. The value of name.getText() at point A is an unresolved promise object.

Protractor Adaptations

Protractor adapts Jasmine so that each spec automatically waits until the control flow is empty before exiting. This means you don’t need to worry about calling runs() and waitsFor() blocks.

Jasmine expectations are also adapted to understand promises. That’s why this line works – the code actually adds an expectation task to the control flow, which will run after the other tasks:

  expect(name.getText()).toEqual('Jane Doe');

Migrating Existing Test Scripts (from Angular Scenario Runner)

ptor = protractor instance

browser().navigateTo(url)

ptor.get(url)

browser().location().url()

ptor.getCurrentUrl()

binding(name)

ptor.findElement(protractor.By.binding(‘{{status}}’)).getText()

input(name).enter(value)

ptor.findElement(protractor.By.input(“user”)).sendKeys(value)

input(name).check()

ptor.findElement(protractor.By.input(“user”)).click();

input(name).select(value)

See Select below.

input(name).val()

ptor.findElement(protractor.By.input(“user”)).getText()

repeater(selector, label).count()

ptor.findElements(protractor.By.repeater(“cat in pets”)).length()

repeater(selector, label).row(index)

ptor.findElements(protractor.By.repeater(“cat in pets”)).row(index)

repeater(selector, label).column(binding)

ptor.findElements(protractor.By.repeater(“cat in pets”)).row(index)..column(binding)

select(name).option(value)

ptor.findElement(protractor.By.id(‘selectId’).click();

ptor.findElement(protractor.By.css(‘option [value=”0”]’’).click();

select(name).options(value1, value2…)

ptor.findElement(protractor.By.id(‘selectId’).click();

ptor.findElement(protractor.By.css(‘option [value=”0”]’’).click();

ptor.findElement(protractor.By.css(‘option [value=”2”]’’).click();

ptor.findElement(protractor.By.css(‘option [value=”4”]’’).click();

element(selector, label)

See WebElement Methods Mentioned Earlier

Plugins de Gulp útiles

AngularJS : Buenas practicas

[Fuente: https://github.com/inavarroreus/angularjs-styleguide]

Single Responsability

  • Cada componente de angular en su fichero

Immediately Invoked Function Expression (IIFE)

  • Envolver los componentes de angular con bloques de Javascript
  • Esto elimina los efectos de ir dejando muchas declaraciones globales que pueden entrar en conflicto
/**
* recommended 
*
* no globals are left behind 
*/

// logger.js
(function() {
    'use strict';

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

    function logger() { }
})();

// storage.js
(function() {
    'use strict';

    angular
        .module('app')
        .factory('storage', storage);

    function storage() { }
})();

Avoid naming collissions

  • Define nombres únicos para los módulos y los submodulos de angular. Con notaciones de puntos

Definitions (aka setters)

  • Para la creación de la aplicación angular y sus componentes evitar crear variables , utiliza la sintaxis de getter / setter:
/* avoid */
var app = angular.module('app');
app.controller('SomeController' , SomeController);

function SomeController() { }
/* recommended */
angular
    .module('app')
    .controller('SomeController' , SomeController);

function SomeController() { }
  • Use angular.module('app', []); to set a module.
  • Use angular.module('app'); to get a module.

Named vs Anonymous Functions

/* avoid */
angular
    .module('app')
    .controller('Dashboard', function() { })
    .factory('logger', function() { });
/* recommended */

// dashboard.js
angular
    .module('app')
    .controller('Dashboard', Dashboard);

function Dashboard() { }
// logger.js
angular
    .module('app')
    .factory('logger', logger);

function logger() { }

controllerAs View Syntax

Es una nueva forma de referenciar el $scope de los controllers. Está pensado sobre para cuando hay varios controllers anidados que no tengas que andar referenciando con $parent

<div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
  Name: <input type="text" ng-model="settings.name"/>
  [ <a href="" ng-click="settings.greet()">greet</a> ]<br/>
  Contact:
  <ul>
    <li ng-repeat="contact in settings.contacts">
      <select ng-model="contact.type">
         <option>phone</option>
         <option>email</option>
      </select>
      <input type="text" ng-model="contact.value"/>
      [ <a href="" ng-click="settings.clearContact(contact)">clear</a>
      | <a href="" ng-click="settings.removeContact(contact)">X</a> ]
    </li>
    <li>[ <a href="" ng-click="settings.addContact()">add</a> ]</li>
 </ul>
</div>
angular.module('controllerAsExample', [])
  .controller('SettingsController1', SettingsController1);

function SettingsController1() {
  this.name = "John Smith";
  this.contacts = [
    {type: 'phone', value: '408 555 1212'},
    {type: 'email', value: 'john.smith@example.org'} ];
}

SettingsController1.prototype.greet = function() {
  alert(this.name);
};

SettingsController1.prototype.addContact = function() {
  this.contacts.push({type: 'email', value: 'yourname@example.org'});
};

SettingsController1.prototype.removeContact = function(contactToRemove) {
 var index = this.contacts.indexOf(contactToRemove);
  this.contacts.splice(index, 1);
};

SettingsController1.prototype.clearContact = function(contact) {
  contact.type = 'phone';
  contact.value = '';
};

controllerAs with vm

Se trata de que cuando se use este tipo de sintaxis no utilicemos this , sino una variable como por ejemplo “vm” , siglas de ViewModel. Esto es por que la palabra clave “this” es contextual , es decir depende del contexto, si por ejemplo se referencia dentro de una función puede ser diferente a si se referencia en otro sitio.

/* avoid */
function Customer() {
    this.name = {};
    this.sendMessage = function() { };
}
/* recommended */
function Customer() {
    var vm = this;
    vm.name = {};
    vm.sendMessage = function() { };
}

Se la puede referenciar dentro de los controladores , por ejemplo en watches:

$scope.$watch('vm.title', function(current, original) {
    $log.info('vm.title was %s', original);
    $log.info('vm.title is now %s', current);
});

Bindable Members Up Top

Poner todos los elementos que sean referenciables al principio del controlador. Que no esten desperdigados por todo el archivo. Y que estén ordenados alfabeticamente.Se gana legibilidad

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

    vm.gotoSession = function() {
      /* ... */
    };
    vm.refresh = function() {
      /* ... */
    };
    vm.search = function() {
      /* ... */
    };
    vm.sessions = [];
    vm.title = 'Sessions';
/* 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() {
      /* */
    }

Function Declarations to Hide Implementation Details

Utilizar pequeñas funciones que escondan los detalles de implementación. Y poner estas funciones al final del componente, dejando al principio las referencias.Tiene que ver con el apartado anterior

/** 
* avoid 
* Using function expressions.
*/
function Avengers(dataservice, logger) {
    var vm = this;
    vm.avengers = [];
    vm.title = 'Avengers';

    var activate = function() {
        return getAvengers().then(function() {
            logger.info('Activated Avengers View');
        });
    }

    var getAvengers = function() {
        return dataservice.getAvengers().then(function(data) {
            vm.avengers = data;
            return vm.avengers;
        });
    }

    vm.getAvengers = getAvengers;

    activate();
}
/*
* recommend
* Using function declarations
* and bindable members up top.
*/
function Avengers(dataservice, logger) {
    var vm = this;
    vm.avengers = [];
    vm.getAvengers = getAvengers;
    vm.title = 'Avengers';

    activate();

    function activate() {
        return getAvengers().then(function() {
            logger.info('Activated Avengers View');
        });
    }

    function getAvengers() {
        return dataservice.getAvengers().then(function(data) {
            vm.avengers = data;
            return vm.avengers;
        });
    }
}

Defer Controller Logic

Se trata de que todo lo que sea lógica de negocio sea deferido a un servicio en vez de ponerlo dentro del controller. De esta forma se puede reutilizar con otros controllers y se le puede hacer pruebas unitarias más facilmente

/* avoid */
function Order($http, $q) {
    var vm = this;
    vm.checkCredit = checkCredit;
    vm.total = 0;

    function checkCredit() { 
        var orderTotal = vm.total;
        return $http.get('api/creditcheck').then(function(data) {
            var remaining = data.remaining;
            return $q.when(!!(remaining > orderTotal));
        });
    };
}
/* recommended */
function Order(creditService) {
    var vm = this;
    vm.checkCredit = checkCredit;
    vm.total = 0;

    function checkCredit() { 
       return creditService.check();
    };
}

Keep Controllers Focused

Definir un controller por vista  , no caer en reutilizar el mismo controller para varias vistas. Si hay código común , definirlos dentro de servicios o de factorias. Así es más fácil hacer pruebas e2e

Assigning Controllers

Cuando tenemos que el mapeo de vistas/controllers con rutas puede ser dinámico y hay algunos controllers/views que claramente pueden ser compartidos con distintas rutas , entonces es mejor hacer routing en la configuración de angular. Si ponemos el controller en la vista con ng-controller esa vista siempre estará asociada a ese controller.

/* avoid - when using with a route and dynamic pairing is desired */

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

function config($routeProvider) {
    $routeProvider
        .when('/avengers', {
          templateUrl: 'avengers.html'
        });
}
<!-- avengers.html -->
<div ng-controller="Avengers as vm">
</div>
/* recommended */

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

function config($routeProvider) {
    $routeProvider
        .when('/avengers', {
            templateUrl: 'avengers.html',
            controller: 'Avengers',
            controllerAs: 'vm'
        });
}
<!-- avengers.html -->
<div>
</div>

Services – Singletons

Tanto los servicios , como los factories son singletons (Singletons – Each component dependent on a service gets a reference to the single instance generated by the service factory.).

Como los services se referencian con new y los factories no , es mejor utilizar factories por consistencia. De hecho en la web de angular ya se refieren a los servicios como factories (https://docs.angularjs.org/guide/services)

Factories – Accessible Members Up Top

Poner los elementos accesibles del servicio al principio de la factory, con los beneficios de legibilidad que ello tiene.Se sigue el patrón http://addyosmani.com/resources/essentialjsdesignpatterns/book/#revealingmodulepatternjavascript

/* avoid */
function dataService() {
  var someValue = '';
  function save() { 
    /* */
  };
  function validate() { 
    /* */
  };

  return {
      save: save,
      someValue: someValue,
      validate: validate
  };
}
/* recommended */
function dataService() {
    var someValue = '';
    var service = {
        save: save,
        someValue: someValue,
        validate: validate
    };
    return service;

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

    function save() { 
        /* */
    };

    function validate() { 
        /* */
    };
}

Data Service : Separate Data Calls

Esconder la lógica de acceso a datos , de llamadas a servicios , etc separadas de la lógica de negocio/presentación de los controllers.

/* recommended */

// dataservice factory
angular
    .module('app.core')
    .factory('dataservice', dataservice);

dataservice.$inject = ['$http', 'logger'];

function dataservice($http, logger) {
    return {
        getAvengers: getAvengers
    };

    function getAvengers() {
        return $http.get('/api/maa')
            .then(getAvengersComplete)
            .catch(getAvengersFailed);

        function getAvengersComplete(response) {
            return response.data.results;
        }

        function getAvengersFailed(error) {
            logger.error('XHR Failed for getAvengers.' + error.data);
        }
    }
}
/* recommended */

// controller calling the dataservice factory
angular
    .module('app.avengers')
    .controller('Avengers', Avengers);

Avengers.$inject = ['dataservice', 'logger'];

function Avengers(dataservice, logger) {
    var vm = this;
    vm.avengers = [];

    activate();

    function activate() {
        return getAvengers().then(function() {
            logger.info('Activated Avengers View');
        });
    }

    function getAvengers() {
        return dataservice.getAvengers()
            .then(function(data) {
                vm.avengers = data;
                return vm.avengers;
            });
    }
}

Data Service:Return a Promise from Data Calls

Esto trata de que cuando llamas a un método de un servicio que retorna una promesa, entonces lo suyo es que la función en la que estás retorne también una promesa. De esta forma es más fácil encadenar promesas para realizar acciones a posteriori.

* recommended */

activate();

function activate() {
    /**
     * Step 1
     * Ask the getAvengers function for the
     * avenger data and wait for the promise
     */
    return getAvengers().then(function() {
        /**
         * Step 4
         * Perform an action on resolve of final promise
         */
        logger.info('Activated Avengers View');
    });
}

function getAvengers() {
      /**
       * Step 2
       * Ask the data service for the data and wait
       * for the promise
       */
      return dataservice.getAvengers()
          .then(function(data) {
              /**
               * Step 3
               * set the data and resolve the promise
               */
              vm.avengers = data;
              return vm.avengers;
      });
}

Directives: Limit 1 Per File

Es más fácil de mantener y de reutilizar

Directives: Limit DOM Manipulation

Para manipular el DOM se utilizan directivas pero hay que limitar estas manipulaciones porque son dificiles de testear y depurar.

A menudo hay alternativas , como el utlizar ngShow / ngHide, angular Templating , utilizar CSS o los  animation services

Directives: Provide a Unique Directive Prefix

  • Dales a las directivas prefijos únicos y descriptivos. Por ejemplo:

    acmeSalesCustomerInfo which is declared in HTML as acme-sales-customer-info.

  • Why?: Con prefijos únicos se identifica el contexto de la directiva tanto como su origen. Por ejemplo el prefijo cc- puede indicar que la directiva es parte de la app CodeCamper mientras que el prefijo acme- puede indicar que la directiva es de la compañia Acme.
  • Note: No utilices ng- porque es el prefijo reservado para las directivas de Angular. 

Directives: Restrict to Elements and Attributes

  • A la hora de crear directivas es mejor crearlas como elementos autocontenidos, es decir poner en el restrict E (custom element) o A (custom attribute).
  • Cuando la directiva tiene su propio control es más apropiado definirlo como E.
  • Desde Angular 1.3+ el por defecto es EA.

Directives and ControllerAs

  • Para controllers de directivas utiliza la sintaxis controller as
  • Note: The directive below demonstrates some of the ways you can use scope inside of link and directive controllers, using controllerAs. I in-lined the template just to keep it all in one place.Note: Regarding dependency injection, see Manually Identify Dependencies.
    <div my-example max="77"></div>
    angular
        .module('app')
        .directive('myExample', myExample);
    
    function myExample() {
        var directive = {
            restrict: 'EA',
            templateUrl: 'app/feature/example.directive.html',
            scope: {
                max: '='
            },
            link: linkFunc,
            controller : ExampleController,
            controllerAs: 'vm'
        };
        return directive;
    
        ExampleController.$inject = ['$scope'];
        function ExampleController($scope) {
            // Injecting $scope just for comparison
            /* jshint validthis:true */
            var vm = this;
    
            vm.min = 3; 
            vm.max = $scope.max; 
            console.log('CTRL: $scope.max = %i', $scope.max);
            console.log('CTRL: vm.min = %i', vm.min);
            console.log('CTRL: vm.max = %i', vm.max);
        }
    
        function linkFunc(scope, el, attr, ctrl) {
            console.log('LINK: scope.max = %i', scope.max);
            console.log('LINK: scope.vm.min = %i', scope.vm.min);
            console.log('LINK: scope.vm.max = %i', scope.vm.max);
        }
    }
    /* example.directive.html */
    <div>hello world</div>
    <div>max={{vm.max}}<input ng-model="vm.max"/></div>
    <div>min={{vm.min}}<input ng-model="vm.min"/></div>

Resolving Promises for a Controller

Controller Activation Promises

  • Se trata de poner la lógica de arranque del controlador en una función activate
  • Why?: Haciendolo de esta forma se hace más fácil de localizar donde empieza a ejecutar el controlador, es más consistente para el testeo, y ayuda para no  esparcir la lógica de activación a lo largo del código del controller.
  • Note: If you need to conditionally cancel the route before you start use the controller, use a route resolve instead.
  • /* avoid */
    function Avengers(dataservice) {
        var vm = this;
        vm.avengers = [];
        vm.title = 'Avengers';
    
        dataservice.getAvengers().then(function(data) {
            vm.avengers = data;
            return vm.avengers;
        });
    }
    /* recommended */
    function Avengers(dataservice) {
        var vm = this;
        vm.avengers = [];
        vm.title = 'Avengers';
    
        activate();
    
        ////////////
    
        function activate() {
            return dataservice.getAvengers().then(function(data) {
                vm.avengers = data;
                return vm.avengers;
            });
        }
    }

Route Resolve Promises

  • Cuando un controller depende de que una promise sea resuelta, es mejor poner esta dependencia utilizando la propiedad resolve del $routeProvider antes de que la lógica del controller se ejecute. Si necesitas condicionalmente cancelar una ruta antes de que el controlador sea activado , utiliza el route resolver.
  • Why?: A controller may require data before it loads. That data may come from a promise via a custom factory or $http. Using a route resolve allows the promise to resolve before the controller logic executes, so it might take action based on that data from the promise.
    /* avoid */
    angular
        .module('app')
        .controller('Avengers', Avengers);
    
    function Avengers(movieService) {
        var vm = this;
        // unresolved
        vm.movies;
        // resolved asynchronously
        movieService.getMovies().then(function(response) {
            vm.movies = response.movies;
        });
    }
    /* better */
    
    // 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();
                    }
                }
            });
    }
    
    // avengers.js
    angular
        .module('app')
        .controller('Avengers', Avengers);
    
    Avengers.$inject = ['moviesPrepService'];
    function Avengers(moviesPrepService) {
          /* jshint validthis:true */
          var vm = this;
          vm.movies = moviesPrepService.movies;
    }

    Note: The code example’s dependency on movieService is not minification safe on its own. For details on how to make this code minification safe, see the sections on dependency injection and on minification and annotation.

Manual Annotating for Dependency Injection

UnSafe from Minification

  • Elimina utilizar abreviaturas a la hora de declarar dependencias sin utilizar alguna forma de minification-safe.
  • Why?: The parameters to the component (e.g. controller, factory, etc) will be converted to mangled variables. For example, common and dataservice may become a or b and not be found by AngularJS.
    /* avoid - not minification-safe*/
    angular
        .module('app')
        .controller('Dashboard', Dashboard);
    
    function Dashboard(common, dataservice) {
    }

    This code may produce mangled variables when minified and thus cause runtime errors.

    /* avoid - not minification-safe*/
    angular.module('app').controller('Dashboard', d);function d(a, b) { }

Manually Identify Dependencies

  • Utiliza $inject para manualmente identificar tus dependencias de los componentes de  AngularJS.Why?: This technique mirrors the technique used by ng-annotate, which I recommend for automating the creation of minification safe dependencies. If ng-annotate detects injection has already been made, it will not duplicate it.Why?: This safeguards your dependencies from being vulnerable to minification issues when parameters may be mangled. For example, common and dataservice may become a or b and not be found by AngularJS.Why?: Avoid creating in-line dependencies as long lists can be difficult to read in the array. Also it can be confusing that the array is a series of strings while the last item is the component’s function.
    /* avoid */
    angular
        .module('app')
        .controller('Dashboard', 
            ['$location', '$routeParams', 'common', 'dataservice', 
                function Dashboard($location, $routeParams, common, dataservice) {}
            ]);
    /* avoid */
    angular
      .module('app')
      .controller('Dashboard', 
         ['$location', '$routeParams', 'common', 'dataservice', Dashboard]);
    
    function Dashboard($location, $routeParams, common, dataservice) {
    }
    /* recommended */
    angular
        .module('app')
        .controller('Dashboard', Dashboard);
    
    Dashboard.$inject = ['$location', '$routeParams', 'common', 'dataservice'];
    
    function Dashboard($location, $routeParams, common, dataservice) {
    }

    Note: When your function is below a return statement the $inject may be unreachable (this may happen in a directive). You can solve this by either moving the $inject above the return statement or by using the alternate array injection syntax.

    Note: ng-annotate 0.10.0 introduced a feature where it moves the $inject to where it is reachable.

    // inside a directive definition
    function outer() {
        return {
            controller: DashboardPanel,
        };
    
        DashboardPanel.$inject = ['logger']; // Unreachable
        function DashboardPanel(logger) {
        }
    }
    // inside a directive definition
    function outer() {
        DashboardPanel.$inject = ['logger']; // reachable
        return {
            controller: DashboardPanel,
        };
    
        function DashboardPanel(logger) {
        }
    }

Manually Identify Route Resolver Dependencies

  • Utiliza $inject para manualmente identificar tus dependecias de componentes Angular en el route resolver.Why?: This technique breaks out the anonymous function for the route resolver, making it easier to read.Why?: An $inject statement can easily precede the resolver to handle making any dependencies minification safe.
    /* recommended */
    function config($routeProvider) {
        $routeProvider
            .when('/avengers', {
                templateUrl: 'avengers.html',
                controller: 'Avengers',
                controllerAs: 'vm',
                resolve: {
                    moviesPrepService: moviePrepService
                }
            });
    }
    
    moviePrepService.$inject =  ['movieService'];
    function moviePrepService(movieService) {
        return movieService.getMovies();
    }

Minification and Annotation

ng-annotate

  • Utilizar la herramienta

    ng-annotate como plugin de Gulp o Grunt para comentar funciones que necesiten inyección de dependencias y que las automatizen. Utilizando /** @ngInject */

  • Why?: This safeguards your code from any dependencies that may not be using minification-safe practices.Why?ng-min is deprecated

    I prefer Gulp as I feel it is easier to write, to read, and to debug.

    The following code is not using minification safe dependencies.

    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);
        }
    }

    When the above code is run through ng-annotate it will produce the following output with the$inject annotation and become minification-safe.

    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);
        }
    }
    
    Avengers.$inject = ['storageService', 'avengerService'];

    Note: If ng-annotate detects injection has already been made (e.g. @ngInject was detected), it will not duplicate the $inject code.

    Note: When using a route resolver you can prefix the resolver’s function with /* @ngInject */and it will produce properly annotated code, keeping any injected dependencies minification safe.

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

    Note: Starting from AngularJS 1.3 use the ngApp directive’s ngStrictDi parameter. When present the injector will be created in “strict-di” mode causing the application to fail to invoke functions which do not use explicit function annotation (these may not be minification safe). Debugging info will be logged to the console to help track down the offending code.<body ng-app="APP" ng-strict-di>

Use Gulp or Grunt for ng-annotate

  • Utiliza gulp-ng-annotate o grunt-ng-annotate para meterlo como una tarea automatizada de build. Inject /* @ngInject */prior to any function that has dependencies.Why?: ng-annotate will catch most dependencies, but it sometimes requires hints using the /* @ngInject */ syntax.The following code is an example of a gulp task using ngAnnotate
    gulp.task('js', ['jshint'], function() {
        var source = pkg.paths.js;
        return gulp.src(source)
            .pipe(sourcemaps.init())
            .pipe(concat('all.min.js', {newLine: ';'}))
            // Annotate before uglify so the code get's min'd properly.
            .pipe(ngAnnotate({
                // true helps add where @ngInject is not used. It infers.
                // Doesn't work with resolve, so we must be explicit there
                add: true
            }))
            .pipe(bytediff.start())
            .pipe(uglify({mangle: true}))
            .pipe(bytediff.stop())
            .pipe(sourcemaps.write('./'))
            .pipe(gulp.dest(pkg.paths.dev));
    });

Exception Handling

decorators

  • Se trata de mejorar el manejo de excepciones sobreescribiendo el servicio que proporciona Angular por defecto. Para ello se utilizan lo que se llaman los decorators –> decorator, Se configuran en el config de la ng-app utilizan el servicio $provide sobre el servicio $exceptionHandler  para realizar acciones personalizadas cuando ocurran excepciones.Why?: Provides a consistent way to handle uncaught AngularJS exceptions for development-time or run-time.Note: Another option is to override the service instead of using a decorator. This is a fine option, but if you want to keep the default behavior and extend it a decorator is recommended.
    /* recommended */
    angular
        .module('blocks.exception')
        .config(exceptionConfig);
    
    exceptionConfig.$inject = ['$provide'];
    
    function exceptionConfig($provide) {
        $provide.decorator('$exceptionHandler', extendExceptionHandler);
    }
    
    extendExceptionHandler.$inject = ['$delegate', 'toastr'];
    
    function extendExceptionHandler($delegate, toastr) {
        return function(exception, cause) {
            $delegate(exception, cause);
            var errorData = { 
                exception: exception, 
                cause: cause 
            };
            /**
             * Could add the error to a service's collection,
             * add errors to $rootScope, log errors to remote web server,
             * or log locally. Or throw hard. It is entirely up to you.
             * throw exception;
             */
            toastr.error(exception.msg, errorData);
        };
    }

Exception Catchers

  • Crearse un factory para exponer un interfaz que recoja y maneje de la manera que tu quieres las excepciones.
  • Why?: Provides a consistent way to catch exceptions that may be thrown in your code (e.g. during XHR calls or promise failures).Note: The exception catcher is good for catching and reacting to specific exceptions from calls that you know may throw one. For example, when making an XHR call to retrieve data from a remote web service and you want to catch any exceptions from that service and react uniquely.
    /* recommended */
    angular
        .module('blocks.exception')
        .factory('exception', exception);
    
    exception.$inject = ['logger'];
    
    function exception(logger) {
        var service = {
            catcher: catcher
        };
        return service;
    
        function catcher(message) {
            return function(reason) {
                logger.error(message, reason);
            };
        }
    }

Route Errors

  • Manejar todos los errores de routing sacando logs utilizando $routeChangeError.Why?: Provides a consistent way handle all routing errors.Why?: Potentially provides a better user experience if a routing error occurs and you route them to a friendly screen with more details or recovery options.
    /* recommended */
    function handleRoutingErrors() {
        /**
         * Route cancellation:
         * On routing error, go to the dashboard.
         * Provide an exit clause if it tries to do it twice.
         */
        $rootScope.$on('$routeChangeError',
            function(event, current, previous, rejection) {
                var destination = (current && (current.title || current.name || current.loadedTemplateUrl)) ||
                    'unknown target';
                var msg = 'Error routing to ' + destination + '. ' + (rejection.msg || '');
                /**
                 * Optionally log using a custom service or $log.
                 * (Don't forget to inject custom service)
                 */
                logger.warning(msg, [current]);
            }
        );
    }

Naming

Naming Guidelines

  • Utilizar nombres consistenes para todos los componentes siguiendo un patrón que describa la funcionalidad del componente y (opcionalmente) su tipo. Mi patrón recomendado es  feature.type.js. Hay dos nombres para la mayoría de assets:
  1. el nombre del fichero (avengers.controller.js)
  2. El nombre del componente que se registra en Angular (AvengersController)
  • Why?: Naming conventions help provide a consistent way to find content at a glance. Consistency within the project is vital. Consistency with a team is important. Consistency across a company provides tremendous efficiency.Why?: The naming conventions should simply help you find your code faster and make it easier to understand.

Feature File Names

  • Use consistent names for all components following a pattern that describes the component’s feature then (optionally) its type. My recommended pattern is feature.type.js.Why?: Provides a consistent way to quickly identify components.Why?: Provides pattern matching for any automated tasks.
    /**
     * common options 
     */
    
    // Controllers
    avengers.js
    avengers.controller.js
    avengersController.js
    
    // Services/Factories
    logger.js
    logger.service.js
    loggerService.js
    /**
     * recommended
     */
    
    // controllers
    avengers.controller.js
    avengers.controller.spec.js
    
    // services/factories
    logger.service.js
    logger.service.spec.js
    
    // constants
    constants.js
    
    // module definition
    avengers.module.js
    
    // routes
    avengers.routes.js
    avengers.routes.spec.js
    
    // configuration
    avengers.config.js
    
    // directives
    avenger-profile.directive.js
    avenger-profile.directive.spec.js

    Note: Another common convention is naming controller files without the word controller in the file name such as avengers.js instead of avengers.controller.js. All other conventions still hold using a suffix of the type. Controllers are the most common type of component so this just saves typing and is still easily identifiable. I recommend you choose 1 convention and be consistent for your team.

      /**
       * recommended
       */
      // Controllers
      avengers.js
      avengers.spec.js

Test File Names

  • Name test specifications similar to the component they test with a suffix of spec.Why?: Provides a consistent way to quickly identify components.Why?: Provides pattern matching for karma or other test runners.
    /**
     * recommended
     */
    avengers.controller.spec.js
    logger.service.spec.js
    avengers.routes.spec.js
    avenger-profile.directive.spec.js

Controller Names

  • Use consistent names for all controllers named after their feature. Use UpperCamelCase for controllers, as they are constructors.Why?: Provides a consistent way to quickly identify and reference controllers.Why?: UpperCamelCase is conventional for identifying object that can be instantiated using a constructor.
    /**
     * recommended
     */
    
    // avengers.controller.js
    angular
        .module
        .controller('HeroAvengers', HeroAvengers);
    
    function HeroAvengers(){ }

Controller Name Suffix

  • Append the controller name with the suffix Controller or with no suffix. Choose 1, not both.Why?: The Controller suffix is more commonly used and is more explicitly descriptive.Why?: Omitting the suffix is more succinct and the controller is often easily identifiable even without the suffix.
    /**
     * recommended: Option 1
     */
    
    // avengers.controller.js
    angular
        .module
        .controller('Avengers', Avengers);
    
    function Avengers(){ }
    /**
     * recommended: Option 2
     */
    
    // avengers.controller.js
    angular
        .module
        .controller('AvengersController', AvengersController);
    
    function AvengersController(){ }

Factory Names

  • Use consistent names for all factories named after their feature. Use camel-casing for services and factories.Why?: Provides a consistent way to quickly identify and reference factories.
    /**
     * recommended
     */
    
    // logger.service.js
    angular
        .module
        .factory('logger', logger);
    
    function logger(){ }

Directive Component Names

  • Use consistent names for all directives using camel-case. Use a short prefix to describe the area that the directives belong (some example are company prefix or project prefix).Why?: Provides a consistent way to quickly identify and reference components.
    /**
     * recommended
     */
    
    // avenger.profile.directive.js    
    angular
        .module
        .directive('xxAvengerProfile', xxAvengerProfile);
    
    // usage is <xx-avenger-profile> </xx-avenger-profile>
    
    function xxAvengerProfile(){ }

Modules

  • Cuando tenemos una app con varios módulos , el módulo principal se recomienda llamarlo app.module.js mientras que los demás módulos dependientes de este son nombrados en función de lo que representan. Por ejemplo, un módulo de admin se llamaría admin.module.js. Los módulos registrados correspondientes serían app y admin.
  • Sin embargo , cuando tenemos una aplicación con sólo un módulo basta con tener app.js
  • Why?: An app with 1 module is named app.js. It is the app, so why not be super simple.
  • Why?: Provides consistency for multiple module apps, and for expanding to large applications.Why?: Provides easy way to use task automation to load all module definitions first, then all other angular files (for bundling).

Configuration

  • Separar la configuración de un módulo en un archivo aparte. A configuration file for the main app module is named app.config.js (or simply config.js). A configuration for a module named admin.module.js is named admin.config.js.Why?: Separates configuration from module definition, components, and active code.Why?: Provides a identifiable place to set configuration for a module.

Routes

  • Separate route configuration into its own file. Examples might be app.route.js for the main module and admin.route.js for the admin module. Even in smaller apps I prefer this separation from the rest of the configuration. An alternative is a longer name such asadmin.config.route.js.

Application Structure LIFT Principle

LIFT

  • Structure your app such that you can Locate your code quickly, Identify the code at a glance, keep the Flattest structure you can, and Try to stay DRY. The structure should follow these 4 basic guidelines.Why LIFT?: Provides a consistent structure that scales well, is modular, and makes it easier to increase developer efficiency by finding code quickly. Another way to check your app structure is to ask yourself: How quickly can you open and work in all of the related files for a feature?When I find my structure is not feeling comfortable, I go back and revisit these LIFT guidelines
    1. Locating our code is easy
    2. Identify code at a glance
    3. Flat structure as long as we can
    4. Try to stay DRY (Don’t Repeat Yourself) or T-DRY

Locate

  • Make locating your code intuitive, simple and fast.Why?: I find this to be super important for a project. If the team cannot find the files they need to work on quickly, they will not be able to work as efficiently as possible, and the structure needs to change. You may not know the file name or where its related files are, so putting them in the most intuitive locations and near each other saves a ton of time. A descriptive folder structure can help with this.
    /bower_components
    /client
      /app
        /avengers
        /blocks
          /exception
          /logger
        /core
        /dashboard
        /data
        /layout
        /widgets
      /content
      index.html
    .bower.json
    

Identify

  • When you look at a file you should instantly know what it contains and represents.Why?: You spend less time hunting and pecking for code, and become more efficient. If this means you want longer file names, then so be it. Be descriptive with file names and keeping the contents of the file to exactly 1 component. Avoid files with multiple controllers, multiple services, or a mixture. There are deviations of the 1 per file rule when I have a set of very small features that are all related to each other, they are still easily identifiable.

Flat

  • Keep a flat folder structure as long as possible. When you get to 7+ files, begin considering separation.Why?: Nobody wants to search 7 levels of folders to find a file. Think about menus on web sites … anything deeper than 2 should take serious consideration. In a folder structure there is no hard and fast number rule, but when a folder has 7-10 files, that may be time to create subfolders. Base it on your comfort level. Use a flatter structure until there is an obvious value (to help the rest of LIFT) in creating a new folder.

T-DRY (Try to Stick to DRY)

  • Be DRY, but don’t go nuts and sacrifice readability.Why?: Being DRY is important, but not crucial if it sacrifices the others in LIFT, which is why I call it T-DRY. I don’t want to type session-view.html for a view because, well, it’s obviously a view. If it is not obvious or by convention, then I name it.

Back to top

Application Structure

Overall Guidelines

  • Have a near term view of implementation and a long term vision. In other words, start small and but keep in mind on where the app is heading down the road. All of the app’s code goes in a root folder named app. All content is 1 feature per file. Each controller, service, module, view is in its own file. All 3rd party vendor scripts are stored in another root folder and not in the app folder. I didn’t write them and I don’t want them cluttering my app (bower_componentsscriptslib).Note: Find more details and reasoning behind the structure at this original post on application structure.

Layout

  • Colocar los componentes que definan el layout general de la app en una carpeta llamada layout. These may include a shell view and controller may act as the container for the app, navigation, menus, content areas, and other regions.Why?: Organizes all layout in a single place re-used throughout the application.

Folders-by-Feature Structure

  • Create folders named for the feature they represent. When a folder grows to contain more than 7 files, start to consider creating a folder for them. Your threshold may be different, so adjust as needed.Why?: A developer can locate the code, identify what each file represents at a glance, the structure is flat as can be, and there is no repetitive nor redundant names.Why?: The LIFT guidelines are all covered.

    Why?: Helps reduce the app from becoming cluttered through organizing the content and keeping them aligned with the LIFT guidelines.

    Why?: When there are a lot of files (10+) locating them is easier with a consistent folder structures and more difficult in flat structures.

    /**
     * recommended
     */
    
    app/
        app.module.js
        app.config.js
        app.routes.js
        components/       
            calendar.directive.js  
            calendar.directive.html  
            user-profile.directive.js  
            user-profile.directive.html  
        layout/
            shell.html      
            shell.controller.js
            topnav.html      
            topnav.controller.js       
        people/
            attendees.html
            attendees.controller.js  
            speakers.html
            speakers.controller.js
            speaker-detail.html
            speaker-detail.controller.js
        services/       
            data.service.js  
            localstorage.service.js
            logger.service.js   
            spinner.service.js
        sessions/
            sessions.html      
            sessions.controller.js
            session-detail.html
            session-detail.controller.js

    Sample App Structure

    Note: Do not use structuring using folders-by-type. This requires moving to multiple folders when working on a feature and gets unwieldy quickly as the app grows to 5, 10 or 25+ views and controllers (and other features), which makes it more difficult than folder-by-feature to locate files.

    /* 
    * avoid
    * Alternative folders-by-type.
    * I recommend "folders-by-feature", instead.
    */
    
    app/
        app.module.js
        app.config.js
        app.routes.js
        controllers/
            attendees.js            
            session-detail.js       
            sessions.js             
            shell.js                
            speakers.js             
            speaker-detail.js       
            topnav.js               
        directives/       
            calendar.directive.js  
            calendar.directive.html  
            user-profile.directive.js  
            user-profile.directive.html  
        services/       
            dataservice.js  
            localstorage.js
            logger.js   
            spinner.js
        views/
            attendees.html     
            session-detail.html
            sessions.html      
            shell.html         
            speakers.html      
            speaker-detail.html
            topnav.html

Modularity

Many Small, Self Contained Modules

  • Create small modules that encapsulate one responsibility.Why?: Modular applications make it easy to plug and go as they allow the development teams to build vertical slices of the applications and roll out incrementally. This means we can plug in new features as we develop them.

Create an App Module

  • Create an application root module whose role is pull together all of the modules and features of your application. Name this for your application.Why?: AngularJS encourages modularity and separation patterns. Creating an application root module whose role is to tie your other modules together provides a very straightforward way to add or remove modules from your application.

Keep the App Module Thin

  • Only put logic for pulling together the app in the application module. Leave features in their own modules.Why?: Adding additional roles to the application root to get remote data, display views, or other logic not related to pulling the app together muddies the app module and make both sets of features harder to reuse or turn off.

Feature Areas are Modules

  • Create modules that represent feature areas, such as layout, reusable and shared services, dashboards, and app specific features (e.g. customers, admin, sales).Why?: Self contained modules can be added to the application will little or no friction.Why?: Sprints or iterations can focus on feature areas and turn them on at the end of the sprint or iteration.

    Why?: Separating feature areas into modules makes it easier to test the modules in isolation and reuse code.

Reusable Blocks are Modules

  • Create modules that represent reusable application blocks for common services such as exception handling, logging, diagnostics, security, and local data stashing.Why?: These types of features are needed in many applications, so by keeping them separated in their own modules they can be application generic and be reused across applications.

Module Dependencies

  • The application root module depends on the app specific feature modules, the feature modules have no direct dependencies, the cross-application modules depend on all generic modules.Modularity and DependenciesWhy?: The main app module contains a quickly identifiable manifest of the application’s features.

    Why?: Cross application features become easier to share. The features generally all rely on the same cross application modules, which are consolidated in a single module (app.core in the image).

    Why?: Intra-App features such as shared data services become easy to locate and share from within app.core (choose your favorite name for this module).

    Note: This is a strategy for consistency. There are many good options here. Choose one that is consistent, follows AngularJS’s dependency rules, and is easy to maintain and scale.

    My structures vary slightly between projects but they all follow these guidelines for structure and modularity. The implementation may vary depending on the features and the team. In other words, don’t get hung up on an exact like-for-like structure but do justify your structure using consistency, maintainability, and efficiency in mind.

Startup Logic

Configuration

  • Inject code into module configuration that must be configured before running the angular app. Ideal candidates include providers and constants.Why?: This makes it easier to have a less places for configuration.
    angular
        .module('app')
        .config(configure);
    
    configure.$inject = 
        ['routerHelperProvider', 'exceptionHandlerProvider', 'toastr'];
    
    function configure (routerHelperProvider, exceptionHandlerProvider, toastr) {
        exceptionHandlerProvider.configure(config.appErrorPrefix);
        configureStateHelper();
    
        toastr.options.timeOut = 4000;
        toastr.options.positionClass = 'toast-bottom-right';
    
        ////////////////
    
        function configureStateHelper() {
            routerHelperProvider.configure({
                docTitle: 'NG-Modular: '
            });
        }
    }

Run Blocks

  • Any code that needs to run when an application starts should be declared in a factory, exposed via a function, and injected into the run block.Why?: Code directly in a run block can be difficult to test. Placing in a factory makes it easier to abstract and mock.
    angular
        .module('app')
        .run(runBlock);
    
      runBlock.$inject = ['authenticator', 'translator'];
    
      function runBlock(authenticator, translator) {
          authenticator.initialize();
          translator.initialize();
      }

Angular $ Wrapper Services

$document and $window

  • Use $document and $window instead of document and window.Why?: These services are wrapped by Angular and more easily testable than using document and window in tests. This helps you avoid having to mock document and window yourself.

$timeout and $interval

  • Use $timeout and $interval instead of setTimeout and setInterval .Why?: These services are wrapped by Angular and more easily testable and handle AngularJS’s digest cycle thus keeping data binding in sync.

 

Testing

Unit testing helps maintain clean code, as such I included some of my recommendations for unit testing foundations with links for more information.

Write Tests with Stories

  • Write a set of tests for every story. Start with an empty test and fill them in as you write the code for the story.Why?: Writing the test descriptions helps clearly define what your story will do, will not do, and how you can measure success.
    it('should have Avengers controller', function() {
        //TODO
    });
    
    it('should find 1 Avenger when filtered by name', function() {
        //TODO
    });
    
    it('should have 10 Avengers', function() {}
        //TODO (mock data?)
    });
    
    it('should return Avengers via XHR', function() {}
        //TODO ($httpBackend?)
    });
    
    // and so on

Testing Library

  • Use Jasmine or Mocha for unit testing.Why?: Both Jasmine and Mocha are widely used in the AngularJS community. Both are stable, well maintained, and provide robust testing features.Note: When using Mocha, also consider choosing an assert library such as Chai.

Test Runner

  • Use Karma as a test runner.Why?: Karma is easy to configure to run once or automatically when you change your code.Why?: Karma hooks into your Continuous Integration process easily on its own or through Grunt or Gulp.

    Why?: Some IDE’s are beginning to integrate with Karma, such as WebStorm and Visual Studio.

    Why?: Karma works well with task automation leaders such as Grunt (with grunt-karma) and Gulp(with gulp-karma).

Stubbing and Spying

  • Use Sinon for stubbing and spying.Why?: Sinon works well with both Jasmine and Mocha and extends the stubbing and spying features they offer.Why?: Sinon makes it easier to toggle between Jasmine and Mocha, if you want to try both.

Headless Browser

  • Use PhantomJS to run your tests on a server.Why?: PhantomJS is a headless browser that helps run your tests without needing a “visual” browser. So you do not have to install Chrome, Safari, IE, or other browsers on your server.Note: You should still test on all browsers in your environment, as appropriate for your target audience.

Code Analysis

  • Run JSHint on your tests.Why?: Tests are code. JSHint can help identify code quality issues that may cause the test to work improperly.

Alleviate Globals for JSHint Rules on Tests

  • Relax the rules on your test code to allow for common globals such as describe and expect.Why?: Your tests are code and require the same attention and code quality rules as all of your production code. However, global variables used by the testing framework, for example, can be relaxed by including this in your test specs.
    /* global sinon, describe, it, afterEach, beforeEach, expect, inject */

    Testing Tools

Animations

Usage

  • Use subtle animations with AngularJS to transition between states for views and primary visual elements. Include the ngAnimate module. The 3 keys are subtle, smooth, seamless.Why?: Subtle animations can improve User Experience when used appropriately.Why?: Subtle animations can improve perceived performance as views transition.

Sub Second

  • Use short durations for animations. I generally start with 300ms and adjust until appropriate.Why?: Long animations can have the reverse affect on User Experience and perceived performance by giving the appearance of a slow application.

animate.css

Back to top

Comments

jsDoc

  • If planning to produce documentation, use jsDoc syntax to document function names, description, params and returns. Use @namespace and @memberOf to match your app structure.Why?: You can generate (and regenerate) documentation from your code, instead of writing it from scratch.Why?: Provides consistency using a common industry tool.
    /**
     * Logger Factory
     * @namespace Factories
     */
    (function() {
      angular
          .module('app')
          .factory('logger', logger);
    
      /**
       * @namespace Logger
       * @desc Application wide logger
       * @memberOf Factories
       */
      function logger($log) {
          var service = {
             logError: logError
          };
          return service;
    
          ////////////
    
          /**
           * @name logError
           * @desc Logs errors
           * @param {String} msg Message to log 
           * @returns {String}
           * @memberOf Factories.Logger
           */
          function logError(msg) {
              var loggedMsg = 'Error: ' + msg;
              $log.error(loggedMsg);
              return loggedMsg;
          };
      }
    })();

Back to top

JS Hint

Use an Options File

  • Use JS Hint for linting your JavaScript and be sure to customize the JS Hint options file and include in source control. See the JS Hint docs for details on the options.Why?: Provides a first alert prior to committing any code to source control.Why?: Provides consistency across your team.
    {
        "bitwise": true,
        "camelcase": true,
        "curly": true,
        "eqeqeq": true,
        "es3": false,
        "forin": true,
        "freeze": true,
        "immed": true,
        "indent": 4,
        "latedef": "nofunc",
        "newcap": true,
        "noarg": true,
        "noempty": true,
        "nonbsp": true,
        "nonew": true,
        "plusplus": false,
        "quotmark": "single",
        "undef": true,
        "unused": false,
        "strict": false,
        "maxparams": 10,
        "maxdepth": 5,
        "maxstatements": 40,
        "maxcomplexity": 8,
        "maxlen": 120,
    
        "asi": false,
        "boss": false,
        "debug": false,
        "eqnull": true,
        "esnext": false,
        "evil": false,
        "expr": false,
        "funcscope": false,
        "globalstrict": false,
        "iterator": false,
        "lastsemic": false,
        "laxbreak": false,
        "laxcomma": false,
        "loopfunc": true,
        "maxerr": false,
        "moz": false,
        "multistr": false,
        "notypeof": false,
        "proto": false,
        "scripturl": false,
        "shadow": false,
        "sub": true,
        "supernew": false,
        "validthis": false,
        "noyield": false,
    
        "browser": true,
        "node": true,
    
        "globals": {
            "angular": false,
            "$": false
        }
    }

Back to top

Constants

Vendor Globals

  • Create an AngularJS Constant for vendor libraries’ global variables.Why?: Provides a way to inject vendor libraries that otherwise are globals. This improves code testability by allowing you to more easily know what the dependencies of your components are (avoids leaky abstractions). It also allows you to mock these dependencies, where it makes sense.
    // constants.js
    
    /* global toastr:false, moment:false */
    (function() {
        'use strict';
    
        angular
            .module('app.core')
            .constant('toastr', toastr)
            .constant('moment', moment);
    })();

Back to top

File Templates and Snippets

Use file templates or snippets to help follow consistent styles and patterns. Here are templates and/or snippets for some of the web development editors and IDEs.

Sublime Text

  • AngularJS snippets that follow these styles and guidelines.
    • Download the Sublime Angular snippets
    • Place it in your Packages folder
    • Restart Sublime
    • In a JavaScript file type these commands followed by a TAB
    ngcontroller // creates an Angular controller
    ngdirective // creates an Angular directive
    ngfactory // creates an Angular factory
    ngmodule // creates an Angular module

Visual Studio

  • AngularJS file templates that follow these styles and guidelines can be found at SideWaffle
    • Download the SideWaffle Visual Studio extension (vsix file)
    • Run the vsix file
    • Restart Visual Studio

WebStorm

  • AngularJS snippets and file templates that follow these styles and guidelines. You can import them into your WebStorm settings:
    • Download the WebStorm AngularJS file templates and snippets
    • Open WebStorm and go to the File menu
    • Choose the Import Settings menu option
    • Select the file and click OK
    • In a JavaScript file type these commands followed by a TAB:
    ng-c // creates an Angular controller
    ng-f // creates an Angular factory
    ng-m // creates an Angular module

Back to top

AngularJS docs

For anything else, API reference, check the Angular documentation.

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 an Issue. 
1. Open a Pull Request, reference the issue, and explain the change and why it adds value.
1. The Pull Request will be evaluated and either merged or declined.

sd
ds
ds
ds
ds
ds
dsds

fd

fdf

d