From jQuery to AngularJS – VS – What needs to be changed?



From jQuery to AngularJS – VS – What needs to be changed?

1 0


from-jquery-to-angularjs

Slides from BarcelonaJS 2013 November

On Github VictorBjelkholm / from-jquery-to-angularjs

From jQuery to AngularJS

Welcome people Thank BarcelonaJS for speaking, Estrella for the beer, and Vreasy for all time

What we will do

  • What is jQuery?
  • What is AngularJS?
  • When jQuery/AngularJS?
  • What needs to be changed?
  • jqLite in AngularJS
  • Further resources

What jQuery is and how we use it

What AngularJS is and how we use it

When to use what and what the difference is

How AngularJS expects you to think to use correctly

jQuery in AngularJS

Where to go from here

Might seem small, look at code in many slides

Anyone know what jQuery is?

JavaScript library released in 2006, created for DOM manipulation by John Resig

50% of the websites, wordpress, joomla

Library

Bundle of functions / methods

Specific, well-defined operations

Tool for a specific need

Underscore, backbone, mootools, handlebars, zepto

All about the DOM

Data, business logic, presentation, everything

Demo - jQuery

Build a todo application in jQuery
  • List of items
  • Add items
  • Remove item
  • Edit items
                        <div>
    <input type="text" id="todoName" placeholder="Name of todo">
    <button id="addTodo" type="submit">Add</button>
    <ul id="todoList">
        <li>
            <span class="text">Item 1</span>
            <a href="#" class="todoRemove">Remove</a>
        </li>
    </ul>
</div>
<div id="todoEdit" style="display: none;">
    <input type="text" id="todoEditField">
    <button type="submit">Save</button>
</div>
                    

No clear connection between button and text field

No clear connection between list and actual items

We don't know what's going on. We can always guess but guessing is dangerous.

We want to be able to read code as smoothly as possible, spend more time reading code than writing code

                        $(document).ready(function () {
    var addItem = function (value) {
        $('#todoList').append('<li><span class="text">' + value + '</span> <a href="#" class="todoRemove">Remove</a></li>')
    }
    $(document).on('click', '#addTodo', function () {
        addItem($('#todoName').val());
    });
    $(document).on('click', '.todoRemove', function (ev) {
        ev.preventDefault();
        $(this).parent().remove();
    });
    $(document).on('click', '#todoList span', function () {
        var itemText = $(this).text();
        $(this).parent().remove();
        $('#todoEdit input').val(itemText);
        $('#todoEdit').show();
    });
    $(document).on('click', '#todoEdit button', function () {
        var itemText = $('#todoEdit input').val();
        addItem(itemText);
        $('#todoEdit').hide();
    })
})
                    

References that will break once moved.

Does stuff it shouldn't care about

In the wrong context, does the wrong thing

Anyone know what AngularJS is?

Open source framework for developing webapplications

Created by Misko Hevery and Adam Abrons 2009

Started out to help webdesigners who isn't developer to spray on some extra HTML and magic with data storage

Misko redesigning Google Feedback admin panel

6 months, issues with productivity

Misko said "with this project I'm working on the side, I could have done this in two weeks!"

Google accepted the challenge "Prove us wrong"

Took him three weeks, not two

From 17'000 LOC, down to 1'500 LOC, same application

Framework

Abstract design

Way of life

User code is in framework, not user code calling framework

"Don't call us, we call you" Hollywood principle, Inversion of control

"You call library code, framework calls your code"

DOM is only one part

Quick about MVC

DOM is for showing stuff and interactions

All the rest is elsewhere

Demo - AngularJS

(25 minutes)
  • List of items
  • Add items
  • Remove item
  • Edit items
                        <div ng-app="plnkr">
    <div ng-controller="IndexCtrl">
        <input type="text" ng-model="newTodo.name">
        <button type="submit" ng-click="addTodo(newTodo)">Add</button>
        <ul>
            <li ng-repeat="item in items">
                <span ng-click="editTodo(item)">{{ item.name }}</span>
                <a href="#" ng-click="removeTodo(item)">Remove</a>
            </li>
        </ul>
        <div ng-show="editingTodo">
            <input type="text" ng-model="editingTodo.name">
            <button ng-click="editingTodo = null">Done</button>
        </div>
    </div>
</div>
                    

You can see clear connections

Stuff can be moved and still working

No classes/ids because that's about styling, other concern!

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

app.controller('IndexCtrl', function($scope) {
    $scope.items = [
        { name: 'Item 1' },
        { name: 'Item 2' }
    ];
    $scope.newTodo = {
        name: "New todo item"
    };

    $scope.addTodo = function(newTodo) {
        $scope.items.push(angular.copy(newTodo));
    }

    $scope.removeTodo = function(item) {
        var index = $scope.items.indexOf(item);
        $scope.items.splice(index, 1);
    }

    $scope.editTodo = function(item) {
        $scope.editingTodo = item;
    }
})
Does only what it needs to do. No view stuff here!

VS

Which is the best one?

None because the question is bad, different use cases

Library versus Framework

Library

<li>
    <span class="text">Item 1</span>
    <a href="#" class="todoRemove">Remove</a>
</li>
$(document).on('click', '.todoRemove', function(ev) {
	ev.preventDefault();
	$(this).parent().remove();
});
Stuck to the place where it's created Does stuff that could change in the future
<a href="#" class="somethingElse"></a>

Framework

<li ng-repeat="item in items">
	<span ng-click="selectTodo(item)">{{ item.name }}</span>
	<a href="#" ng-click="removeTodo(item, $event)">Remove</a>
</li>
$scope.removeTodo = function (item, $event) {
  $event.preventDefault();
  var index = $scope.items.indexOf(item);
  $scope.items.splice(index, 1);
}

Just a method, could be called from anywhere, don't care about outside

Remove selected
Imperative versus Declarative

Write code in two ways

AngularJS extends HTML, embraces HTML, what happened in the demo

Imperative - How to do something, end up with what we wanted to do

Declarative - What we want to do, how it does it is not a concern of ours

Don't decide the flow of the control

Abstract away logic, seperation of concerns

Imperative

$('#addTodo').on('click', function(ev) {
    ev.preventDefault();
    addItem($('#todoName').val());
});
                	
How we want to add the item

Declarative

<button type="submit" ng-click="addTodo(newTodo)">Add</button>
                	
Just add the goddamn todo
Website versus Application

jQuery - Start with website, extend with functionality

AngularJS - Start with thinking, doing foundation, add functionality, end up with website

When to use what (30 minutes)

jQuery - Websites, no data, minimal interactions

AngularJS - Application, a lot of interactions, contains data, communicates with something (db / backend)

Introspection

Thinking and reflection moment

jQuery, library for the dom, tell it what do, looking on html isn't enough

AngularJS, framework to build applications, we extend it after it's law and principles

You know library, now it's time for framework

First steps first

What needs to be changed?

Don't think about jQuery

"Don't even use jQuery. Don't even include it. It will hold you back"

When I started out, I would often reach for the jQuery solution, easy and fast. Not including jQuery anymore brought me to seek native angularjs solution which I'm now benifitting from.

Cornerstones of AngularJS

  • DRY
  • Structure
  • Testability
Data back and forth between the browser and data storage Don't repeat yourself, reusability Common structure for applications Built in testbility for developers Difference between website and application, you need tests!

Don't Repeat Yourself

angular.module('friendList', [])
.directive('list', function () {
    return {
        restrict: 'E',
        scope: {
            'ngModel': '='
        },
        template: '<pre><code>{{ ngModel }}</code></pre>'
    }
})
<div>
    Your friendlist!
    <list ng-model="user.friends"></list>
</div>
<div>
    Mauros friendlist!
    <list ng-model="User('userId').friends"></list>
</div>

Structure

Structure

mask.js - angular-ui/ui-utils
angular.module('ui.mask', [])
  .directive('uiMask', ['uiMaskConfig', function (maskConfig) {
    return {
      priority: 100,
      require: 'ngModel',
      restrict: 'A',
      compile: function uiMaskCompilingFunction(){
        var options = maskConfig;
[...]

Structure

progressbar.js - angular-ui/bootstrap
angular.module('ui.bootstrap.progressbar', ['ui.bootstrap.transition'])
    .directive('progress', function() {
        return {
            restrict: 'EA',
            replace: true,
            controller: 'ProgressBarController',
            scope: {
                value: '=percent',
                onFull: '&',
                onEmpty: '&'
[...]

Structure

Restangular - mgonto/restangular
angular.module('restangular', [])
    .provider('Restangular', function() {
        // Configuration
        var Configurer = {};
        Configurer.init = function(object, config) {
            /**

Testability

it("should display the welcome text properly", function() {
    var element = $compile('<div welcome="user"></div>')($rootScope);
    expect(element.text()).to.match(/Welcome/i);
})

Architecture

MVC
  • Model - Data
  • View - Presentation
  • Controller - Connector
  • Model - holds our data, usually comes from the backend
  • View - shows our data and makes it interactive
  • Controller - communicator between model and view

MVC in AngularJS

angular.module('User', [])
    .provider('User', function () {
        [...]
    });

angular.module('FriendList', [])
    .directive('list', function () {
        return {
            [...]
        }
    })

angular.module('mainApp', ['User', 'FriendList'])
    .controller('IndexCtrl', function($scope, User) {
        $scope.user = User.current();
    })
<div ng-controller="IndexCtrl">
    Your friends!
    <list ng-model="user.friends"></list>
</div>

Model and Controller above

View below

jqLite in AngularJS

Subset of jQuery for DOM manipulation

Directives in AngularJS

Reusable components

Creating new HTML elements, available for reuse everywhere!

<div>
  <pre>{{ users | json }}</pre>
</div>
<div style="float: right;">
  <user-image user="current_user"></user-image>
</div>
<user-list users="users"></user-list>
<div style="float: left;">
  <user-card user="current_user"></user-card>
</div>

user-image for showing image

user-card for showing image and related information

user-list for list of user-cards

<div>
  <user-image user="current_user"></user-image>
</div>

<div>
  <user-card user="current_user"></user-card>
</div>

<div>
  <user-list users="users"></user-list>
</div>

    app.directive('userImage', function () {
      return {
        restrict: 'E',
        scope: {
          'user': '='
        },
        template: '<img height="50" ng-src="{{user.image}}">'
      }
    })

    app.directive('userCard', function() {
            return {
                restrict: 'E',
                scope: {
                    'user': '='
                },
                template: '<div><h3>{{ user.name }}</h3>' +
                          '<h5>@{{ user.twitter }}</h5>' +
                          '<user-image user="user"></user-image></div>'
            }
        })

    app.directive('userList', function() {
            return {
                restrict: 'E',
                scope: {
                    'users': '='
                },
                template: '<div><user-card ng-repeat="user in users" user="user"></user-card></div>'
            }
        })

Where is jQuery?

jqLite methods

addClass - after - append - attr - bind - children - clone - contents - css - data - eq - find - hasClass - html - next - on - off - parent - prepend - prop - ready - remove - removeAttr - removeClass - removeData - replaceWith - text - toggleClass - triggerHandler - unbind - val - wrap Not here? Can't use it!

jqLite

jqLite

<change-color color="purple"></change-color>
<div ng-repeat="color in colors">
    <change-color color="{{color}}"></change-color>
</div>
app.controller('IndexCtrl', function($scope) {
    $scope.colors = ['red', 'blue', 'green', 'yellow'];
})

app.directive('changeColor', function() {
        return {
            restrict: 'E',
            scope: {
                'color': '@'
            },
            template: '<h3>Change my color to {{ color }} by clicking on me!!!</h3>',
            link: function (scope, element) {
                element.bind('click', function () {
                    element.css('color', scope.color);
                });
            }
        }
    })

Think first

Take time to think before coding

Further resources

  • Developer guide
  • Official API documentation
  • Official Youtube channel
  • #angularjs on Freenode
  • Mailing list
  • Stack Overflow

The End

victor@vreasy.com @victorbjelkholm github.com/victorbjelkholm