Slide 1

Slide 1 text

Refactoring AngularJS Apps to Components @teropa

Slide 2

Slide 2 text

Component is the main primitive. ! An atomic UI piece that is composable and reusable. Brian Ford, TXJS 2015

Slide 3

Slide 3 text

Angular 2 Components

Slide 4

Slide 4 text

@Component({ selector: 'my-confirmation', inputs: ['message'], outputs: ['ok'] }) @View({ template: `
{{message}} OK
` }) class MyConfirmation { okEvents = new EventEmitter(); ok() { this.okEvents.next(); } } Interface Boundary: Inputs & Outputs UI Template Logic Angular 2 Components

Slide 5

Slide 5 text

Angular 1 Approximation

Slide 6

Slide 6 text

module.directive('myConfirmation', function() { return { scope: {}, bindToController: { message: '=', onOk: '&' }, controller: function() { }, controllerAs: 'ctrl', template: `
{{ctrl.message}} OK
` } }); Interface Boundary: Inputs & Outputs UI Template Logic Angular 1 Approximation

Slide 7

Slide 7 text

module.component('myConfirmation', { bindings: { message: '=', onOk: '&' }, controller: function() { }, template: `
{{myConfirmation.message}} OK
` }); Interface Boundary: Inputs & Outputs UI Template Logic Angular 1.5 Approximation

Slide 8

Slide 8 text

Image: Howard Lake Most Real Apps: Scope Soup

Slide 9

Slide 9 text

Image: Howard Lake Most Real Apps: Scope Soup ! Lots of ng-controller and ng-include ! No controller/template parity ! Data sharing through scope inheritance Rampant shared mutable state

Slide 10

Slide 10 text

Scope Soup Components ?

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

Small, Simple, Systematic steps Scope Soup Components

Slide 13

Slide 13 text

Stages 1 - Component Creation 2 - Data Flow

Slide 14

Slide 14 text

1 Component Creation

Slide 15

Slide 15 text

Replace ng-controller with Component 1 - Component Creation

Slide 16

Slide 16 text

{{ctrl.getText()}}

Replace ng-controller with Component index.html Before

Slide 17

Slide 17 text

foobar.js After module.component('foobar', { scope: true, controller: ‘FoobarCtrl as ctrl' }); Replace ng-controller with Component

Slide 18

Slide 18 text

After components/foobar/ foobar.js foobar_controller.js Replace ng-controller with Component

Slide 19

Slide 19 text

index.html After

{{ctrl.getText()}}

Replace ng-controller with Component

Slide 20

Slide 20 text

Move Markup to Component Template 1 - Component Creation

Slide 21

Slide 21 text

{{ctrl.getText()}}

Move Markup to Component Template index.html After

Slide 22

Slide 22 text

After components/foobar/ foobar.js foobar_controller.js foobar.html Move Markup to Component Template

Slide 23

Slide 23 text

module.component(‘foobar', { scope: true, controller: ‘FoobarCtrl as ctrl', templateUrl: 'foobar.html' }); foobar.js After Move Markup to Component Template

Slide 24

Slide 24 text

foobar.html After

{{ctrl.getText()}

Move Markup to Component Template

Slide 25

Slide 25 text

index.html After Move Markup to Component Template

Slide 26

Slide 26 text

2 Data Flow

Slide 27

Slide 27 text

Replace external reference with bound input 2 - Data Flow

Slide 28

Slide 28 text

Replace external reference with bound input foobar.html Before

{{foobar.getText(mainCtrl.getLanguage())}}

Slide 29

Slide 29 text

module.component(‘foobar', { scope: true, bindings: { visible: '=' }, controller: 'FoobarCtrl', templateUrl: 'foobar.html' }); Replace external reference with bound input foobar.js After

Slide 30

Slide 30 text

Replace external reference with bound input index.html After

Slide 31

Slide 31 text

Replace external reference with bound input foobar.html After

{{foobar.getText(mainCtrl.getLanguage())}}

Slide 32

Slide 32 text

module.component('foobar', { scope: true, bindings: { visible: '=', language: '=' }, controller: 'FoobarCtrl', templateUrl: 'foobar.html' }); Replace external reference with bound input foobar.js After

Slide 33

Slide 33 text

Replace external reference with bound input index.html After

Slide 34

Slide 34 text

Replace external reference with bound input foobar.html After

{{foobar.getText(foobar.language)}}

Slide 35

Slide 35 text

Replace external function call with bound output 2 - Data Flow

Slide 36

Slide 36 text

{{foobar.getText(foobar.language)}}

Delete
Replace external function call with bound output foobar.html Before

Slide 37

Slide 37 text

module.component('foobar', { scope: true, bindings: { visible: '=', language: '=', onDelete: '&' }, controller: 'FoobarCtrl', templateUrl: 'foobar.html' }); foobar.js After Replace external function call with bound output

Slide 38

Slide 38 text

index.html After Replace external function call with bound output

Slide 39

Slide 39 text

foobar.html After Replace external function call with bound output

{{foobar.getText(foobar.language)}}

Delete

Slide 40

Slide 40 text

Isolate Component 2 - Data Flow

Slide 41

Slide 41 text

module.component('foobar', { scope: true, bindings: { visible: '=', language: '=', onDelete: '&' }, controller: 'FoobarCtrl', templateUrl: 'foobar.html' }); foobar.js Before Isolate Component

Slide 42

Slide 42 text

1 - Component Creation 2 - Data Flow Replace ng-include with Component Replace ng-controller with Component Move Markup to Component Template Adopt Template Root Controller to Component Replace External Reference with Bound Input Wrap Markup in Component Directive Replace External Function Call with Bound Output Isolate Component Replace State Mutation with Bound Outputs teropa.info/blog/2015/10/18/refactoring-angular-apps-to-components.html Replace Two-Way Binding with One-Way Binding