48
Angular Rebooted: Components Everywhere Carlo Bonamico -Sonia Pini MILAN 25-26 NOVEMBER 2016 [email protected] [email protected] - NIS s.r.l. - a DGS company [email protected] – Genova Java User Group Twitter: @carlobonamico @nis_srl

Angular Rebooted: Components Everywhere

Embed Size (px)

Citation preview

Page 1: Angular Rebooted: Components Everywhere

Angular Rebooted: Components Everywhere

Carlo Bonamico -Sonia Pini

MILAN 25-26 NOVEMBER 2016

[email protected] [email protected] - NIS s.r.l. - a DGS [email protected] – Genova Java User Group

Twitter: @carlobonamico @nis_srl

Page 2: Angular Rebooted: Components Everywhere

AbstractAttracted by AngularJS power and simplicity, you have chosen it for your next project. Getting started with DataBinding, Scopes and Controllers was relatively quick and easy...

But what do you need to effectively bring a complex application to Production?

We discuss ● the new Component API, ● lifecycle callbacks - $onChanges ● selecting different ways for components to collaborate● choosing between Two-Way Binding and One-Way Data Flow, ● "smart" vs "dumb" components,

We ‘ll share recipes from our real world experience so that you can productively & reliably build a complex application out of reusable Components.

Page 3: Angular Rebooted: Components Everywhere

We all love AngularJs● Simple & Powerful

○ Two way data binding is legendary○ Dependency Injection is awesome

○ Routing is very flexible○ D.R.Y and reusable code made easy○ Components/Directives FTW○ Modular and component-driven

…○ Testable code

We all love AngularJs

Page 4: Angular Rebooted: Components Everywhere

Real world apps are not easyBringing a complex application to production requires more than quickly bind form fields:● decoupling unrelated parts● preventing fragility in the face of changes● keeping collaboration effective as team grows ● avoiding performance issues

Angular gives us good tools - but we need to use them in the right way

Page 5: Angular Rebooted: Components Everywhere

Avoiding bad practicesOften, as the application starts to grow, we see● single large controller and HTML file per view

○ thousands of lines each● significant repetition across views

○ same HTML fragments in many files● “Spaghetti Binding”

○ creates dependencies between unrelated parts

Code becomes hard to navigate / risky to change

We need Software Engineering for the Frontend, too

Page 6: Angular Rebooted: Components Everywhere

“Spaghetti Binding” vs Components

Page 7: Angular Rebooted: Components Everywhere

What is a Component?● Self-contained set of UI and logic

○ encapsulates a specific behaviour ○ provides an explicit API

● Since Angular 1.5, special kind of Directive with○ UI in a template○ Logic in a controller○ some metadata (inputs, outputs, …)

● Makes it easier/cheaper to do a good design○ pushing the community towards best practices

● In Angular 2, the main application construct

Page 8: Angular Rebooted: Components Everywhere

Most of the concepts that we present apply to both

Angular 1.5 & Angular 2.0

although syntax is different

Page 9: Angular Rebooted: Components Everywhere

Example App: NG Component Mail

Full Source in https://github.com/carlobonamico/angular-component-based

Page 10: Angular Rebooted: Components Everywhere

Thinking in Components

<message-list>

<folder-list> <nav-actions>

<message-viewer>

<search-panel>

<folder-list>

<message-actions>

Page 11: Angular Rebooted: Components Everywhere

Design the Component APIDefine input and output properties

● Keep naming conventions consistent ● Follow Clean Code guidelines

<component>

inputs

outputs

Page 12: Angular Rebooted: Components Everywhere

<folder-list> API and behavior

input → folder array, title, allowCreate

output → selected folder

encapsulated state and behaviour → current folder, select with click, sorting, filtering

Page 13: Angular Rebooted: Components Everywhere

● = → two-way binding● < → one-way binding● @ → input string● ? → optional

<folder-list> - Declaring Inputs

Page 14: Angular Rebooted: Components Everywhere

Template

Component

Controller

Page 15: Angular Rebooted: Components Everywhere

Passing Inputs to <folder-list>

FolderList Component

Page 16: Angular Rebooted: Components Everywhere

Why didn’t we use “=”?The “=” qualifier means that the binding is two-way● the <folder-list> component could even replace

the folder array with another one○ while it’s role is just to display it

● and this change could also immediately affect various other parts of the page which reference the folder array in their {{}} expressions and $watch-es

Guideline: default to “<” for component inputs● one-way change propagation

Page 17: Angular Rebooted: Components Everywhere

Two-way bindings pros and cons● Very effective collaboration “in the small”

○ like when all people in a room can talk to each other to solve a problem

○ ng-model for bi-directional updates between form inputs and model

○ a validation expression can reference several model variables

● creates chaos “in the large” ○ think all people in the building talking to any

one else

Page 18: Angular Rebooted: Components Everywhere

How to handle <folder-list> Output?Passing the selected folder to the MailController which updates the message list - ideas?

● Option 1■ $scope.$parent.currentFolder = selectedFolder

○ avoid! it makes the component non-reusable

● Option 2 - two-way binding ■ binding selectedFolder : “=”■ <folder-list selected-folder=”mailCtrl.currentFolder”>■ in the parent, $watch(‘currentFolder’, function(){

loadMessages(currentFolder)})

Page 19: Angular Rebooted: Components Everywhere

Making Outputs explicit with EventsOption 3 - The component ● detects when a significant user action takes place● updates its internal state

○ e.g. track the selected folder● updates its view

○ display the element in bold / red● sends an event to notify the parent component

○ including relevant data (e.g. folder id / name)

● lets the parent component decide what to do then○ e.g. retrieving a new message list

Page 20: Angular Rebooted: Components Everywhere

Sending the event in <folder-list>● We declare an output binding with “&”

● Angular injects an emitter function in the controller● We call it passing an Event Object including

relevant data

MailController

<folder-list> component

Page 21: Angular Rebooted: Components Everywhere

Using the component outputSpecify an expression to be executed in the parent scope when the event is received

Parent Component Controller

FolderListController

mail-view HTML

Page 22: Angular Rebooted: Components Everywhere

AdvantagesStonger Encapsulation (isolated scope + explicit binding)● changing the component internal implementation

has less impact on the rest of the application● more decoupling, less regressions

Reusability (with parametrization)● same component used in different contexts

○ <message-list> can display either folder messages and search results

Page 23: Angular Rebooted: Components Everywhere

AdvantagesBetter Collaboration● less conflicts when team grows● easier to test for regressions

More Clarity and Readability● I can effectively use a component knowing only

its API (the bindings section)● the link to other component is very clear and

explict in the HTML

Page 24: Angular Rebooted: Components Everywhere

Components all the way down

What happens if we consistently apply this pattern across the entire application?

The application becomes...

Page 25: Angular Rebooted: Components Everywhere

A tree of collaborating Components

<mail-view>

<folder-list> <message-list>

<nav-actions><common-star>

<message-view>

<common-star>

Page 26: Angular Rebooted: Components Everywhere

Types of Components

<mail-view>

<folder-list> <message-list>

<nav-actions><common-star>

<message-view>

<common-star>

more application - specific

more generic/reusable

Page 27: Angular Rebooted: Components Everywhere

Types of Components

<mail-view>

<folder-list> <message-list>

<nav-actions><common-star>

<message-view>

<common-star>

“Smart” components

“Dumb” components

Services / $http

Page 28: Angular Rebooted: Components Everywhere

Components: Smart vs Dumb ● Also called stateful● Provides data - e.g. from http

REST clients ● May receive initial data via

route resolves ● Has knowledge of the

current state● Is informed by stateless

components when something needs to change

● Also called stateless● Like a pure JavaScript

function● It receives data via property

binding● it focuses on rendering and

interaction without managing business logic

● It requests state changes through explicit events

Page 29: Angular Rebooted: Components Everywhere

Data Flow “down”: property bindingComponent pass a subset of their model to children

<mail-view>

<folder-list> <message-list>

<nav-actions><common-star>

<message-view>

<common-star>

foldersmessages

currentMessage

Page 30: Angular Rebooted: Components Everywhere

Data Flow “up”: events & callbacksComponent pass relevant events/changes to parent

<mail-view>

<folder-list> <message-list>

<nav-actions><common-star>

<message-view>

<common-star>

onSelected()

onCurrentMsg()

onStar()

onReply()

onNext()

Page 31: Angular Rebooted: Components Everywhere

Component InteractionComplex behaviour achieved through collaboration

<mail-view>

<folder-list> <message-list> <message-view>

onSelected()

Page 32: Angular Rebooted: Components Everywhere

Component InteractionComplex behaviour achieved through collaboration

<mail-view>

<folder-list> <message-list> <message-view>

messages

Page 33: Angular Rebooted: Components Everywhere

Component InteractionComplex behaviour achieved through collaboration

<mail-view>

<folder-list> <message-list> <message-view>

onSelected()

onCurrentMsg()messagescurrentMessage

Page 34: Angular Rebooted: Components Everywhere

AdvantagesIf a component passes data to its children, that it knows well, the risk of unintended side effects is low

If a component notifies its parent, the change can potentially affect unrelated / not yet developed parts ● more explicit and controlled● parent component can mediate and orchestrate

how the child interacts with the rest

Also, the tree is very good for performance

Page 35: Angular Rebooted: Components Everywhere

Component means Composable

What is the right size of a component?

Page 36: Angular Rebooted: Components Everywhere

Component means ComposableThere is no “right answer”, but...● if a component becomes too big, split it into

collaborating child components

Basic Design Principles●Low Coupling - avoid unneeded dependencies●High Cohesion - Single Responsibility Principle (SOLID Principle)− separate things that change for different

reasons or at different timesIn short: don’t put your socks in the fridge...

Page 37: Angular Rebooted: Components Everywhere

Single Responsibility appliedIf you need to do 2 things, make 3 components● A, B ● C that does A + B

Example ● <upload-attachment> does file browsing and calls

the UploadService HTTP client● <attachment-list> displays the currently attached

messages● <mail-attachments> groups the first two

Page 38: Angular Rebooted: Components Everywhere

More Component goodies● Since Angular 1.5.3, Components can declare

"lifecycle hooks"

● $onInit()○ one-time initialization after interconnected

components have been bound○ https://toddmotto.com/on-init-require-object-syntax-angular

-component● $onDestroy()

○ deallocate resources when the component is removed from the view

○ e.g. a websocket in a chat

Page 39: Angular Rebooted: Components Everywhere

Change notification● $onChanges

○ Called when “<” / input bindings are updated○ parameter: a changes object including

■ keys for each changed property■ previousValue and currentValue

● Very effective for○ compute derived values

■ compute unread messages count ○ apply filtering or sorting to data

■ display various sets of messages according to a choice

http://blog.thoughtram.io/angularjs/2016/03/29/exploring-angular-1.5-lifecycle-hooks.html

Page 40: Angular Rebooted: Components Everywhere

$onChanges: filtering message list

Page 41: Angular Rebooted: Components Everywhere

Test a Component Controller

Pass inputs to the controller and test its behaviour

ngMock module has been updated with the $componentController method

Page 42: Angular Rebooted: Components Everywhere

Test a Component

we can compile the element and test ● that it renders what we expected● that it correctly reacts to user events

So we can compile the element and test that it renders what we expected.

Page 43: Angular Rebooted: Components Everywhere

What happens in Angular 2?

Page 44: Angular Rebooted: Components Everywhere

Components in Angular 2Syntax, some costructs change, but Component-based Architecture is even stronger● no more stand-alone controllers● even application home, first-level views become

components○ component-based routing

● component metadata + Typescript allow for○ better tooling support ○ completion, validation○ more explicit API definition

Page 45: Angular Rebooted: Components Everywhere

<folder-list> in Angular2

Page 46: Angular Rebooted: Components Everywhere

Components

are

the future of web apps

Page 48: Angular Rebooted: Components Everywhere

Thank you!

● Other presentations− http://www.slideshare.net/carlo.bonamico/presentations

● Follow us on Twitter− @carlobonamico @nis_srl

● updates on AngularJS!● and some Security, Ansible, Continuous Delivery

● Contact us− [email protected] / [email protected][email protected]

● Our company− http://www.nispro.it