together
- Pull down the repository
- Try it
- Look at the template
- Look at the controller
- Look at post service
together
- Create a users service that will get the users
- from
http://jsonplaceholder.typicode.com/users
- Give it a
getmethod that uses$http - Put the
response.datainto a "data" variable on the service - Make sure it has a callback Test these now
together
- Add a function to the
postsservice called "mapUsers" - Call the
usersservice - When the
userIdfromposts.datais equal to theusers.id, add auserNamefield to theposts.data
on your own -ish
- Write tests for the users service and posts service
- Mock the
$http.getwith$httpBackend - Services are mocked with
module(function($provide){...
usersneeds to be mocked- it might feel like duplicating the function, but just simplify it to its base
- all it needs is a
datavar and agetfunction
- Services are included with
inject(function($injector){...
$httpBackend = $injector.get('$httpBackend');users = $injector.get('users');
together
- Add a new directive file
- Create a new directive called 'post'
angular.module('directings').directive('post', function(){...
- Return an object literal with one key-value:
template: "asdf" - Add a
<post>element to the template inside of the<li> - Check it out
together
- Add the
<divthat's currently in the<li>to thetemplatevalue
template: "<div><strong>Title:</strong> {{ post.title }}</div>"
- Add an attribute of
titleto thepostelement and give it a value ofpost.title
- Note: any attribute of a directive is going to take an experession
- Change
post.titleto justtitlesince that's the attribute we're using to pass in the value - Add a
scopeto the directive
return {
scope: {
title: '=title'
},
template: ...
together
- Initialize the current module
module('directings');
- Inject in the
$compileand$rootScopeservices
inject(function($compile, $rootScope){...
- Attach
$compileto a variable we can use outside of theinjectscope - Create a new localized scope from
$rootScopeand attach it to a variable outside theinjectscope
scope = $rootScope.$new();
- Create an element with
angular.elementwith the directive in it
var element = angular.element('<div><post-display post="post">{{ post.title }}</post-display></div>');
- Compile the element and attach the new, localized scope to it
compiledDirective = compile(element)(scope);
- Digest the scope
scope.$digest();
- Try the following
it
it("should have put the title in bold", function(){
var el = compiledDirective.find('strong');
expect(el).toBeDefined();
expect(el.text()).toBe(scope.post.title);
});
on your own
- Add a
post.htmlto atemplatesdirectory - Give it the HTML currently in your
templatevalue - Replace
templatewithtemplateUrland give it the value of your new html
templateUrl: '/templates/post.html'
on your own
- Add another
<div>to the<li>in index.html - Give it the
ng-includeattribute with a value of the template file you just created
- *Note:
ng-includeexpects an expression, not a string, so make sure you pass it a string ng-include="'/templates/post.html'"
- Look at what you have
- Change
titletopost.title(what it was originally) - Check it out
together
- Instead of adding
title, just add thepostvariable
<post post="post"></post>- That's so cool looking right?
- Look at that error
- Rename the
postdirective topost-display
- in both index.html and post.js
- Look at the result
- Change the directive registration to
postDisplay
- but leave the index.html the same
on your own
- Add a new controller "DisplayController"
- Put it into the index.html template in a
<div>after the list controller - Inject
posts
on your own
- Write a method in the
postsservice to set the current post - Call that method whenever a post is clicked in the list
- you should wrap it in an
<a>for accessibility - convenience class of
unlinkis available in the css
- Now you can include the
<post-display>directive in theDisplayController
together
- Wrap the directive template in a
<div> - Use
ng-ifto only show that div ifpostexists - Add a
bodyattribute to the directive, give it a booleantruevalue - Add it to the
scope - Add a
<div>to the directive's template and have it contain an expression for{{ post.body }} - Use
ng-ifto only show that if thebodyattribute is true
together
- Include the
post.titlein the body of the<post-display>tag - Remove the
post.titleexpression from the directive's template - Add
ng-transcludeto the<strong>tag - Add
transclude: trueto the directive's return object
together
- Adjust our tests...
together
npm install --save-dev karma-ng-html2js-preprocessor- Add all of your .html files to the list of Karma files
- Add the following lines to your karma config
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'src/**/*.html': ['ng-html2js']
},
ngHtml2JsPreprocessor: {
moduleName: 'templates',
stripPrefix: 'src/'
},
And add the moduleName you just put there to the angular.mocks.module call in your directive test
module('templates', 'directings');
on your own
the real reason Google developed Angular together
- Create a new directive called "blink"
- Inject
$timeoutinto the directive
$timeoutis just an angular wrapper aroundwindow.setTimeout()
- Create a function in the directive that, when taking an element as a parameter will hide that element using css's
visibility
element.css("visibility", "hidden");
- Create another function that's does the opposite of that
element.css("visibility", "visible");
- Use
$timeoutat the end of each of those functions to call the other function
$timeout(function(){ showElement(element); }, 500);
- Add a "promise" variable to the directive at the highest scope on the directive
- Assign the
$timeouts to that variable so they overwrite each other - Return a
linkfunction with the directive
linkcontrollerandcompileall take 3 parameterslink: function(scope, element, attrs){...
- Add
showElement(element);to thelinkfunction