Date post: | 07-Jan-2017 |
Category: |
Technology |
Upload: | codemotion |
View: | 101 times |
Download: | 0 times |
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
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
References on ComponentsAngular 1.5 Components reference https://docs.angularjs.org/guide/component
Exploring Angular 1.5 Componentshttps://toddmotto.com/exploring-the-angular-1-5-component-method/
Refactoring an 1.5 application to Componentshttps://teropa.info/blog/2015/10/18/refactoring-angular-apps-to-components.html
Components in Angular 2https://angular.io/docs/ts/latest/cookbook/component-communication.html
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