Angular Rebooted: Components Everywhere

Post on 06-Apr-2017

444 views 1 download

Transcript of Angular Rebooted: Components Everywhere

Angular Rebooted: Components Everywhere

Carlo Bonamico -Sonia Pini

MILAN 25-26 NOVEMBER 2016

sonia.pini@nispro.it carlo.bonamico@nispro.it - NIS s.r.l. - a DGS companycarlo.bonamico@gmail.com – Genova Java User Group

Twitter: @carlobonamico @nis_srl

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.

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

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

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

“Spaghetti Binding” vs Components

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

Most of the concepts that we present apply to both

Angular 1.5 & Angular 2.0

although syntax is different

Example App: NG Component Mail

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

Thinking in Components

<message-list>

<folder-list> <nav-actions>

<message-viewer>

<search-panel>

<folder-list>

<message-actions>

Design the Component APIDefine input and output properties

● Keep naming conventions consistent ● Follow Clean Code guidelines

<component>

inputs

outputs

<folder-list> API and behavior

input → folder array, title, allowCreate

output → selected folder

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

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

<folder-list> - Declaring Inputs

Template

Component

Controller

Passing Inputs to <folder-list>

FolderList Component

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

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

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

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

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

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

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

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

Components all the way down

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

The application becomes...

A tree of collaborating Components

<mail-view>

<folder-list> <message-list>

<nav-actions><common-star>

<message-view>

<common-star>

Types of Components

<mail-view>

<folder-list> <message-list>

<nav-actions><common-star>

<message-view>

<common-star>

more application - specific

more generic/reusable

Types of Components

<mail-view>

<folder-list> <message-list>

<nav-actions><common-star>

<message-view>

<common-star>

“Smart” components

“Dumb” components

Services / $http

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

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

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()

Component InteractionComplex behaviour achieved through collaboration

<mail-view>

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

onSelected()

Component InteractionComplex behaviour achieved through collaboration

<mail-view>

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

messages

Component InteractionComplex behaviour achieved through collaboration

<mail-view>

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

onSelected()

onCurrentMsg()messagescurrentMessage

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

Component means Composable

What is the right size of a component?

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...

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

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

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

$onChanges: filtering message list

Test a Component Controller

Pass inputs to the controller and test its behaviour

ngMock module has been updated with the $componentController method

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.

What happens in Angular 2?

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

<folder-list> in Angular2

Components

are

the future of web apps

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− carlo.bonamico@gmail.com / carlo.bonamico@nispro.it − Sonia.pini@nispro.it

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