The Abstractions of AngularJS
CC Attribution - NonCommercial - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Allen, Scott
AngularJS is a JavaScript framework for building applications with HTML. In this session we'll explore the fundamental abstractions of Angular in the context of real application. We'll see how to use controllers, models, services, filters, directives, views, templates, and more.
 Hello out there. Can you hear me? Yes. Okay. My name is Scott Allen and this is a talk on AngularJS. I usually skip some of the opening formalities. I assume if you're here you know what Angular is about. It's a framework for building complex client-side applications. If you do a search for it you'll find out the AngularJS website where you can download the framework. You can find the documentation. You can find some samples. And basically what I wanted to do today was walk you through some of the primary abstractions of AngularJS and show you how to build an application using things like directives and filters and data binding expressions, all those sorts of things. We will start with an empty page which is my default.html page. Currently this page just has some styles included. It has this funny little expression with the double mustaches, 2 plus 3. We haven't included Angular yet. And so right at this point that's the test. We haven't implemented anything yet so they all fail. Right now it just displays that 2 plus 3. So we'll include Angular. We just need Angular and a script that I'm rating in. No jQuery required. We'll talk about that later. Include Angular. Just doing that doesn't give us anything yet because once you have the Angular script included what you need to do is start adding directives to your HTML. So directives are these Angular abstractions that integrate very tightly with the DOM. You add a directive using typically ng-attributes. I'll show you how to build a custom one later. This is me saying dear Angular, please take control of this body DOM element and everything inside of it. And what Angular will do is it will look for directives like ng-app which you can also, by the way, if you're into HTML5 data validation or HTML5 validation you can add a data-prefix to that. It'll find that attribute and look through what it controls now, everything inside of the body, and look for other directives and expressions like 2 plus 3, compile them, evaluate them. So I refresh the page now and I get a 5. So this is not JavaScript that I'm rating inside of here. It's a subset of JavaScript that Angular will understand inside of these data-binding expressions which is the double mustaches. It'll look for those things, evaluate them. Typically what you don't do is hard code things, of course. Typically what you do is you have some sort of model. So there's the concept of models which is the data that you want to put onto the screen. Controllers which initialize the model. So we'll get into that. So first of all, typically don't do this. Let me do something a little more interesting. Let me have a div that's going to data-bind against something called name. And let me have an input type text that will use another directive, ng-model. So I can say data-ng-model. And that is going to also look at something called name in my model to figure out what it should display in that input. And what I want to show you first of all is an example of 2A data-binding. The fact that I'll be able to type into the input, it'll update something called name. It's also displaying in this div. And before we all do that, I'll make this a little more formal and say that I want a specific application. So an application that I'm going to configure with routes and controllers, I'll just call it myApp. But now as soon as I do that, Angular is going to start looking for something called myApp. So we're going to write that in the JavaScript. I'll create a independently, or immediately invoked function expression in iffy. Once I apply the proper curly braces here, it gets invoked. It gets closed off. I'm going to say the application is an Angular.module called myApp case sensitive. And this is how you create a module in Angular. So a module is simply an abstraction that you can use to group together different components. Some of the things we'll be looking at later, like controllers, filters, directives, services, you can put them into modules. The advantage of doing that is then that modules have configuration code that can run, that can get bootstrapped. We'll see how dependency injection works with modules. This is the name of the module. This is the list of dependencies for my module, just an empty array because I don't depend on anything else as yet. That will create that module and then I can do things like create a run function. So app.run is the ability to register a function with Angular to say this is a piece of code to execute when this application is up and running. I'll actually create that as a separate function as first. So run is a function. And I'm going to throw in two parameters to this. One called root scope and one called log. And we're simply, first of all, just going to log that the application is running. And I'll explain what these parameters are and why they're named that way, but then I'll register this run function. And I think if I did everything right, I should be able to also say root scope dot name, initialize this name property that we're going to be displaying and data binding against. We could just say it's the app. Save everything. Refresh the page. There's the app and the app in the div and you can see the application is running. So we executed our run code. I should be able to type in here now. Scott Allen. And that's one of the big benefits of Angular, the ability to have very simple pieces of JavaScript model that I can just inside of the view that has no idea what the model exactly is. Inside of the view, it can have these data binding expressions and say, I'm going to take this name and put it into an input, put it into a div. When the name changes, I want Angular to automatically keep things in sync and update the DOM elements and do all that good stuff, right? The way I'm doing that right now is I'm attaching something to an object known as root scope. So Angular is very interesting. It's a very interesting framework. It has a lot of concepts like dependency injection. When you put parameters on a function that Angular is going to call, Angular can actually analyze those parameters and figure out what you're asking for. So this one's a little easier to understand, the second parameter actually log. I'm asking Angular for the built-in log service that it has. And you can replace that service, you can decorate that service, you can do all sorts of interesting things with it. But the built-in service that comes with Angular, when you call.log or.worn or.error, what it will do is write something to the console, console.output if it's available. So there's an actual dependency injection component behind the scenes that when this function runs, it says, oh, $log, you need the log service. And it literally is looking at it by name because in JavaScript, we don't really have types. You know, in C-sharp, if you've done dependency injection, you're probably used to injecting an i-logger, an i-repository, things like that. But there's a type there that an inversion of control container can look at and say, oh, you need the i-repository, let me look that up by type name. I found one, I'll give it to you. JavaScript, we don't really have types. So it's literally looking at the name. So one thing to be aware of right from the start is what happens when a minifier runs on this code and changes these things. I was just going to give you a really quick demonstration of that because I'm using bundling and minification inside of ASP.nmvc4. And if I look at my bundle config, I have a bundle defined for my script. You don't really have to be familiar with MVC4 to understand what's going on here. But if I reference this URL, I will be getting a script that is minified. That's the big difference. It's been minified. So you know, a minifier likes to change local parameter names to make them as short as possible. Let's see what happens if I go into my default at html and instead of including my script, let's include this name, which was bundles my script. So script source equals bundles my script. I think that should work. Run this again. And we will get an error. So whenever you see something like this, unknown provider, n provider, that's Angular's way of saying that you just wrote a function that has a parameter named n and I have no idea what n is. So how do you deal with minification? We could actually look at our minified source code and see that in there. If I look at my scripts, so there was my run function that was rewritten with two parameters, n and t, to make them short. All right. So how do you fix that sort of problem? There's a couple different approaches. One, actually, I can think of three. One is to use an Angular friendly minifier. I forget the name of it. I'm sorry, you can Google that. Another approach is to do what's known as what they call annotate this function. So any function that the dependency injector is going to work against, you can give that function a property $inject. And inside of $inject, you can give it the array of things that that function will require. Right now, we're requiring root scope and we're requiring log. And the injector will look at that instead of the actual parameter name. So I could call this anything now. I could call it n or l or what have you. Just doing that should fix my problem. Let me just do one little thing because it aggressively caches these scripts. Let me just add a little query string to make sure we get a new version of the script. Yeah. So application is running and we're back up data binding and so forth. If that makes sense. Am I making any sense? Sometimes it's hard to tell when you can't see people. But cool. Let me not use the minified script just because it does get aggressively cached and then that throws things off. We'll go back to just using my script.js. All right. So that's a little bit about dependency injection. Angular does dependency injection. So if you want to write unit tests, have a fake log service, very easy to do and you can make sure that things like the application are actually calling into the logger. But this is typically not what people do. Typically people don't put their model in the application. Typically what you do is you write a controller. So I want to have a controller called a numbers controller that is actually responsible for this part of the DOM. It's going to be responsible for setting up a name, calling a web service to get the name and then setting that in the model and then Angular will take care of displaying it here and updating it from this input. So if I have a numbers controller, of course Angular is going to go out and look for a numbers controller. So I'll have to write that next. So back in my script.js. I'm going to put this in a separate iffy. Not because that's required. Just because I want to demonstrate that you could put the application in one js file and the controller in another js file and organize your application however you want and use different folder structures. So this isn't required just doing this here to make a point. I am going to pass in. I know I want the Angular module called myApp. So I want to get a reference to that module that I've already defined. MyApp. So no second parameter here. That would try to recreate it. I just want a reference to myApp. Pass that in as the module to this function. And then ultimately what I have to do is register a controller. The numbers controller. So numbers controller could look like this. Numbers controller is a function. And let me make sure I try to spell everything. Right. It would be 2Ls not 2Rs. Right. Yes. This one we could also give it a scope and a log. And let's say log that numbers controller is up. Up and running. Scope.name equals scott. We should also provide the injection here. Copy that. Just in case it gets minified. So what we're asking for this time is scope and log. I'll explain the difference between root scope and scope here in a second. And let me comment out this line temporarily. It's our controller that's going to be responsible for setting up that scope. And then finally module.controller. I'm telling Angular there is a new controller to be aware of. The numbers controller which when someone asks for the numbers controller here's the function to invoke to set things up. So doing that and refreshing. Hopefully. Oops. Let's see what did I do. Oh run is not defined. Let's see what I did up here. That's interesting. Run where? Oh. Yeah. Yeah. Yeah. Thank you. This should have been numbers controller.inject. We're annotating that function. Very good. So we're working. Thank you, sir. So that's still working. All right. So a little bit later we'll call a web service. We'll get some data. We'll bind it into the page. But before we do that I really want to explain the concept of scope in Angular because it's extremely important. When you set up an HTML page and you put these directives in place like data.ng controller, what you're telling Angular is that this controller is responsible for this part of the DOM. And so any expressions that are inside of here are going to use the scope that is defined by that controller. And you can have controllers inside of controllers and controllers inside of applications. And the important thing to understand about the scope is when it goes looking for name, it's literally looking for a property name that is defined on the scope that was set up by that controller. But this scope, when you have things inside of each other, the scope controlled here inherits from the prototypes, inherits from the scope that's set up by ng application. And that means if we were to not define a name here and instead have the name defined here, JavaScript will find that, right? There's some things in Angular where you just have to be very familiar with pieces of JavaScript. So if you're not familiar with prototypal inheritance in JavaScript, you might want to read up on it. There's a great article out here that I wrote a number of years ago called prototypes and inheritance in JavaScript. If you Google for that, you'll find it. I'm not trying to plug myself. Just saying it's out there, and I think it's pretty good. But it'll explain to you that when JavaScript walks up to this scope object and it says, please give me the name property, what the JavaScript runtime will do is look in that scope, not find a name. So it follows the prototype reference which Angular has set up to point to this scope. So it'll go to that object and say, please give me a name. And there it'll say, yes, we have a name. So it takes that value, puts it on the screen. So if I run this now, even though we don't have scope.name in the controller, since we are asking for something called name, that should be found. And it should be the app. So where does this become really interesting? Let's take this controller or this block of markup. And what we'll do is we'll have a numbers controller inside of a numbers controller. And I'm also going to take this little bit of markup and put it outside of here. Control K, control D to do some formatting. So think about this for a second. When it looks for name here, where is it going to go? It's going to go to the app because that's the abstraction that's in control of everything inside the body element. When it looks for the name here, it's going to look for this numbers controller that was instantiated. When it looks for this name, it's going to look for it in this numbers controller that was instantiated. But since none of the numbers controller defined a name right now, if I type something up here like this is the app, they're all picking up essentially the same name property, right? This particular text box is saying give me the name, doesn't find it there, follows it to the next scope, to the next scope, eventually hits that name in the root scope. Where it gets tricky, if you ever get in this nested controller situations when someone does this. So what happens there? Well in JavaScript, when you write to an object, you never write into the prototype. So when I put something in the input here, Angular is saying, oh, I have to set the name on the scope. So it literally sets the name on the scope of this numbers controller and that effectively hides the one that's in root scope. We might be off in the weeds right now, but we'll circle back to real stuff. This is the kind of stuff that you might run into that just seems very confusing at first. And the same thing happens here. This is the inner controller. So it now has its own scope with its own name property. It's completely dissociated from those other two. So at the risk of doing something very odd now, let me just show you how this is slightly different. If I say root scope has a person object that is an object that has a name property. And let's see how this is different. So instead of root scope.name, I have root scope.person.name. And I do have to change my data binding expressions a little bit. So these can be very rich. You can have greater than and less than comparisons and work with arrays and regular expressions. It's not a full, it's not the complete JavaScript language inside of here. It's just a subset that Angular knows how to parse and evaluate. But this is person.name and this is now person.name. And let me see if I can just copy and paste those so I don't have to type too much. So person.name, person.name, ctrl-k, ctrl-d. All right, same situation, but instead of going to the name property, we go to person.name. And now, when I refresh, if I come into this innermost controller, it controls everything. So if you can understand what's happening behind the scenes there, then you'll be perfectly prepared to work with Angular. But essentially, when I type inside of here, Angular is saying, oh, I need to update person.name. So go to this scope, find the person property, which isn't here. It's not here. It's in the application. Find that person property, get that object, and set the name. So now we are setting stuff in root scope. Pretty fascinating, isn't it? Just want to make you aware of scope and how they inherit and how they work in relationships like this. All right, but that's kind of enough weird stuff about Angular. I think what I wanted to show you next was something a little more realistic. These are my notes, which is, oh, yes. So typically, this is not the type of thing that people write. Typically, we're trying to build a single-page application. So we will, once I have valid HTML, include a new directive, which is data-ng-view. So this directive tells Angular that here's a DOM element where you can load the current view that should be in effect. I have two views defined in this application. Well, I have the markup defined. I don't have them loaded in yet. But if I refresh right now after I save this, refresh, there's nothing on that page, but I have numbers and I have movies. Nothing displays. What I need to do with Angular is tell it that when someone comes to hash slash numbers, load the numbers view into there, when someone comes to hash slash movies, pretend that said movies, load the movies view. So to do that, we need to add some configuration to our application. So I'm going to write a config function that is a function that takes another Angular service known as the route provider. And without route provider, I can say when someone comes to slash numbers, what I want you to do is load my email. Now, load views. I think I called it numbers.html. And you can also specify a controller. So you could wire up the controller right here. But basically, I'm saying come to this URL, go out, grab this HTML, put it into that DOM element where I had the ng view defined. And I could do the same thing with movies. So when someone comes to movies, please go to this template URL, which is views movies.html. And I can also say otherwise, if there are some strange URL that you don't recognize, please just redirect them to numbers. I think that's right. And then I have to register this config function. I should also annotate it, decorate it so that we tell everyone that it needs a route provider. But I'm not minifying right now. So let me just do an app.config. Here's a configuration function to execute when you load this module up. Let me see if any of this works. Do a save all, refresh this page. Yeah. So there's numbers. There's movies. We're going to have to fill in the code for these pages to work. And if someone comes to blah, it redirects to numbers. So that seems to work good. And of course, the advantage to this is Angular manages the browser history. So as people are navigating between things and you hit the back button, they actually go back to the previous view and things like that. Oh, and so one thing it's not doing right now is it's kind of an abrupt transition between these two. What they added fairly recently in Angular is the ability to kick off animations when certain things happen. So that looks something like data ng animate equals. And then it's like passing an JSON object. When this view raises the enter event, I want you to run the animation view enter. And I think that has to be in single quotes, but we'll find out. Let me see if this works. Refresh. Yeah. So when I go to movies, it sort of glides in. Numbers glides in. Very good, right? You could just do that all day. I'm not a UI person. So how does this work? View enter. One of the great things about Angular animations is on CSS3 capable browsers, you can just use, here we go, CSS3 animation. So view enter is going to be a class that Angular applies that we're going to transition everything. We're going to start it off invisible to the left a little bit. And when that thing becomes active, it will be in the proper position and it will be completely opaque. But it will do it with this easing function specified by Bayesian curve with those points. So you can find lots of examples on that. ng animate. All right. So here's what we have to do. We have our views loading. And that's sort of one way to break down a complex application into smaller pieces, right? I'll put things inside of different views. Then inside of a view itself, let me load up one of these views. Let's load up the numbers view. Inside of one of these views, you can also encapsulate some HTML. Let me format this up a little bit. Eventually we're going to have some numbers in here. We're going to handle a click event. What I want to do right for this moment is just show you that you can do a div with another directive ng include to say what I want you to do is go out and inside of this div load up views. I think I called it greeting.html. Let's look at that file real quick. So what I'm telling Angular is for this div, there's actually a partial view out there called underscore greeting.html. Please load that up. Stick it into the page here. That view, partial view, can use data binding expressions to get evaluated against the scope of your controller. So it should display person.name. If I refresh all this, so we get hello.app. That's another way to sort of break things down. But I want to talk about something else, something that's very powerful in Angular, something where you can build a custom directive. So instead of ng including a directive, what I would like to do is build something where I can say div migrating and have it figure out how to display a name or something like that on the page. So in order for this to work, I'm going to have to define something that is registered with Angular so it knows how to display migrating. So we'll come back into our script. Let me just do a couple other things. Let's actually remove person from up here. Because typically people don't want to mess with root scope too much. You put something in root scope since all the other scopes inherit from it. It's almost like a global object. It's almost like the global namespace. We'll just keep that in the numbers controller where it's just scope and put something more reasonable here. There we go. So let me write a custom directive. Again, I'll put it in its own little function here. Copying, pasting to avoid typing so much. Always a clue that you could do something better. But migrating is going to be a function that ultimately I have to register with this module. So here's a custom directive called migrating that when someone uses that, call this function. And so there's a bit of a naming convention here. When you camel case something in JavaScript, like migrating with no dashes in the capital G, that's what Angular goes looking for when it sees my dash greeting. That's how this things work. And if you look in that Angular source code, Angular.js, there'll be a directive in there with a function ngClick, not ng-click. So it sees data-migrating. It'll go looking for directives, migrating, like this. And what we can do from here is we return an object where you can set a number of different properties to influence how this directive is going to behave. So today, we only have so much time, I'll be able to show you about 20% of what's possible with directives. They're extremely powerful. I'll just show you a subset of things that can be done. I just want you to know there's a lot more that could be done. One thing you could do is still use a template URL. So I could say when someone's using that directive, go out to the views and load up greeting.html. And if I did everything correctly here and refresh, yes. Then we just load that up and it says hello, Scott. But if that's all you're going to do, you might as well just use ngInclude, right? Just include the partial view. So we'll do something a little more advanced. Oh, but before I do that, there's a couple different syntaxes that you can use for these directives. This is the attribute syntax. This would be the class syntax. Angular can actually look inside of a class and say, oh, I know what my greeting is. You must want a directive there. And you can also do custom HTML elements, like my greeting. Some people don't like that because HTML5 validators won't like it. Let's just see if that works. It doesn't work yet because by default, Angular only looks at attributes, I believe. When we register the directive, we would also have to tell it pass in something called restrict, restrict. Make sure I spell it. I want attributes and elements. So we have two of those. I want attributes, elements, and classes. Now all three of them display. And there's also a way to do it with HTML5, with HTML comments, attributes, elements, classes, and comments. But I really just need one thing here. So let me let's go back to just using that one. And let's get rid of the template URL. We want to do something a little more powerful. I'm going to provide a link function. So a link function, link, is a function that Angular will invoke when it's recognized that directive, when it's gotten the reference to that DOM element. It will take that DOM element, pass it to your link function, along with a scope, and the element, and the attributes that are on that element. So one thing I could do here is say element.text. Hello. Just to make sure this is working. Uh-oh. That's supposed to be a semi-whole. Did I switch languages? There we go. All right. We got hello. So that's not very interesting. What I want to be able to do is say element.text equals some sort of expression that you give me in the directives that I know what you're trying to set. So let me say, I want to say hello in someone's name. But you have to tell me the object that has the name property. So I could say data-migrating person, right? The person that's on the scope. Data-migrating person. And so one crude way to do this would be to say, okay, the name I want to display is equal to scope. So the scope object will have, that'll be my scope with the model inside of it. I want to get to attributes.migrating. Yes, migrating. All right. Index into the scope using migrating. So what is the value of this? Attributes will literally contain all of the attributes that were on that DOM element. So if I ask for attributes, migrating, that should give me person. And once I have a reference to that object, I should be able to say name. And now I should be able to say hello plus name. Let's see if that works. Oops, let's see what did I miss? Cannot read name undefined. That is because, sorry. Yeah, scope. Some attributes.migrating should give me the person. And then we should be able to get my name. Let's see what happens if we put a break point right here. I'm missing something obvious. So if I say scope. Some attributes. I'll blow this up here in a second so we're going to see it. Oh, what is attributes.migrating? So something wasn't set. Oh, because I didn't save numbers.html. Unsaved file. Save it. Cross fingers. Refresh. Run. There we go. Hello, Scott. Is that interesting? Not entirely. What if? So one of the things you want to do with a directive is sort of decouple yourself from the model as much as possible. This directive now is assuming that you're going to give me an object that has a name property. But what if I just want you to give me the name? Just give me an expression that gives me the name that I can then use to set the element.text. Well, then I could say, okay, let's use greeting equals person.name. Save the file. Which I know if I tried to use this syntax using a real expression like that, this is going to break because this will look inside of scope for a property called person.name. It won't look for person and then do a dot name. It'll look for person.name, right, on that object. So trying to run this, we'll probably get back undefined. Let me get rid of that breakpoint. Yeah, undefined. So I need something from Angular that will actually understand what person.name is and give me something that I can evaluate that. Well, fortunately, there's another service in Angular called the parse service. The dependency injector can inject it into the migrating function when it's setting up this directive. So I will need to take that parse service and save it off here and something that gets closed over. So I could say, before we return that object parse equals that parse service. One of the things I can do with parse then is I can say, give me an expression by parsing attributes.migrating. And what I can do with the expression then is invoke it, passing in the scope object. And that should dig the name out for me without me having to figure out if there's dots in that thing or not. So refresh, we're back to hello, Scott, which is good. The problem with this is that hello, Scott is written once when the link function runs. And now if someone is updating that model, that is updating person.name, but my directive is not written in a way that it's recognizing any model changes. That's something else that you need to do from inside of a directive. You have to tell Angular what you actually need to observe or watch so that when it changes, you can update your display accordingly. So actually it turns out to be fairly easy. I can say, dear Angular, I want to watch this expression. And when it changes, you can call this function for me and pass in the new value. I'll talk about this here in a second once I get everything put in place. And let's change this to I am watching something. I think that's right. Not using the expression, but I'm going to leave that there because we might need it later. Refresh the page. I am watching Scott. Alan. So now we're updating appropriately. So Angular changed detection a little bit different than some of the other frameworks that are out there. If you use knockout and backbone and some of these other ones, when your model changes, the properties on those model objects have to be observable. They have to essentially raise events that broadcast to the world that, hey, this value just got set. Now someone can go out and update the DOM. Angular works a little bit differently in the sense that my JavaScript can be plain, unobservable objects. So what is person? It's just a regular JavaScript object with a name property. And what Angular will do is when you're using directives like ngModel and these expressions like x plus y, it will set up watches on those properties. And a watcher really is, let's look at the current value. Okay, we see what the current value is. We'll save that off. And now something has happened. Let's check the value again. Oh, it changed. We have to update the screen. So it's very much like snapshot change detection, which does influence some of the applications that you can write with Angular. The rule of thumb that the team came out with is that if you have a model with over a thousand things, a thousand properties, you might start running into performance problems because every one of those thousand things is data bound on the screen somewhere. There's a thousand watchers. There's a thousand comparisons that have to happen when it figures out what's changed. There's ways to optimize around that, but it's just something to be aware of. Someone emailed me recently with a page that had a table with 10,000 rows in it, and they were wondering why performance was slowing to a crawl. It's like, well, you're going to have to come up with a different solution for that one. Making sense? At all? Yeah, maybe? Well, I'm going to forge forward. So a couple of things happening then. Oh, yeah. So we have a directive that I can essentially bind something in my model, have it update the screen. It's two-way data binding. So what I want to do now is say, when someone interacts with this element, I want to actually modify the underlying model value. So with elements, I can bind to events. Now, I said earlier, we don't need jQuery, and that's because Angular actually includes an implementation of what they call jQuery Lite, which is a subset of the jQuery API, but it's all the things that you always use. Add class, remove class, dot bind, hookup events, dot text to set the text, dot HTML, all the stuff that you use for DOM manipulation in jQuery and selecting things. It's already provided by Angular. When you get one of these elements, it's essentially wrapped by jQuery Lite. That being said, if you include the jQuery library before you include Angular.js, it will use jQuery, the full jQuery library. So you'll have all that plus whatever else jQuery is providing. But element dot bind is a way to say, I want to hook up to the click event. So when someone clicks on this, what I want to do is add exclamation points or something at the end of the string just to make it look like it's doing something. So the way I can do that is through this expression, that expression knows how to assign values. So I'm going to say expression dot assign on the scope object, take this value and add an exclamation point. Right? So every time I click, I wanted to add an exclamation point into the model on the scope. So let me refresh the page. There's no errors. I'm going to click on this a few times. It doesn't seem to be updating. There's no errors. That's weird. Let me try to update something else on the screen, like this text box. Huh. Then all of a sudden all of my exclamation points appear. So this is something else to be aware of with Angular. There's two worlds of code when you're writing an Angular application. There's the world where code runs inside of Angular or Angular is aware that the code is running. There's something from Angular on the call stack. And then there's the world where Angular doesn't know that code is executing. This is a case where Angular doesn't know this code is executing because we're just saying, bind to click event. When someone clicks it, we're going to change the model. Angular doesn't know that that executed that it changed something, so it's not going out and doing any change detection. So push that on your mental stack just for a second. We're going to come back to this situation. Before we do, I just want to do a slightly simpler scenario, which is this numbers controller. I have an input for X and input for Y. This will show X plus Y. I want to have a button that when you click on it, it will just double X and double Y. Let's see how to implement that. That's changing the model too, but it's a little bit simpler than what we're doing. So over in the numbers controller, let's initialize some things. Scope.X, let's say it starts off as a 3. Scope.Y started off as 5. Scope.DoubleIt. So I'm saying when someone clicks this button, look for something on the current scope, in the current scope, called DoubleIt, and treat it like a function. So invoke it. So Scope.DoubleIt is a function that when someone invokes that, we will say Scope.X times equals 2. Scope.Y times equals 2. Let's just see if this works. Refresh the page. So we've got a 3 and a 4 and an 8. I can bump these up. That's worked. It's updating the screen. Change X. Double everything. Double X and Y, and that also updated that div out there. So all that works. When you're inside of code that Angular knows it was called, it does the change detection for you and everything just works. It knows that it had to call DoubleIt. And so as soon as your code executed because you wired up something here with an ngClick directive, as soon as you change something inside of that function, Angular will do the change detection, figure out how to update the screen. But if you execute code inside of here without going through Angular, it doesn't know that things change. So if I had an increment function, and I said inside of here we'll do Scope.X plus equals 1 and Scope.Y plus equals 1, and then we do a set timeout. Let's do a set timeout. So every, well, we'll start calling this after one second. And then just to make things a little bit dramatic after every 250 milliseconds we'll keep calling it. Run this. No changes appearing on the screen because set timeout is just calling that code increment function. Angular doesn't know that's happening. If I try to update something on the screen, like change X, oh yeah, I can see something's getting doubled, right? Why was way up there? Angular doesn't know that things are changing. Instead of set timeout, what I should be using is another service in Angular, the timeout service that's basically a wrapper for set timeout. But it's through an Angular service. So again, it's about testability. You could fake that out in a unit test, make sure the controller was calling timeout for some reason. But now if I say let's use the timeout service to invoke that function, well, timeout does a little bit smarter and knows that things might change. And I think I also have to change my injection here. Or using timeout service. Let me refresh. So through the timeout service, things are changing. Angular knows that something was changed when it called that function back. Yeah. Pretty exciting, isn't it? You guys glad you came to the session. All right. Let me take this out so it doesn't become annoying. How do we do that? How do we do that from our own code? Well, when you're writing a directive and you're changing something in the model, you should always do one of two things. Either call apply after that is finished. That's the way of telling Angular, okay, code just executed. Probably made some changes. I need to you to go through and do your digest cycle and see what changed and update the screen appropriately. If you want to do it the really safe way, though, you can also invoke apply and pass in a function of the code that might change the value. The advantage to this being if that code that is changing stuff throws an exception somewhere along the line, Angular will still do its apply change detection stuff. Right. And update the screen. Save this. Refresh. Now let me click my directive. Now you can see it's actually updating appropriately. Right. So that's how you would change the model from a directive. So directives are really that piece of, they're like glue between the DOM and your model. The model for a controller should really never do any DOM manipulation. The model, the things that you put on scope, they're very much, you treat them like a view model if you've ever done silverlight or WPF development. They don't really know about the view. You just set properties on things. You write functions that modify things. And it's the data binding expressions and the directives that take care of pulling data out of there, modifying the DOM, wiring up click events in the DOM. You would never write DOM manipulation code inside of the controller, basically. And that means we should have at least one passing test inside of here. I'm hoping. Yeah, should double it, actually, is a passing test. Let me show you the test real quick. Don't know if we'll have time to cover these in much detail today, but a test for that controller for double it could look as easy as this. I want you to initialize X to 10 and if someone doubles it, I would expect it to be 20 after it's doubled. There's a little bit of setup code to get there. You basically have to instantiate the controller and provide maybe a fake for the timeout service, but they very much want you to be able to unit test your models and controllers. All right. Let's try to get through some material here. We have the numbers view working, I believe. We did the double it. We have the custom director right. So let's look at movies, which is a little more realistic scenario. So what I want to do here is have a movies controller that will, which we don't have yet, a movies controller that will go out and we'll call a web service that sits at slash api slash movies that returns some movie information in JSON. This is showing XML, but that's because I ran it through the browser, but it'll hit that end point, pull back some movies, display them in a table, allow me to edit them, let me save them. We need a movies controller to do that. So function. I need a reference again to angular. I'm going to put this in my app also. That's going to be my module. So my movies controller is a function that will take a scope. That's where I'll put my model. Also going to take another service called the HTTP service. You can write your own custom services, by the way, very easy to write, have them injected in to controllers and directives and other things like that. Typically what people would do, a lot of people wouldn't use dollar sign HTTP service directly from a controller. They would hide it behind their own custom service. There's a number of advantages to that, including caching. And sometimes it's easier to test that way. We're just going to use it right from the controller, just, well, in the interest of time. This is basically like dollar sign.ajax. HTTP has get, put post methods, JSONP method, I'm going to get API movies. It returns a promise. So I can say.then or.always or I believe there's a.air. Then after you have retrieved the movies, call this function with the result. What I want to do is take the data that comes back and put it into my scope. So scope.movies equals result.data. And let's check the view real quick. So the view is building a table. And then this is a big directive that you'll use quite often, the ng repeat directive. It's basically saying find the movies property on the scope. And essentially for each movie that you find in the movie's collection, actually repeat the following DOM elements. So basically, well, repeat these DOM elements. Repeat a table row for each movie that you find. And it sets up a new scope for each, one of those repeated DOM elements, where the movie, the single movie that pulled out is the scope. So when I say things like movie.id, movie.title, movie.release date, it should be pulling that out for each individual movie, putting it into a table cell there. Pretty good stuff, right? See if it works. Refresh this and I didn't save something. Still got an error, which is movies controller is not a function. Oh, right. So I bet I forgot a step. We wrote the movies controller function. I never told Angular about it. So dear module, there is a controller called movies controller. This is the function to use. We should annotate it for dependency injection, but we'll get to that. All right. So we got movies from my web service. Very good. It's very ugly display. What are some things we could do to improve this? Well, we could go into the view. And since I'm using bootstrap, I guess one thing I could do is say this is a table, table, hover, effects. That doesn't really matter. Table striped effects. Slightly better. Release date. Not pretty. How do I modify the release date so it's a pretty value? Here's another category of abstractions in Angular. Things called filters. Filters are things that you can pipe into. So I could say, please pipe this into a filter called date. And that date, I can give it a parameter. I want you to display a date with the year, a four-digit year. And you can also do month, year, whatever type of syntax you want. Do a save all here. Yeah. So we just have a four-digit year. So filters are a nice way of formatting things, keeping that code out of the model, keeping that code out of the controller, not having to change your API or the JSON that comes back. You just pipe things through a filter. They're also very easy to write. They're essentially a function that takes a value. And you modify the value and you return it. What else do we want to do here? We want to edit things. So when I click on the edit button, how do I edit this movie? This is already set up with an ng-click directive that says someone clicks the button, call this function, pass in the current movie that's in scope. So I just need to, in my controller, say scope.edit is a function that takes a movie. And it looks like this editing section, a couple different things going on. So first of all, there's an ng-show directive. That's a really easy way to turn a DOM element on or off. Basically, it looks at this expression on the current scope. And if it's truthy, it'll show it. If it's falsy, there's no DOM element. It'll hide it. So literally, when we're editing, if I say scope.editing equals true, that should turn that view on. Also looks like we are binding now against edit movie. So edit movie.title, edit movie.release date. Let me say scope.edit movie equals that incoming movie that you just passed me. Let's see if this works. I'm going to edit star king. I don't know how I came up with these movie names. They're ridiculous. So I'm editing that JavaScript object. I edit star king over here. That's the same object as what's in the table. So you can see the data binding works to update the table, which might not be what I want. I might want to get a copy of that object so I can modify it and not update the table until users are ready to commit that somehow. So I would probably do something like Angular. There's a copy, a deep copy method helper. Angular.copy that movie. Now I should have a distinct copy of, let's say, Star Wars. So if I make changes over here, they're not going to be propagated over there until I click save. Let's see what the save button does. Save. I was just going to call a function called save and pass in the movie. There's also a cancel, which effectively stops the edit. Let's implement that stuff real quick. So scope.cancel as a function. I guess all I really have to do here is say scope.editing equals false. That should be enough where I should be able to say let's cancel it. Very good. And scope.save, that's a function where you give me the movie that you want to save. Obstensibly, I can do an htdb.put there, put that movie back to the web server, tell it to save it in the database. I probably also want to update the movie that's in the table, which I guess if I had a library like underscore, it would be a little bit easier because I guess the best way to do it right now is to say let's go through the movies that we have in the model. And when we find the movie that has the same id as that incoming movie, that's the one we want to update. So we'll break out of the loop. But here I could do angular.extend, which is a lot like jQuery.extend. Take this object and this object and move all the properties into it. Extends scope.movies sub i with that incoming movie, if I'm making sense. I hope I'm making some sense. Let's try to edit star king. I have no idea if that's really a movie. Star king 2, save it. Uh oh. What did I miss? Movies is not defined. Uh, yeah, that's interesting. Oh, how did that sneak in there? Yeah, yeah, yeah, thank you. Now I see it. Hopefully that's the problem. Save it. Yes, thank you. So that's the, that would be, that would be an example of something that you could do with angular that you'll notice is amazingly easy, right? That's a very complex page. It's showing things, hiding things, putting things on the server, retrieving things from the server. But it's all right here. It's relatively straightforward. It's also not too difficult to unit test. I haven't completely implemented the update movies the way it wants to be implemented. But just to show you some of the tests again. This is an example of, I expect after the movie controller gets instantiated, it should have made a call to the web server to get API movies. And I would expect after all the asynchronous stuff is done that the scope.movies.length, it'll have three movies in there. And I expect if I call scope.edit that it'll turn on the editing flag so that DOM element appears. So lots of interesting ways to write unit tests. And I think, let me just check something real quick. I think I covered 90% of what I wanted to show you today. So I'll just open it up for questions. We only have a couple minutes left. Well, if there's no questions. Ah, so the question is why Angular not knockout. It's a very personal decision, I believe. Some people use knockout and they like it. Some people use knockout and they just doesn't do it for them. I kind of fall into that category. The first time I tried Angular honest to goodness and I looked at their examples and I saw things like ng-click, it turned me off and I disregarded it for about four months and then I came back to it. Actually went through their tutorial. So if you want another good tutorial on Angular, they have on the Angular web page here a link to a tutorial where you bring down the Git repository and you go through different steps that they have tagged and it'll show you how to build an application that has a master detail view. Very interesting. When I went through that, then that's when I said this is the one. It doesn't funkify stuff so you don't have to make your model observable. You don't have to do crazy things to, you know, every property becomes a function. I really like this data binding syntax. I like candle bars or mustaches, whatever you want to call them. I think it has a lot of flexibility with the directives. The downsides to Angular are the documentation is not that good. It is complex. If you haven't worked with inversion of control containers and dependency injectors and an MVVM type pattern before, it can all be quite overwhelming. But I think the simple cases are very simple. They're very easy to do. The hard cases where you have to build custom directives, that requires a little bit of work. So does that answer the question? I like it. So if you have any other questions, my email address is this and you can email me. I can give you the code that I wrote today and I have some Plural Site cards. If you want to watch some Plural Site videos, it's a free monthly subscription. So $30 value. Thank you for coming. Hope you enjoyed it.
 Hello out there. Can you hear me? Yes. Okay. My name is Scott Allen and this is a talk  on AngularJS. I usually skip some of the opening formalities. I assume if you're here you know  what Angular is about. It's a framework for building complex client-side applications.  If you do a search for it you'll find out the AngularJS website where you can download  the framework. You can find the documentation. You can find some samples. And basically what I  wanted to do today was walk you through some of the primary abstractions of AngularJS and show  you how to build an application using things like directives and filters and data binding  expressions, all those sorts of things. We will start with an empty page which is my default.html  page. Currently this page just has some styles included. It has this funny little expression  with the double mustaches, 2 plus 3. We haven't included Angular yet. And so right at this point  that's the test. We haven't implemented anything yet so they all fail. Right now it just displays  that 2 plus 3. So we'll include Angular. We just need Angular and a script that I'm rating in. No  jQuery required. We'll talk about that later. Include Angular. Just doing that doesn't give us  anything yet because once you have the Angular script included what you need to do is start  adding directives to your HTML. So directives are these Angular abstractions that integrate very  tightly with the DOM. You add a directive using typically ng-attributes. I'll show you how to  build a custom one later. This is me saying dear Angular, please take control of this body DOM  element and everything inside of it. And what Angular will do is it will look for directives  like ng-app which you can also, by the way, if you're into HTML5 data validation or HTML5 validation  you can add a data-prefix to that. It'll find that attribute and look through what it controls  now, everything inside of the body, and look for other directives and expressions like 2 plus 3,  compile them, evaluate them. So I refresh the page now and I get a 5. So this is not JavaScript  that I'm rating inside of here. It's a subset of JavaScript that Angular will understand inside of  these data-binding expressions which is the double mustaches. It'll look for those things, evaluate  them. Typically what you don't do is hard code things, of course. Typically what you do is you  have some sort of model. So there's the concept of models which is the data that you want to put  onto the screen. Controllers which initialize the model. So we'll get into that. So first of all,  typically don't do this. Let me do something a little more interesting. Let me have a div  that's going to data-bind against something called name. And let me have an input type text  that will use another directive, ng-model. So I can say data-ng-model. And that is going to also  look at something called name in my model to figure out what it should display in that input.  And what I want to show you first of all is an example of 2A data-binding. The fact that I'll  be able to type into the input, it'll update something called name. It's also displaying in  this div. And before we all do that, I'll make this a little more formal and say that I want a  specific application. So an application that I'm going to configure with routes and controllers,  I'll just call it myApp. But now as soon as I do that, Angular is going to start looking for  something called myApp. So we're going to write that in the JavaScript. I'll create a  independently, or immediately invoked function expression in iffy. Once I apply the proper  curly braces here, it gets invoked. It gets closed off. I'm going to say the application  is an Angular.module called myApp case sensitive. And this is how you create a module in Angular.  So a module is simply an abstraction that you can use to group together different components.  Some of the things we'll be looking at later, like controllers, filters, directives, services,  you can put them into modules. The advantage of doing that is then that modules have configuration  code that can run, that can get bootstrapped. We'll see how dependency injection works with  modules. This is the name of the module. This is the list of dependencies for my module,  just an empty array because I don't depend on anything else as yet. That will create that  module and then I can do things like create a run function. So app.run is the ability to register  a function with Angular to say this is a piece of code to execute when this application is up and  running. I'll actually create that as a separate function as first. So run is a function.  And I'm going to throw in two parameters to this. One called root scope and one called log.  And we're simply, first of all, just going to log that the application is running.  And I'll explain what these parameters are and why they're named that way, but then I'll register  this run function. And I think if I did everything right, I should be able to also say root scope  dot name, initialize this name property that we're going to be displaying and data binding against.  We could just say it's the app. Save everything. Refresh the page. There's the app and the app  in the div and you can see the application is running. So we executed our run code. I should  be able to type in here now. Scott Allen. And that's one of the big benefits of Angular,  the ability to have very simple pieces of JavaScript model that I can just inside of the view that  has no idea what the model exactly is. Inside of the view, it can have these data binding  expressions and say, I'm going to take this name and put it into an input, put it into a div.  When the name changes, I want Angular to automatically keep things in sync and update the DOM  elements and do all that good stuff, right? The way I'm doing that right now is I'm attaching  something to an object known as root scope. So Angular is very interesting. It's a very  interesting framework. It has a lot of concepts like dependency injection. When you put parameters  on a function that Angular is going to call, Angular can actually analyze those parameters  and figure out what you're asking for. So this one's a little easier to understand,  the second parameter actually log. I'm asking Angular for the built-in log service  that it has. And you can replace that service, you can decorate that service, you can do all  sorts of interesting things with it. But the built-in service that comes with Angular,  when you call.log or.worn or.error, what it will do is write something to the console,  console.output if it's available. So there's an actual dependency injection component behind the  scenes that when this function runs, it says, oh, $log, you need the log service. And it literally  is looking at it by name because in JavaScript, we don't really have types. You know, in C-sharp,  if you've done dependency injection, you're probably used to injecting an i-logger, an i-repository,  things like that. But there's a type there that an inversion of control container can look at  and say, oh, you need the i-repository, let me look that up by type name. I found one, I'll give  it to you. JavaScript, we don't really have types. So it's literally looking at the name. So one  thing to be aware of right from the start is what happens when a minifier runs on this code and  changes these things. I was just going to give you a really quick demonstration of that because I'm  using bundling and minification inside of ASP.nmvc4. And if I look at my bundle config, I have a  bundle defined for my script. You don't really have to be familiar with MVC4 to understand what's  going on here. But if I reference this URL, I will be getting a script that is minified. That's  the big difference. It's been minified. So you know, a minifier likes to change local parameter  names to make them as short as possible. Let's see what happens if I go into my default at  html and instead of including my script, let's include this name, which was bundles my script.  So script source equals bundles my script. I think that should work. Run this again.  And we will get an error. So whenever you see something like this, unknown provider,  n provider, that's Angular's way of saying that you just wrote a function that has a parameter  named n and I have no idea what n is. So how do you deal with minification? We could actually look  at our minified source code and see that in there. If I look at my scripts, so there was my run  function that was rewritten with two parameters, n and t, to make them short. All right. So how do  you fix that sort of problem? There's a couple different approaches. One, actually, I can think  of three. One is to use an Angular friendly minifier. I forget the name of it. I'm sorry,  you can Google that. Another approach is to do what's known as what they call annotate this function.  So any function that the dependency injector is going to work against, you can give that function  a property $inject. And inside of $inject, you can give it the array of things that that function  will require. Right now, we're requiring root scope and we're requiring log. And the injector  will look at that instead of the actual parameter name. So I could call this anything now. I could  call it n or l or what have you. Just doing that should fix my problem. Let me just do one little  thing because it aggressively caches these scripts. Let me just add a little query string to make  sure we get a new version of the script. Yeah. So application is running and we're back up  data binding and so forth. If that makes sense. Am I making any sense? Sometimes it's hard to tell  when you can't see people. But cool. Let me not use the minified script just because it does get  aggressively cached and then that throws things off. We'll go back to just using my script.js.  All right. So that's a little bit about dependency injection. Angular does dependency  injection. So if you want to write unit tests, have a fake log service, very easy to do and you  can make sure that things like the application are actually calling into the logger. But this  is typically not what people do. Typically people don't put their model in the application. Typically  what you do is you write a controller. So I want to have a controller called a numbers controller  that is actually responsible for this part of the DOM. It's going to be responsible for setting up a  name, calling a web service to get the name and then setting that in the model and then  Angular will take care of displaying it here and updating it from this input. So if I have a numbers  controller, of course Angular is going to go out and look for a numbers controller. So I'll have  to write that next. So back in my script.js. I'm going to put this in a separate iffy. Not because  that's required. Just because I want to demonstrate that you could put the application in one js file  and the controller in another js file and organize your application however you want and use different  folder structures. So this isn't required just doing this here to make a point. I am going to pass in.  I know I want the Angular module called myApp. So I want to get a reference to that module that  I've already defined. MyApp. So no second parameter here. That would try to recreate it. I just want  a reference to myApp. Pass that in as the module to this function. And then ultimately what I have  to do is register a controller. The numbers controller. So numbers controller could look  like this. Numbers controller is a function. And let me make sure I try to spell everything.  Right. It would be 2Ls not 2Rs. Right. Yes. This one we could also give it a scope and a log.  And let's say log that numbers controller is up. Up and running. Scope.name equals scott.  We should also provide the injection here. Copy that. Just in case it gets minified. So what we're  asking for this time is scope and log. I'll explain the difference between root scope and scope here  in a second. And let me comment out this line temporarily. It's our controller that's going to  be responsible for setting up that scope. And then finally module.controller. I'm telling Angular  there is a new controller to be aware of. The numbers controller which when someone asks for  the numbers controller here's the function to invoke to set things up. So doing that and refreshing.  Hopefully. Oops. Let's see what did I do. Oh run is not defined. Let's see what I did up here.  That's interesting. Run where? Oh. Yeah. Yeah. Yeah. Thank you. This should have been numbers  controller.inject. We're annotating that function. Very good. So we're working. Thank you, sir.  So that's still working. All right. So a little bit later we'll call a web service. We'll get  some data. We'll bind it into the page. But before we do that I really want to explain  the concept of scope in Angular because it's extremely important. When you set up an HTML page  and you put these directives in place like data.ng controller, what you're telling Angular is that  this controller is responsible for this part of the DOM. And so any expressions that are inside  of here are going to use the scope that is defined by that controller. And you can have controllers  inside of controllers and controllers inside of applications. And the important thing to  understand about the scope is when it goes looking for name, it's literally looking for a property  name that is defined on the scope that was set up by that controller. But this scope, when you have  things inside of each other, the scope controlled here inherits from the prototypes, inherits from  the scope that's set up by ng application. And that means if we were to not define a name here  and instead have the name defined here, JavaScript will find that, right? There's some things in  Angular where you just have to be very familiar with pieces of JavaScript. So if you're not familiar  with prototypal inheritance in JavaScript, you might want to read up on it. There's a great  article out here that I wrote a number of years ago called prototypes and inheritance in JavaScript.  If you Google for that, you'll find it. I'm not trying to plug myself. Just saying it's out there,  and I think it's pretty good. But it'll explain to you that when JavaScript walks up to this scope  object and it says, please give me the name property, what the JavaScript runtime will do is  look in that scope, not find a name. So it follows the prototype reference which Angular has set up  to point to this scope. So it'll go to that object and say, please give me a name. And there it'll  say, yes, we have a name. So it takes that value, puts it on the screen. So if I run this now,  even though we don't have scope.name in the controller, since we are asking for something  called name, that should be found. And it should be the app. So where does this become really  interesting? Let's take this controller or this block of markup. And what we'll do is we'll have  a numbers controller inside of a numbers controller. And I'm also going to take this little bit of  markup and put it outside of here. Control K, control D to do some formatting. So think about  this for a second. When it looks for name here, where is it going to go? It's going to go to the  app because that's the abstraction that's in control of everything inside the body element.  When it looks for the name here, it's going to look for this numbers controller that was  instantiated. When it looks for this name, it's going to look for it in this numbers controller  that was instantiated. But since none of the numbers controller defined a name right now,  if I type something up here like this is the app,  they're all picking up essentially the same name property, right? This particular text box is  saying give me the name, doesn't find it there, follows it to the next scope, to the next scope,  eventually hits that name in the root scope. Where it gets tricky, if you ever get in this nested  controller situations when someone does this. So what happens there? Well in JavaScript, when you  write to an object, you never write into the prototype. So when I put something in the input  here, Angular is saying, oh, I have to set the name on the scope. So it literally sets the name  on the scope of this numbers controller and that effectively hides the one that's in root scope.  We might be off in the weeds right now, but we'll circle back to real stuff. This is the kind of  stuff that you might run into that just seems very confusing at first. And the same thing happens  here. This is the inner controller. So it now has its own scope with its own name property. It's  completely dissociated from those other two. So at the risk of doing something very odd now,  let me just show you how this is slightly different. If I say root scope has a person object that is  an object that has a name property. And let's see how this is different. So instead of root scope.name,  I have root scope.person.name. And I do have to change my data binding expressions a little bit.  So these can be very rich. You can have greater than and less than comparisons and work with arrays  and regular expressions. It's not a full, it's not the complete JavaScript language inside of here.  It's just a subset that Angular knows how to parse and evaluate. But this is person.name and this  is now person.name. And let me see if I can just copy and paste those so I don't have to type too  much. So person.name, person.name, ctrl-k, ctrl-d. All right, same situation, but instead of going  to the name property, we go to person.name. And now, when I refresh, if I come into this  innermost controller, it controls everything. So if you can understand what's happening behind  the scenes there, then you'll be perfectly prepared to work with Angular. But essentially,  when I type inside of here, Angular is saying, oh, I need to update person.name. So go to this scope,  find the person property, which isn't here. It's not here. It's in the application. Find that person  property, get that object, and set the name. So now we are setting stuff in root scope. Pretty  fascinating, isn't it? Just want to make you aware of scope and how they inherit and how they work  in relationships like this. All right, but that's kind of enough weird stuff about Angular. I think  what I wanted to show you next was something a little more realistic. These are my notes,  which is, oh, yes. So typically, this is not the type of thing that people write. Typically,  we're trying to build a single-page application. So we will, once I have valid HTML, include a new  directive, which is data-ng-view. So this directive tells Angular that here's a DOM element  where you can load the current view that should be in effect. I have two views defined in this  application. Well, I have the markup defined. I don't have them loaded in yet. But if I refresh  right now after I save this, refresh, there's nothing on that page, but I have numbers and I  have movies. Nothing displays. What I need to do with Angular is tell it that when someone comes to  hash slash numbers, load the numbers view into there, when someone comes to hash slash movies,  pretend that said movies, load the movies view. So to do that, we need to add some configuration  to our application. So I'm going to write a config function that is a function that takes  another Angular service known as the route provider. And without route provider, I can say  when someone comes to slash numbers, what I want you to do is load my email. Now, load  views. I think I called it numbers.html. And you can also specify a controller. So you could  wire up the controller right here. But basically, I'm saying come to this URL, go out, grab this  HTML, put it into that DOM element where I had the ng view defined. And I could do the same thing  with movies. So when someone comes to movies, please go to this template URL, which is views  movies.html. And I can also say otherwise, if there are some strange URL that you don't recognize,  please just redirect them to numbers. I think that's right. And then I have to register this  config function. I should also annotate it, decorate it so that we tell everyone that it  needs a route provider. But I'm not minifying right now. So let me just do an app.config.  Here's a configuration function to execute when you load this module up. Let me see if any of  this works. Do a save all, refresh this page. Yeah. So there's numbers. There's movies. We're  going to have to fill in the code for these pages to work. And if someone comes to  blah, it redirects to numbers. So that seems to work good. And of course, the advantage to this  is Angular manages the browser history. So as people are navigating between things and you hit  the back button, they actually go back to the previous view and things like that. Oh, and so  one thing it's not doing right now is it's kind of an abrupt transition between these two. What  they added fairly recently in Angular is the ability to kick off animations when certain things  happen. So that looks something like data ng animate equals. And then it's like passing an  JSON object. When this view raises the enter event, I want you to run the animation view enter. And I  think that has to be in single quotes, but we'll find out. Let me see if this works. Refresh. Yeah.  So when I go to movies, it sort of glides in. Numbers glides in. Very good, right? You could  just do that all day. I'm not a UI person. So how does this work? View enter. One of the great  things about Angular animations is on CSS3 capable browsers, you can just use, here we go,  CSS3 animation. So view enter is going to be a class that Angular applies that we're going to  transition everything. We're going to start it off invisible to the left a little bit. And when  that thing becomes active, it will be in the proper position and it will be completely opaque.  But it will do it with this easing function specified by Bayesian curve with those points.  So you can find lots of examples on that. ng animate. All right. So here's what we have to do.  We have our views loading. And that's sort of one way to break down a complex application into  smaller pieces, right? I'll put things inside of different views. Then inside of a view itself,  let me load up one of these views. Let's load up the numbers view.  Inside of one of these views, you can also encapsulate some HTML. Let me format this up a  little bit. Eventually we're going to have some numbers in here. We're going to handle a click  event. What I want to do right for this moment is just show you that you can do a div with another  directive ng include to say what I want you to do is go out and inside of this div load up views.  I think I called it greeting.html. Let's look at that file real quick. So what I'm telling  Angular is for this div, there's actually a partial view out there called underscore greeting.html.  Please load that up. Stick it into the page here. That view, partial view, can use data  binding expressions to get evaluated against the scope of your controller. So it should display  person.name. If I refresh all this, so we get hello.app. That's another way to sort of break  things down. But I want to talk about something else, something that's very powerful in Angular,  something where you can build a custom directive. So instead of ng including a directive,  what I would like to do is build something where I can say div migrating and have it figure out  how to display a name or something like that on the page. So in order for this to work, I'm going  to have to define something that is registered with Angular so it knows how to display migrating.  So we'll come back into our script. Let me just do a couple other things. Let's actually remove  person from up here. Because typically people don't want to mess with root scope too much. You  put something in root scope since all the other scopes inherit from it. It's almost like a global  object. It's almost like the global namespace. We'll just keep that in the numbers controller  where it's just scope and put something more reasonable here. There we go.  So let me write a custom directive. Again, I'll put it in its own little function here.  Copying, pasting to avoid typing so much. Always a clue that you could do something better. But  migrating is going to be a function that ultimately I have to register with this module.  So here's a custom directive called migrating that when someone uses that, call this function.  And so there's a bit of a naming convention here. When you camel case something in JavaScript,  like migrating with no dashes in the capital G, that's what Angular goes looking for when it sees  my dash greeting. That's how this things work. And if you look in that Angular source code,  Angular.js, there'll be a directive in there with a function ngClick, not ng-click.  So it sees data-migrating. It'll go looking for directives, migrating, like this. And what we  can do from here is we return an object where you can set a number of different properties to  influence how this directive is going to behave. So today, we only have so much time, I'll be able  to show you about 20% of what's possible with directives. They're extremely powerful. I'll  just show you a subset of things that can be done. I just want you to know there's a lot more  that could be done. One thing you could do is still use a template URL. So I could say when  someone's using that directive, go out to the views and load up greeting.html. And if I did  everything correctly here and refresh, yes. Then we just load that up and it says hello, Scott.  But if that's all you're going to do, you might as well just use ngInclude, right? Just include  the partial view. So we'll do something a little more advanced. Oh, but before I do that, there's  a couple different syntaxes that you can use for these directives. This is the attribute syntax.  This would be the class syntax. Angular can actually look inside of a class and say, oh,  I know what my greeting is. You must want a directive there. And you can also do custom  HTML elements, like my greeting. Some people don't like that because HTML5 validators won't like it.  Let's just see if that works. It doesn't work yet because by default, Angular only looks at  attributes, I believe. When we register the directive, we would also have to tell it  pass in something called restrict, restrict. Make sure I spell it. I want attributes and elements.  So we have two of those. I want attributes, elements, and classes.  Now all three of them display. And there's also a way to do it with HTML5, with HTML comments,  attributes, elements, classes, and comments. But I really just need one thing here. So let me  let's go back to just using that one. And let's get rid of the template URL.  We want to do something a little more powerful. I'm going to provide a link function. So a link  function, link, is a function that Angular will invoke when it's recognized that directive,  when it's gotten the reference to that DOM element. It will take that DOM element, pass it to your  link function, along with a scope, and the element, and the attributes that are on that element.  So one thing I could do here is say element.text. Hello. Just to make sure this is working.  Uh-oh. That's supposed to be a semi-whole. Did I switch languages? There we go. All right.  We got hello. So that's not very interesting. What I want to be able to do is say element.text  equals some sort of expression that you give me in the directives that I know what you're  trying to set. So let me say, I want to say hello in someone's name. But you have to tell me the  object that has the name property. So I could say data-migrating person, right? The person that's  on the scope. Data-migrating person. And so one crude way to do this would be to say, okay,  the name I want to display is equal to scope. So the scope object will have, that'll be my scope  with the model inside of it. I want to get to attributes.migrating. Yes, migrating.  All right. Index into the scope using migrating. So what is the value of this? Attributes will  literally contain all of the attributes that were on that DOM element. So if I ask for attributes,  migrating, that should give me person. And once I have a reference to that object, I should be able  to say name. And now I should be able to say hello plus name. Let's see if that works. Oops,  let's see what did I miss? Cannot read name undefined. That is because, sorry.  Yeah, scope. Some attributes.migrating should give me the person.  And then we should be able to get my name. Let's see what happens  if we put a break point right here. I'm missing something obvious.  So if I say scope. Some attributes. I'll blow this up here in a second so we're going to see it.  Oh, what is attributes.migrating? So something wasn't set. Oh, because I didn't save numbers.html.  Unsaved file. Save it. Cross fingers. Refresh. Run. There we go.  Hello, Scott. Is that interesting? Not entirely. What if? So one of the things you want to do  with a directive is sort of decouple yourself from the model as much as possible. This directive now  is assuming that you're going to give me an object that has a name property. But what if I just want  you to give me the name? Just give me an expression that gives me the name that I can then use to  set the element.text. Well, then I could say, okay, let's use greeting equals person.name.  Save the file. Which I know if I tried to use this syntax using a real expression like that,  this is going to break because this will look inside of scope for a property called person.name.  It won't look for person and then do a dot name. It'll look for person.name, right, on that object.  So trying to run this, we'll probably get back undefined. Let me get rid of that breakpoint.  Yeah, undefined. So I need something from Angular that will actually understand what  person.name is and give me something that I can evaluate that. Well, fortunately,  there's another service in Angular called the parse service. The dependency injector can inject it  into the migrating function when it's setting up this directive. So I will need to take that  parse service and save it off here and something that gets closed over. So I could say, before we  return that object parse equals that parse service. One of the things I can do with parse then is  I can say, give me an expression by parsing attributes.migrating. And what I can do with  the expression then is invoke it, passing in the scope object. And that should dig the name out  for me without me having to figure out if there's dots in that thing or not. So refresh, we're back  to hello, Scott, which is good. The problem with this is that hello, Scott is written once when  the link function runs. And now if someone is updating that model, that is updating person.name,  but my directive is not written in a way that it's recognizing any model changes. That's something  else that you need to do from inside of a directive. You have to tell Angular what you  actually need to observe or watch so that when it changes, you can update your display accordingly.  So actually it turns out to be fairly easy. I can say, dear Angular, I want to watch  this expression. And when it changes, you can call this function for me and pass in the new value.  I'll talk about this here in a second once I get everything put in place. And let's change this to  I am watching something. I think that's right. Not using the expression, but I'm going to leave that  there because we might need it later. Refresh the page. I am watching Scott.  Alan. So now we're updating appropriately. So Angular changed detection a little bit different  than some of the other frameworks that are out there. If you use knockout and backbone and some  of these other ones, when your model changes, the properties on those model objects have to be  observable. They have to essentially raise events that broadcast to the world that, hey, this value  just got set. Now someone can go out and update the DOM. Angular works a little bit differently in  the sense that my JavaScript can be plain, unobservable objects. So what is person?  It's just a regular JavaScript object with a name property. And what Angular will do  is when you're using directives like ngModel and these expressions like x plus y,  it will set up watches on those properties. And a watcher really is, let's look at the  current value. Okay, we see what the current value is. We'll save that off. And now something has  happened. Let's check the value again. Oh, it changed. We have to update the screen. So it's  very much like snapshot change detection, which does influence some of the applications that  you can write with Angular. The rule of thumb that the team came out with is that if you have a  model with over a thousand things, a thousand properties, you might start running into performance  problems because every one of those thousand things is data bound on the screen somewhere.  There's a thousand watchers. There's a thousand comparisons that have to happen  when it figures out what's changed. There's ways to optimize around that, but it's just something  to be aware of. Someone emailed me recently with a page that had a table with 10,000 rows in it,  and they were wondering why performance was slowing to a crawl. It's like, well, you're going to have  to come up with a different solution for that one. Making sense? At all? Yeah, maybe? Well, I'm  going to forge forward. So a couple of things happening then. Oh, yeah. So we have a directive  that I can essentially bind something in my model, have it update the screen. It's two-way  data binding. So what I want to do now is say, when someone interacts with this element, I want to  actually modify the underlying model value. So with elements, I can bind to events. Now, I said  earlier, we don't need jQuery, and that's because Angular actually includes an implementation of  what they call jQuery Lite, which is a subset of the jQuery API, but it's all the things that you  always use. Add class, remove class, dot bind, hookup events, dot text to set the text, dot HTML,  all the stuff that you use for DOM manipulation in jQuery and selecting things. It's already  provided by Angular. When you get one of these elements, it's essentially wrapped by jQuery  Lite. That being said, if you include the jQuery library before you include Angular.js,  it will use jQuery, the full jQuery library. So you'll have all that plus whatever else jQuery  is providing. But element dot bind is a way to say, I want to hook up to the click event.  So when someone clicks on this, what I want to do is add exclamation points or something at the  end of the string just to make it look like it's doing something. So the way I can do that  is through this expression, that expression knows how to assign values. So I'm going to say  expression dot assign on the scope object, take this value and add an exclamation point.  Right? So every time I click, I wanted to add an exclamation point into the model  on the scope. So let me refresh the page. There's no errors. I'm going to click on this a few times.  It doesn't seem to be updating. There's no errors. That's weird. Let me try to update something else  on the screen, like this text box. Huh. Then all of a sudden all of my exclamation points appear.  So this is something else to be aware of with Angular. There's two worlds of code  when you're writing an Angular application. There's the world where code runs inside of  Angular or Angular is aware that the code is running. There's something from Angular on the call  stack. And then there's the world where Angular doesn't know that code is executing. This is a  case where Angular doesn't know this code is executing because we're just saying,  bind to click event. When someone clicks it, we're going to change the model.  Angular doesn't know that that executed that it changed something, so it's not going out and  doing any change detection. So push that on your mental stack just for a second. We're going to  come back to this situation. Before we do, I just want to do a slightly simpler scenario,  which is this numbers controller. I have an input for X and input for Y. This will show X plus Y.  I want to have a button that when you click on it, it will just double X and double Y.  Let's see how to implement that. That's changing the model too, but it's a little bit simpler than  what we're doing. So over in the numbers controller, let's initialize some things. Scope.X, let's say  it starts off as a 3. Scope.Y started off as 5. Scope.DoubleIt. So I'm saying when someone clicks  this button, look for something on the current scope, in the current scope, called DoubleIt,  and treat it like a function. So invoke it. So Scope.DoubleIt is a function that when someone  invokes that, we will say Scope.X times equals 2. Scope.Y times equals 2. Let's just see if this  works. Refresh the page. So we've got a 3 and a 4 and an 8. I can bump these up. That's worked.  It's updating the screen. Change X. Double everything. Double X and Y, and that also updated  that div out there. So all that works. When you're inside of code that Angular knows it was called,  it does the change detection for you and everything just works. It knows that it had to  call DoubleIt. And so as soon as your code executed because you wired up something here  with an ngClick directive, as soon as you change something inside of that function,  Angular will do the change detection, figure out how to update the screen. But if you execute code  inside of here without going through Angular, it doesn't know that things change. So if I had an  increment function, and I said inside of here we'll do Scope.X plus equals 1 and Scope.Y plus equals 1,  and then we do a set timeout. Let's do a set timeout. So every, well, we'll start calling this  after one second. And then just to make things a little bit dramatic after every 250 milliseconds  we'll keep calling it. Run this. No changes appearing on the screen because set timeout is  just calling that code increment function. Angular doesn't know that's happening. If I try to update  something on the screen, like change X, oh yeah, I can see something's getting doubled, right?  Why was way up there? Angular doesn't know that things are changing. Instead of set timeout,  what I should be using is another service in Angular, the timeout service that's basically a  wrapper for set timeout. But it's through an Angular service. So again, it's about testability.  You could fake that out in a unit test, make sure the controller was calling timeout for some reason.  But now if I say let's use the timeout service to invoke that function, well, timeout does a  little bit smarter and knows that things might change. And I think I also have to change my  injection here. Or using timeout service. Let me refresh. So through the timeout service,  things are changing. Angular knows that something was changed when it called that function back.  Yeah. Pretty exciting, isn't it? You guys glad you came to the session.  All right. Let me take this out so it doesn't become annoying. How do we do that? How do we do  that from our own code? Well, when you're writing a directive and you're changing something in the  model, you should always do one of two things. Either call apply after that is finished. That's  the way of telling Angular, okay, code just executed. Probably made some changes. I need to  you to go through and do your digest cycle and see what changed and update the screen appropriately.  If you want to do it the really safe way, though, you can also invoke apply and pass in a function  of the code that might change the value. The advantage to this being if that code that is  changing stuff throws an exception somewhere along the line, Angular will still do its  apply change detection stuff. Right. And update the screen. Save this. Refresh. Now let me click  my directive. Now you can see it's actually updating appropriately. Right. So that's how you  would change the model from a directive. So directives are really that piece of, they're like  glue between the DOM and your model. The model for a controller should really never do any DOM  manipulation. The model, the things that you put on scope, they're very much, you treat them like  a view model if you've ever done silverlight or WPF development. They don't really know about the  view. You just set properties on things. You write functions that modify things. And it's the  data binding expressions and the directives that take care of pulling data out of there, modifying  the DOM, wiring up click events in the DOM. You would never write DOM manipulation code inside of  the controller, basically. And that means we should have at least one passing test inside of here.  I'm hoping. Yeah, should double it, actually, is a passing test. Let me show you the test  real quick. Don't know if we'll have time to cover these in much detail today, but a test for that  controller for double it could look as easy as this. I want you to initialize X to 10 and if  someone doubles it, I would expect it to be 20 after it's doubled. There's a little bit of setup  code to get there. You basically have to instantiate the controller and provide maybe a fake for the  timeout service, but they very much want you to be able to unit test your models and controllers.  All right. Let's try to get through some material here. We have the numbers view working, I believe.  We did the double it. We have the custom director right. So let's look at movies,  which is a little more realistic scenario. So what I want to do here is have a movies controller  that will, which we don't have yet, a movies controller that will go out and we'll call a  web service that sits at slash api slash movies that returns some movie information in JSON.  This is showing XML, but that's because I ran it through the browser, but it'll hit that end  point, pull back some movies, display them in a table, allow me to edit them, let me save them.  We need a movies controller to do that. So  function.  I need a reference again to angular. I'm going to put this in my app also.  That's going to be my module. So my movies controller is a function that will take a scope.  That's where I'll put my model. Also going to take another service called the HTTP service.  You can write your own custom services, by the way, very easy to write, have them injected in to  controllers and directives and other things like that. Typically what people would do, a lot of  people wouldn't use dollar sign HTTP service directly from a controller. They would hide it  behind their own custom service. There's a number of advantages to that, including caching. And  sometimes it's easier to test that way. We're just going to use it right from the controller,  just, well, in the interest of time. This is basically like dollar sign.ajax. HTTP has get,  put post methods, JSONP method, I'm going to get API movies. It returns a promise.  So I can say.then or.always or I believe there's a.air. Then after you have retrieved the movies,  call this function with the result. What I want to do is take the data that comes back  and put it into my scope. So scope.movies equals result.data. And let's check the view real quick.  So the view is building a table. And then this is a big directive that you'll use quite often,  the ng repeat directive. It's basically saying find the movies property on the scope. And  essentially for each movie that you find in the movie's collection,  actually repeat the following DOM elements. So basically, well, repeat these DOM elements.  Repeat a table row for each movie that you find. And it sets up a new scope for each,  one of those repeated DOM elements, where the movie, the single movie that pulled out is the scope.  So when I say things like movie.id, movie.title, movie.release date, it should be pulling that  out for each individual movie, putting it into a table cell there. Pretty good stuff, right?  See if it works. Refresh this and I didn't save something. Still got an error, which is  movies controller is not a function. Oh, right. So I bet I forgot a step. We wrote the movies  controller function. I never told Angular about it. So dear module, there is a controller called  movies controller. This is the function to use. We should annotate it for dependency injection,  but we'll get to that. All right. So we got movies from my web service. Very good. It's very ugly  display. What are some things we could do to improve this? Well, we could go into the view.  And since I'm using bootstrap, I guess one thing I could do is say this is a table, table,  hover, effects. That doesn't really matter. Table striped effects. Slightly better. Release date.  Not pretty. How do I modify the release date so it's a pretty value? Here's another category of  abstractions in Angular. Things called filters. Filters are things that you can pipe into. So  I could say, please pipe this into a filter called date. And that date, I can give it a parameter.  I want you to display a date with the year, a four-digit year. And you can also do month,  year, whatever type of syntax you want. Do a save all here. Yeah. So we just have a four-digit year.  So filters are a nice way of formatting things, keeping that code out of the model,  keeping that code out of the controller, not having to change your API or the JSON that comes  back. You just pipe things through a filter. They're also very easy to write. They're essentially  a function that takes a value. And you modify the value and you return it. What else do we want  to do here? We want to edit things. So when I click on the edit button, how do I edit this movie?  This is already set up with an ng-click directive that says someone clicks the button,  call this function, pass in the current movie that's in scope. So I just need to, in my controller,  say scope.edit is a function that takes a movie.  And it looks like this editing section, a couple different things going on. So first of all,  there's an ng-show directive. That's a really easy way to turn a DOM element on or off. Basically,  it looks at this expression on the current scope. And if it's truthy, it'll show it. If it's falsy,  there's no DOM element. It'll hide it. So literally, when we're editing, if I say scope.editing equals  true, that should turn that view on. Also looks like we are binding now against edit movie. So  edit movie.title, edit movie.release date. Let me say scope.edit movie equals that incoming movie  that you just passed me. Let's see if this works. I'm going to edit star king. I don't know how I  came up with these movie names. They're ridiculous. So I'm editing that JavaScript object. I edit  star king over here. That's the same object as what's in the table. So you can see the data  binding works to update the table, which might not be what I want. I might want to get a copy of  that object so I can modify it and not update the table until users are ready to commit that  somehow. So I would probably do something like Angular. There's a copy, a deep copy method  helper. Angular.copy that movie. Now I should have a distinct copy of, let's say, Star Wars. So if I  make changes over here, they're not going to be propagated over there until I click save. Let's  see what the save button does. Save. I was just going to call a function called save and pass in  the movie. There's also a cancel, which effectively stops the edit. Let's implement that stuff real  quick. So scope.cancel as a function. I guess all I really have to do here is say scope.editing  equals false. That should be enough where I should be able to say let's cancel it. Very good.  And scope.save, that's a function where you give me the movie that you want to save.  Obstensibly, I can do an htdb.put there, put that movie back to the web server, tell it to  save it in the database. I probably also want to update the movie that's in the table, which I  guess if I had a library like underscore, it would be a little bit easier because I guess the best  way to do it right now is to say let's go through the movies that we have in the model. And when we  find the movie that has the same id as that incoming movie, that's the one we want to update. So we'll  break out of the loop. But here I could do angular.extend, which is a lot like jQuery.extend.  Take this object and this object and move all the properties into it. Extends scope.movies sub i  with that incoming movie, if I'm making sense. I hope I'm making some sense. Let's try to edit  star king. I have no idea if that's really a movie. Star king 2, save it. Uh oh. What did I miss?  Movies is not defined.  Uh, yeah, that's interesting.  Oh, how did that sneak in there?  Yeah, yeah, yeah, thank you. Now I see it. Hopefully that's the problem.  Save it. Yes, thank you. So that's the, that would be, that would be an example of something  that you could do with angular that you'll notice is amazingly easy, right? That's a very complex  page. It's showing things, hiding things, putting things on the server, retrieving things from the  server. But it's all right here. It's relatively straightforward. It's also not too difficult to  unit test. I haven't completely implemented the update movies the way it wants to be implemented.  But just to show you some of the tests again.  This is an example of, I expect after the movie controller gets instantiated, it should have  made a call to the web server to get API movies. And I would expect after all the asynchronous  stuff is done that the scope.movies.length, it'll have three movies in there. And I expect if I  call scope.edit that it'll turn on the editing flag so that DOM element appears. So  lots of interesting ways to write unit tests. And I think, let me just check something real quick.  I think I covered 90% of what I wanted to show you today.  So I'll just open it up for questions. We only have a couple minutes left.  Well, if there's no questions.  Ah, so the question is why Angular not knockout. It's a very personal decision, I believe.  Some people use knockout and they like it. Some people use knockout and they just  doesn't do it for them. I kind of fall into that category. The first time I tried Angular  honest to goodness and I looked at their examples and I saw things like ng-click,  it turned me off and I disregarded it for about four months and then I came back to it.  Actually went through their tutorial. So if you want another good tutorial on Angular,  they have on the Angular web page here a link to a tutorial where you bring down the Git  repository and you go through different steps that they have tagged and it'll show you how to  build an application that has a master detail view. Very interesting. When I went through that,  then that's when I said this is the one. It doesn't funkify stuff so you don't have to make your  model observable. You don't have to do crazy things to, you know, every property becomes a function.  I really like this data binding syntax. I like candle bars or mustaches, whatever you want to  call them. I think it has a lot of flexibility with the directives. The downsides to Angular are  the documentation is not that good. It is complex. If you haven't worked with inversion of control  containers and dependency injectors and an MVVM type pattern before, it can all be quite overwhelming.  But I think the simple cases are very simple. They're very easy to do. The hard cases where  you have to build custom directives, that requires a little bit of work. So does that answer the  question? I like it. So if you have any other questions, my email address is this and you  can email me. I can give you the code that I wrote today and I have some Plural Site cards. If you  want to watch some Plural Site videos, it's a free monthly subscription. So $30 value. Thank you  for coming. Hope you enjoyed it.
Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_0_107.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_108_635.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_636_1523.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_1524_5615.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_5616_8699.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_8700_13307.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_13308_14171.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_14172_17339.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_17340_17423.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_17424_21779.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_21780_23387.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_23388_23459.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_23460_23687.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_23688_25523.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_25524_26615.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_26616_26879.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_26880_27227.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_27228_28607.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_28608_29111.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_29112_30827.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_30828_31271.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_31272_31451.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_31452_31499.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_31500_31583.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_31584_34079.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_34080_34259.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_34260_35639.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_35640_36923.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_36924_38891.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_38892_44255.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_44256_44435.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_44436_45251.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_45252_46463.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_46464_48707.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_48708_48995.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_48996_49631.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_49632_49703.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_49704_49847.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_49848_51239.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_51240_51455.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_51456_52763.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_52764_53015.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_53016_53063.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_53064_53723.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_53724_54671.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_54672_55319.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_55320_61235.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_61236_63227.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_63228_63443.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_63444_63779.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_63780_65147.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_65148_65231.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_65232_66455.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_66456_66539.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_66540_66947.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_66948_68411.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_68412_68531.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_68532_68867.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_68868_69623.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_69624_69839.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_69840_70919.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_70920_71399.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_71400_75323.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_75324_75431.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_75432_75599.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_75600_76499.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_76500_76811.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_76812_77159.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_77160_77327.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_77328_80255.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_80256_80459.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_80460_80723.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_80724_81191.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_81192_82703.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_82704_83039.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_83040_83567.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_83568_83891.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_83892_84143.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_84144_84455.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_84456_86471.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_86472_86519.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_86520_86591.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_86592_87107.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_87108_88451.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_88452_88511.png Scott_Allen_-_The_Abstractions_of_AngularJS-68215604_88512_88551.png