AngularJS Data Driven Directives Presentation Slides

Transcription

AngularJS Data Driven Directives Presentation Slides
AngularJS Data Driven
Directives
!
by Jeremy Zerr
!
Blog: http://www.jeremyzerr.com
LinkedIn: http://www.linkedin.com/in/jrzerr
Twitter: http://www.twitter.com/jrzerr
Github: https://github.com/jrzerr
Plunker: http://plnkr.co/users/jrzerr
Data Driven Directives
Using D3.js to create data visualization
Creating a Column Chart and Line Chart directive that uses D3
Making the chart interactive
Creating chart Data Models and Options objects that
correspond to each chart
Transforming data from the server into chart Data Models
compatible with the charts using a Mapper
Challenges
Create chart directives with a simple interface
Organize the data in a structured way
Transform domain data models into models compatible for
displaying using the chart directives
Avoid code duplication when creating multiple similar charts
Keeping the D3 code separate from the directive to better
adhere to Single Responsibility Principle
Code and Demo
Code is on Github at: AngularJS Data Driven Directives
Live demo on my web site: Basketball Scorebook
AngularJS Directive
Interfaces
The more complicated the directive…
the more complicated the interface
Different ways to create your
directive interface
Use directive scope to map all parameters individually
Use a small number of directive scope items to pass
larger complex data structures
Directive scope with
individual parameters
An example: AngularJS NVD3
about 50
total…
Directive scope with
individual parameters
To me this looks a lot like:
function foo(var1, var2, var3, var4, var5, var6, …) { … }
Whenever I see a function with too many arguments, code instincts
kick in and tell me that something is not designed properly:
the function is doing too much
has too many dependencies
typically solve by refactoring into subroutines or objects to
encapsulate or replacing arguments with an object (or several)
Using a data structure
An example: ng-grid
Using a data structure
This is the method I prefer
Notice the $scope.gridOptions.data argument, it is a string.
Bit of magic… being a string is special, tells the ng-grid directive to $watch the
data
I feel better about having another parameter like “doWatchData: true” that is explicit
Allows you to fine-tune your $watch and data-binding too, and even put the user in
control of that through the directive options
Also, since there are a lot of arguments, I prefer putting a little formality around that
options structure and make it into its own Object
Using a data structure
Here is an example of my
ColumnChartOptions
object
Default options already
defined if you pass no
options to the constructor.
Options you want to
override can be passed
into the constructor
Directive Inheritance?
Creating a Column Chart and Line Chart, they are very similar. So
maybe you want directive inheritance?
I say not a good idea, a directive has a well-defined public API,
you don’t want to pollute that with non-directive methods that
you would need to allow overriding methods
Consider a more flexible alternative:
Within your directive link(), use a separate View object which
you can then freely design with inheritance without worrying
about the Directive API.
Directive (View) Inheritance
FTW!
Let’s take a look at the ColumnChart directive
at charts/columnchart/ColumnChart.js
The chart creation heavy lifting is all in
ColumnChartView, which inherits some of its
functionality from ChartView.
Chart Objects
Each chart (Column Chart and Line Chart) have 4 types of
objects:
columnChart (directive <column-chart>)
ColumnChartOptions (chart configuration options)
ColumnChartView (does the D3 rendering)
ColumnChartModel (data model displayed by
ColumnChartView)
Why Create a
ColumnChartModel?
Maintaining sanity when moving large complex data
around is critical.
A ColumnChartModel is a great way to enforce a
common data format that needs to be met before
rendering the chart.
Then write Mappers that are responsible for
transforming one domain Data Model into the desired
Chart Data Model.
What does that process
look like?
Fetch data from server using $http from either GameService or
PlayerService, this is initiated from the Controller.
Before returning the data to the Controller, the response is
transformed by the Services into the domain Models:
GameModels and PlayerGameModels.
When controller data changes (seen by $watch), the domain
Models are mapped into the appropriate Chart Data Model.
The Chart Directive is $watching the Chart Data Model, when the
data changes, the Chart View is (re-)rendered.
Doing backend-less development
with a $httpBackend mock
Also a part of this github project is an example of doing
backend-less development by using a $httpBackend
mock
Great for isolating frontend from backend for testing and
also development to avoid needing a dev node server to
provide a REST API.
I have taken the code from this github project and broke
it out into a Plunker that adds more detail and more
examples specifically on this topic.
Structuring a D3
Directive
D3 Basics
Uses SVG + HTML5 + CSS3
Has its own implementations of a lot of jQuery DOMrelated functions. (selectors, styling, attributes, etc.)
It’s pretty low-level library, there’s no LineChart function.
You build it up from scratch by binding data to SVG
entities.
You can also integrate HTML with it too, for chart controls
like tooltips, legends, buttons, etc.
D3 Chart Components
Scales for X and Y
Maps data (domain) to a scale (chart pixels)
Axis for X and Y
Displays a scale
Bind data to an SVG entity like a line or a rect
Uses the scales to map the data to a chart location/dimension and plot
Add title, legend, tooltips, buttons, etc
Add events like on clicking a bar, hovering over a data point, dragging a timeline, or
transitions between different chart types or changing data sources
D3 Directive
The Directive object link function calls the render() function on the View
object (ColumnChartView or LineChartView).
Take a look at the base ChartView object to find the render() function.
Calls several render functions for different visual components.
SVG, XAxis, YAxis, Title, Data
Has functions for creating each of the components: scales, axes, SVG,
title, data.
These are overriden if necessary in the ColumnChartView or
LineChartView objects.
D3 Directive - Closer look at
ColumnChartView
Let’s take a closer look at ColumnChartView
Pieces being overriden
X and Y scales (not too much different than Line)
Data
Compare data portions
Comparing renderData()
ColumnChartView
LineChartView
Want to learn more?
Look how nvd3 builds their D3 charts: nvd3
Chart.js is another alternative to D3: Chart.js
Both have Angular adapters: Angular nvd3 and Angular Chart.js
The Angular nvd3 library is used way more than Angular Chart.js
My Demo code is on my blog: AngularJS DDD Demo Page
Slides are on my blog: AngularJS DDD Presentation page
See some code from this presentation, and more, at My Plunker Page
Thanks!
!
by Jeremy Zerr
!
Blog: http://www.jeremyzerr.com
LinkedIn: http://www.linkedin.com/in/jrzerr
Twitter: http://www.twitter.com/jrzerr
Github: https://github.com/jrzerr
Plunker: http://plnkr.co/users/jrzerr