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
get
method that uses$http
- Put the
response.data
into a "data" variable on the service - Make sure it has a callback Test these now
together
- Add a function to the
posts
service called "mapUsers" - Call the
users
service - When the
userId
fromposts.data
is equal to theusers.id
, add auserName
field to theposts.data
on your own -ish
- Write tests for the users service and posts service
- Mock the
$http.get
with$httpBackend
- Services are mocked with
module(function($provide){...
users
needs to be mocked- it might feel like duplicating the function, but just simplify it to its base
- all it needs is a
data
var and aget
function
- 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
<div
that's currently in the<li>
to thetemplate
value
template: "<div><strong>Title:</strong> {{ post.title }}</div>"
- Add an attribute of
title
to thepost
element and give it a value ofpost.title
- Note: any attribute of a directive is going to take an experession
- Change
post.title
to justtitle
since that's the attribute we're using to pass in the value - Add a
scope
to the directive
return {
scope: {
title: '=title'
},
template: ...
together
- Initialize the current module
module('directings');
- Inject in the
$compile
and$rootScope
services
inject(function($compile, $rootScope){...
- Attach
$compile
to a variable we can use outside of theinject
scope - Create a new localized scope from
$rootScope
and attach it to a variable outside theinject
scope
scope = $rootScope.$new();
- Create an element with
angular.element
with 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.html
to atemplates
directory - Give it the HTML currently in your
template
value - Replace
template
withtemplateUrl
and 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-include
attribute with a value of the template file you just created
- *Note:
ng-include
expects an expression, not a string, so make sure you pass it a string ng-include="'/templates/post.html'"
- Look at what you have
- Change
title
topost.title
(what it was originally) - Check it out
together
- Instead of adding
title
, just add thepost
variable
<post post="post"></post>
- That's so cool looking right?
- Look at that error
- Rename the
post
directive 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
posts
service 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
unlink
is available in the css
- Now you can include the
<post-display>
directive in theDisplayController
together
- Wrap the directive template in a
<div>
- Use
ng-if
to only show that div ifpost
exists - Add a
body
attribute to the directive, give it a booleantrue
value - Add it to the
scope
- Add a
<div>
to the directive's template and have it contain an expression for{{ post.body }}
- Use
ng-if
to only show that if thebody
attribute is true
together
- Include the
post.title
in the body of the<post-display>
tag - Remove the
post.title
expression from the directive's template - Add
ng-transclude
to the<strong>
tag - Add
transclude: true
to 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
$timeout
into the directive
$timeout
is 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
$timeout
at 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
$timeout
s to that variable so they overwrite each other - Return a
link
function with the directive
link
controller
andcompile
all take 3 parameterslink: function(scope, element, attrs){...
- Add
showElement(element);
to thelink
function