What is a component?
Components = controllers + scopes + directives
Components are reusable widgets or parts like a time picker or a dropdown menu.
I will talk to you about how to create visualization components with Angular and talk about the migration strategies.
What is a d3 Angular component?
D3.js is a cool JavaScript library for manipulating documents based on data. It is a collection of helper functions that makes working with DOM and DATA very pleasant. Why do we need Angular than? Because D3 is not a plug and play charts library like google charts. But by creating our own d3 components we can have our own encapsulated and reuseable visualizations.
We can take advantage of flexibility of d3 to make our visualizations as we like them and use angular to include interactivity.
“The Angular way” of integrating D3?
D3 logic in a directive
Use HTML-declarative syntax to feed of data to your directive instances
Store the data in your controller
Create Angular filters using D3 methods.
Let's talk about the angular way of integrating d3.
All your D3 logic and presentation must be contained within a directive.
Use HTML-declarative syntax to feed of data to your directive instances
By doing that, you can store the data in your controller, passing it to your D3 directive via data binding of parameters.
Another cool use of Angular and d3 is creating your custom filters.
You can take advantage of d3's formatting method's and use it easily anywhere in your application.
How we use it in html
We can declartively use our prepared components with any data anywhere.
this is our interface for angular AAANNNND angular 2!!!
//Find gifs
Or it can look like this. You can bind isolated scope properties to any DOM attribute to customize your graph. I think this is a very powerful tool.
We can use other angular directives like ng-repeat to make a lot of the graphs.
how we define Angular 1
angular.module('App', [])
.directive('graph', function() {
return {
restrict: 'E',
scope: {
data: '=bindData', // bindings
width: '@width', // static value
color: '&color' // expression
},
link: Graph
};
function Graph(scope, element, attrs) { // d3 code
};
});
JsFiddle
Directives have a link function which is essentially a “constructor”.
It contains your d3 code that assumes some sort of data but doesn't know about your data.
Scope options: The & binding allows a directive to trigger evaluation of an expression in the context of the original scope, at a specific time.
Enter and Exit
scope.$watch('data', function(data){
if (!data) return;
//divs selection with the data
divs = divs.data(data);
//remove the extra elements
divs.exit().remove();
divs.enter().append('div')
.transition().ease("elastic")
.style("width", function (d) {
return d + "%";
})
.text(function (d) {
return d + "%";
});
}, true);
Enter and exit is one of the most confusing concepts in d3.
$watch is responsible for adding or removing the necessary div tags and combination with d3’s .enter() .exit() selections.
Getting Data
d3.json('data.json', function(err, data){
//render the graph with the data
});
d3.csv('data.csv', function(err, data){...})
D3 comes with a set of useful utilities for loading data from remote sources. The most common being the d3.json() or d3.csv()‘ functions. If used properly, we can continue to use
these same functions but Angular also offers its own alternatives for loading in data.
Our directive “know” nothing about where it got its data and only care about if or when it gets data and when that data changes.
Using $http service instead of d3.json() allows us to avoid having to call $scope.$apply() directly.
$http.get('/yourApiUrl').
success(function(response) {
// when the response is available
$scope.data = response.data;
}).
error(function(response) {
});
To allow the above directive to not know about the data, we should only have it watch for changes to the data on the scope, and then we’ll load our data onto the scope from somewhere else. “someplace else” will be a controller. The controller is where the logic should go that ties together our application.
Truth about the data
Example
Array Functions
Data is never in the format that you want it to be. D3 is expecting you to feed its function a certain format of data. For example where a bar graph can be calculated from an array of numbers using the indexes as well, we need a nested object to render a chord graph.
There are couple of places you can deal with this. One of them is in your controller, you can iterate over your data to format it. D3 has all the array methods that you need.
We have all these d3 functions to iterate over our data and create the data structure we are looking for. But your data might be big and iteratio takes time.
divs.style("width", function (d) {
return scope.accessor({d:d}) + "%";
})
Accessor JSFiddle
By making the accessors configurable, we avoid having a directive that assumes a particular input format. This means our directive can accept any type of data array so long as we tell it how to pluck the specific values out of the data using the accessor expression.
TypeScript
npm install -g tsd
tsd query angular2 --action install
To get the benefits of TypeScript, we want to have the type definitions available for the compiler and the editor. TypeScript type definitions are typically published in a repo called DefinitelyTyped. To fetch one of the type definitions to the local directory, we use the tsd package manager.
npm install -g typescript@^1.5.0-beta
tsc --watch -m commonjs -t es5 --emitDecoratorMetadata app.ts
we need to run a compiler to translate your code to browser-compliant JavaScript as you work. This quickstart uses the TypeScript compiler in --watch mode, but it is also possible to do the translation in the browser as files are loaded, or configure your editor or IDE to do it.
Using TypeScript
module graphs {
export function graph(): ng.IDirective {
return {
link: ($scope: ng.IScope, element: JQuery, attributes: any) => {
...construction function goes here.
}
};
}
}
Checkout definetly typed for Type definitions for Angular JS 1.3+
You can do as much or as little as you want.
Angular 2
///
import {Component, View, bootstrap} from 'angular2/angular2';
Inside of app.ts, import the type definitions from Angular
Once you do that, your editor should be able to complete the available imports.
The module will load at runtime.
Defining a component
@Component({
selector: 'bar-graph'
})
we have just created a component that has an HTML tag named bar-graph
A component annotation describes details about the component. An annotation can be identified by its at-sign (@).
@Component({
selector: 'bar-graph'
})
@View({
templateUrl: 'path.html',
directives: []
})
class BarGraph {
...
}
A component consists of three parts, the component controller which is an ES6 class, and the decorators which tell Angular how to place the component into the page.
Every property defined in our controller class is available inside our components html with double-mustache syntax.
bootstrap(BarGraph);
Lastly we bootstrap our component.
The bootstrap() function takes a component as a parameter, enabling the component (as well as any child components it contains) to render.
You need to bootsrap only the entrance point to your app.
Inside the head tag of index.html, include the traceur-runtime and the Angular bundle. Instantiate the my-app component in the body.
Add system.import to load the module.
Service Class
@Component({
...
appInjector: [DataService]
})
class Graph {
data: Array;
constructor(dataService: DataService) {
this.data = dataService.values;
}
}
class DataService {
this.values = [1,2,3];
}
Events
{{newdata.value}}
The #newdata creates a local variable in the template that we'll refer to below in the element. The (keyup) tells Angular to trigger updates when it gets a keyup event. And the {{myname.value}} binds the text node of the
element to the input's value property.
Actually directives are still here in Angular 2. The component is just the most important type of a directive, but not the only one. A component is a directive with a view. But you can still write decorator-style directives, which do not have views.