Created
February 14, 2015 02:41
-
-
Save Hendrixer/bde5eee00eea1731c6bd to your computer and use it in GitHub Desktop.
intro to directives
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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() { | |
}; | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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