Skip to content

Instantly share code, notes, and snippets.

@Hendrixer
Created February 14, 2015 02:41
Show Gist options
  • Save Hendrixer/bde5eee00eea1731c6bd to your computer and use it in GitHub Desktop.
Save Hendrixer/bde5eee00eea1731c6bd to your computer and use it in GitHub Desktop.
intro to directives
// Directives are easy
// Two types
// * attribute that adds functionality to an element (think jquery shit)
// * component (think custom element)
// follow below
angular.module('directives', [])
// ----------------- LEVEL ONE ------------------------------
// this directive will be an attribute directive
// we'll add functionality to an element
// lets change some css when clicked
.directive('levelOne', function(){ // dependency injection here
// the JS name of this directive is 'levelOne'
// but in HTML land it will be '<div level-one></div>'
// angukar converts camelCase to dash spaced for HTML compliant code
// this function is called the Link function
// this function IS NOT DEPENDENCY INJECTION
// it does get acces to the current scope, element, and attributes in that order
// this is where you would do jquery-ish stuff
// Directives can return this link function or an object
return function (scope, element, attr) {
// element === JqueryLite(yourElement)
// you cannot and should not traverse the DOM in here
// so do not do this 'var button = angular.element('.button');'
// that won't work, jqLite doesnt allow anything but element type selection
// not css selectors, if you need to effect another element make a directive
// for that element too. This directive can only be used as an attibute on
// another element or directive now, like ng-model
element.on('click', function(event) { // jq .on api here
element.css('height', '300px');
});
};
})
// ----------------- LEVEL TWO ------------------------------
// Now lets make a custom element that is just some plane HTML
// <level-two></level-two>
.directive('levelTwo', function() {
// Return an object instead of a link function
// called a Directive Definition Object or DDO
return {
// Resitrict tells angular how we want to use this direcitve
// Possible values are:
// 'E' = element
// 'A' = attribute
// 'C' = class
// 'M' = comment
// you can use any combo of these like 'EAC'
restrict: 'E',
// Template options are just like routes
// TemplateUrl takes a path relative to the public folder
// no the current file or an ID of a template created using
// <script type="text/ng-template" id="levelTwo"></script>
// in your index.HTML
// Template takes a HTML string or function that returns a string
// JUST LIKE ROUTING
// You ushould be using templateUrl unless your template is tiny
// like the one below. **Note** you will need a server
// to serve the templates unless you use the script tag
// method, or use template instead templateUrl, or place your
// html templates into the $templateCache manually or with a build tool
// like gulp
template: '<div>' +
'<h1>{{ message }}</h1>' +
'</div>',
// link is the same from above, think if it as 'like a controller' almost, until
// we talk about controller in directives that is. Great place for
// DOM stuff. YOU SHOULD NOT BE DOING DOM THINGS ANYWHERE IN ANGULAR BUT
// A LINK FUNCTION
link: function(scope, element, attr) {
// In our template above we get access to the scope created for us.
// By default the scope will be the same scope of the template
// we place this directive into.
scope.message = 'Yooooo';
}
};
})
// ----------------- LEVEL THREE ------------------------------
// Now lets make a more sophisticated directive and explor more properties on the DDO
.directive('levelThree', function($http) { // we can inject things in here remember?
return {
restrict: 'EA', // element or attrinute usage,
// Replace just means replace the directive with its template in the DOM
// so <level-three></level-three> becomes <div></div> or what ever the tempalte
// is in the DOM. This fixes issues sometimes
replace: true,
// this tempalteUrl is the id of a script tag template in the HTML file, go look!
templateUrl: 'level-three.html',
// WTF? transclusion is simple really. This allows us to write html inside our
// directive and for it to be included int the template above, check the html
// for more details, promise its not hard
transclusion: true,
// this is the BIG one and very important, pay attentions
// by default our directives use the same scope are the controller they're placed
// in. We can change that with the scope property.
// Possible values are:
// true means to create a child scope of the scope its placed in
// {} means create an isolate scope that inherits from nothing and is all alone
// we're gonna make an isolate scope
scope: {
// The properties on this scope indicate what attributees we can bind to
// our directive, so we can do this:
// <level-three points name update></level-three>
// all values are bound to this directives scope
// so in the link funciton
// scope.points && scope.name && scope.update will be true if you pass in values
// = means the value will have two-way data binding
// so if we pass in an array and if that array changes outise our directive
// it will also change in our directive as well and the other way around
// great oor objects and arrays
points: '=',
// @ means I want one-way data binding. So if it changes outside itll change
// here too bu not the other way around. Great for numbers and strings
name: '@',
// & means this is a function value. The function exists in some controller
// elsewhere and we want to be able to bind to it on this directives scope
// and call it whenever
update: '&'
},
link: function(scope, element, attr) {
// can use this function in our directives template on ng-click
scope.getPoints = function() {
$http.get('some/url/' + scope.name).then(function(data) {
// pushing to scope.points will update he template values
// and the controller that sent in points in the first place
// because we used '='
scope.points.push(data);
});
};
element.on('mouseenter', function(event) {
// Because this DOM event is async, angular needs to be told about it
// if you plan on updated the scope value in the callback
// what happens is if you dont do scope.$apply, the scope will get updated
// but we fail to tell angular to go check to see if it chagned and then update the view.
// so the view wont get updated until angular checks again. scope.$apply forces a check.
// all of angular's `$` services and factories do this check for you already, thats why you should
// use them whn you can.
scope.$apply(function() {
scope.name = 'some crazy name';
});
});
scope.$on('$destroy', function() {
// listen for when the directive is destroyed
// like when its not on the page anymote due to navigation
// or other removal and remove listeners
element.off('mouseenter');
})
}
};
})
// just for examples
.controller('Main', function() {
this.points = [1,2,3,4];
this.name = 'Harvey Sheen';
this.doThis = function() {
};
});
<!DOCTYPE html>
<html lang="en" ng-app="directves">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body ng-controller="Main as MainCtrl">
<!-- -------------- LEVEL ONE ------------- -->
<div level-one></div>
<!-- -------------- LEVEL TWO ------------- -->
<level-two></level-two>
<!-- -------------- LEVEL THREE ------------- -->
<level-three name="{{ MainCtrl.name }}" update="MainCtrl.doThis()" points="MainCtrl.points">
<!-- TRANSCLUDED HTML HERE -->
<div>
<h1>hey I'm transcluded!!</h1>
</div>
</level-three>
<script type="text/ng-tempalte" id="level-three.html">
// this will make a call to scope.update in the directve
// which will call MainCtrl.doThis
// greate way to pass in params n such
<div ng-click="update()">
<h1>Yoo, im am in the directves template</h1>
// above in the html where you see the transcluded
// HTML, it will be placed as a child of the div below.
// the ng-tranclude directve tells angular wher eto place
// the children HTML we wrote above, you have to use the
// transclude: true property on the dorective too
<div ng-transclude></div>
</div>
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment