Created by Aidas Klimas

About me


I code mostly with - JavaScript and PHP

I share stuff at - https://github.com/AidasK



Who is using Angular.js


Uploady.com

Google Trends

plnkr.co



And more http://builtwith.angularjs.org/

First impression


No need to write javascript 

<!doctype html>
<html ng-app>
  <head>
      <script src="js/angular.js"></script>
  </head>
  <body>
      <label>Name:</label>
      <input type="text" ng-model="yourName">
      <h1>Hello {{yourName}}!</h1>
  </body>
</html>
                    

Hello {{yourName}}!

No template language

Handlebars


<ul>
  {{#each visitors}}
    <li>Hello, {{name}}!</li>
  {{/each}}
</ul>

Angular


<ul>
    <li ng-repeat="visitor in visitors">Hello, {{visitor.name}}!</li>
</ul>

Basic templates

HTML string + Data = Merged HTML string

Angular templates

Easy to bind events


<div ng-init="boxes=[]">
    <button class="btn btn-default" ng-click="boxes.push({
        id: boxes.length + 1
    })">Add box</button>
    <div ng-repeat="box in boxes" class="box">{{box.id}}</div>
</div>

{{box.id}}

Directives


<greeter name="VilniusJS"></greeter>

Should output:

Hello VilniusJS!

<greeter> Directive


app.directive('greeter', function () {
    return {
        restrict: 'E',
        template: 'Hello {{name}}!',
        scope: {
            name: '@'
        }
    };
});

<greeter name="Angular"></greeter>
<greeter name="VilniusJS"></greeter>

Outputs:

Directive "restrict"

  • restrict: "E" - for elements only
    <directive></directive>
  • restrict: "A" - for attributes only
    <div directive></div>
  • "C" - class names
  • "M" - comments
  • Or any combined variation restrict: "EACM"

draggable Directive


<img src="images/datadog.png" draggable/>

Example:

Draggable Directive


app.directive('draggable', function($document) {
    return function (scope, element, attr) {
        var startX = 0, startY = 0, x = 0, y = 0;
        element.css({
            position: 'relative', cursor: 'pointer'
        });
        element.on('mousedown', function (event) {
            startX = event.pageX - x;
            startY = event.pageY - y;
            $document.on('mousemove', mousemove);
            $document.on('mouseup', mouseup);
            event.preventDefault();
        });
        function mousemove(event) {
            y = event.pageY - startY;
            x = event.pageX - startX;
            element.css({
                top: y + 'px',
                left: x + 'px'
            });
        }
        function mouseup() {
            $document.unbind('mousemove', mousemove);
            $document.unbind('mouseup', mouseup);
        }
    }
});

Angular Directives

  • ng-click
  • ng-hide
  • ng-if
  • ng-class
  • ng-style
  • ng-switch
  • ng-repeat
  • ng-animate
  • ng-swipe-left
  • ...

Tips

Directives naming

  • Prefix your directives
  • Make sure your prefix is unique
  • Don't use "ng-"
  • Possible prefixes - "my-", "app-"

View is not changing!


app.directive('awesomeClick', function($document) {
    return function (scope, element, attr) {
        scope.awesome = 0;
        element.bind('click', function () {
            scope.awesome += 1;
        });
    }
});

<a awesome-click>awesome-click [{{awesome}}]</a>
awesome-click [{{awesome}}]

app.directive('runApplyClick', function($document) {
    return function (scope, element, attr) {
        element.bind('click', function () {
            scope.$apply();
        });
    }
});
run-apply-click

awesome-click fixed


app.directive('awesomeClickFixed', function($document) {
    return function (scope, element, attr) {
        scope.awesome = 0;
        element.bind('click', function () {
            scope.awesome += 1;
            scope.$apply();
        });
    }
});

<a awesome-click-fixed>awesome-click-fixed [{{awesome}}]</a>
awesome-click-fixed [{{awesome}}]

$scope.$apply()

$digest already in progress

Make sure event is always called sync or async

This is not a solution


    if (!$scope.$$phase) $scope.$apply()

$digest already in progress

Solution:

  • Open a pull request and fix a library
  • Use $timeout for async execution

$timeout(function () {
    // Ugly code goes here
});

$http

Suggestion: don't hardcode URLs in a controller


app.factory('api', function($http) {
    return {
        folder: {
            list: request('/folders/children', 'GET'),
            remove: request('/folders', 'DELETE'),
            ...
        }
    };
    function request(url, method) {
        return function (params, data) {
            return $http({
                url: url, method: method, params: params, data: data
            });
        };
    }
});

    api.folder.remove({id: 5})

$resource

Doesn't work with advanced APIs, use $http instead.


http://jsonapi.org/ - "JSON API" is a standard for building APIs in JSON.

Logging


app.factory('$log', function($window){
    return {
        log: consoleLog('log'),
        info: consoleLog('info'),
        warn: consoleLog('warn'),
        ...
    };
    function consoleLog(type) {
        return function() {
            var args = [];
            forEach(arguments, function(arg) {
                args.push(formatError(arg));
            });
            return logFn.apply(console, args);
        };
    }
});

Ooops, an error occured

Logging

Send all errors to the server side.


...
function consoleLog(type) {
    return function() {
        var args = [];
        forEach(arguments, function(arg) {
            args.push(formatError(arg));
        });
        var url = $window.location && $window.location.href;
        $http.post('/log', {message: args.join('\n\n'), url: url});
        return logFn.apply(console, args);
    };
}
...

SEO

What does the google see?


<html ng-app>
    <head>
        <link rel="stylesheet" type="text/css" href="/css/min.css"/>
        <script type="text/javascript" src="/js/min.js"></script>
        <title>My Angular site</title>
    </head>
    <body>
        <div ng-view></div>
    </body>
</html>

How to fix this?


    <meta name="fragment" content="!"/>

    $locationProvider.hashPrefix('!');

http://example.com/#!/article

http://example.com/?_escaped_fragment_=/article

How to fix this for html5 urls?


    $locationProvider.html5Mode(true).hashPrefix('!');

http://example.com/article

http://example.com/article?_escaped_fragment_=

Example - angular documentation

Regular page: http://docs.angularjs.org/guide/dev_guide.services.$location Indexed page: http://docs.angularjs.org/guide/dev_guide.services.$location?_escaped_fragment_=

Libraries

UI-Alias


                    angular.module('ui.alias').constant('uiAliasConfig', {
    'alias': '<template dir1 options="customScopeVar"></template>',
    // becomes <alias>
    'alias2': {
        template: '<another-template></another-template>',
        restrict: 'AEC'
    },
    date: '<input ui-date ui-date-format="mm/dd/yyyy">'  // <date>

});

Angular Flow

JavaScript library providing multiple simultaneous, stable and resumable uploads via the HTML5 File API.

github.com/flowjs/ng-flow

And more

  • ui-bootstrap - angular with bootstrap 2/3
  • angulartics - track your visitors with angular routes
  • ngprogress-lite - Slim progress bars for Ajax'y applications

Whats next?

  • Angular.js with Require.js

Thank You!

Questions?

Get slides from klimas.lt/slides