├── 00-0-concepts.html ├── 00-1-concepts.html ├── 00-1-spin.html ├── 00-2-concepts.html ├── 00-2-spin.html ├── 01-1-forms.html ├── 01-1-shopping.html ├── 02-1-filters.html ├── 02-2-filters.html ├── 03-1-directives.html ├── 03-2-directives.html ├── 03-3-directives.html ├── 03-4-readinglist.html ├── 03-5-transculsion.html ├── 03-6-elements.html ├── 03-8-compilevslink.html ├── 04-0-scope.html ├── 04-1-scope.html ├── 04-2-scope.html ├── 04-3-scope.html ├── 04-4-review.html ├── 05-0-modules.html ├── 05-1-event.html ├── 06-0-templateurl.html ├── 06-1-templatecache.html ├── 07-0-ngview.html ├── 07-1-routing.html ├── 07-2-routeParams.html ├── 07-3-promises.html ├── 07-4-resolve.html ├── 07-5-ChangeError.html ├── 08-0-ngAnimate.html ├── 08-1-ngResource.html ├── 08-2-onEmitBroadcast.html ├── 09-0-forms.html ├── 09-1-compile.html ├── README.md ├── bestpractices.html ├── partial1.html └── partial3.html /00-0-concepts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 00-concepts 5 | 6 | 7 | 8 | 9 |

Data Binding


10 | 11 | 12 |
13 | Invoice: 14 |
Quantity:
15 |
Costs:
16 | 17 | 18 | 19 |
Total: {{qty*cost | currency }}
20 | 21 | 22 | -------------------------------------------------------------------------------- /00-1-concepts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 00-concepts 5 | 6 | 7 | 30 | 31 | 32 |

Controllers


33 |
34 | 35 | Invoice: 36 |
37 | Quantitiy: 38 |
39 |
40 | Costs: 41 | 45 |
46 |
47 | Total: 48 | 49 | {{invoice.total(c) | currency:c }} 50 | 51 | 52 | 53 |
54 |
55 | 56 | -------------------------------------------------------------------------------- /00-1-spin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Taking AngularJS for a spin 5 | 6 | 10 | 11 | 12 |
13 | {{data.message}} 14 |
15 |

{{2+2}}

16 | Type in a message: 17 |

{{data.message}}

18 |
19 |
20 | Type in a message: 21 |

{{data.message}}

22 |
23 |
24 | 25 | -------------------------------------------------------------------------------- /00-2-concepts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 00-concepts 7 | 8 | 9 | 48 | 49 | 50 |

Services and Dependency Injection


51 | 52 |
53 | Invoice: 54 |
55 | Quantitiy: 56 |
57 |
58 | Costs: 59 | 62 |
63 |
64 | Total: 65 | 66 | {{invoice.total(c) | currency:c }} 67 | 68 | 69 |
70 |
71 | 72 | -------------------------------------------------------------------------------- /00-2-spin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Taking AngularJS for a spin 5 | 6 | 27 | 28 | 29 |
30 |
31 | Type in a message: 32 |

{{data.message}}

33 |
34 |
35 | Type in a message: 36 |

{{reversedMessage(data.message)}}

37 |
38 |
39 | 40 | -------------------------------------------------------------------------------- /01-1-forms.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Formsdemo 6 | 10 | 11 | 12 | 13 | 19 | 20 | 21 | 22 |
23 |
24 | 25 | Name:
26 | Email:
27 | 28 | 29 | Email is required (only shown if you don't type any email)
30 | This is not an email! (shown if you type in invalid email)
31 | 32 | Do you agree that we have NO Terms and Conditions
33 | 34 | 35 |
Please agree to TOCs!
36 |
Thank you for signing!

37 | 38 | Type in a message to introduce yourself!
(this demonstrated delayed triggers using ng-model-options) 39 |
40 |
41 | 42 | 43 | You entered: {{data.user.name}} and {{data.user.email}} with message {{data.user.message}} 44 | 45 |
46 | 47 | -------------------------------------------------------------------------------- /01-1-shopping.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | Shopping Cart 7 | 9 | 10 | 11 | 12 | 13 | 54 | 55 | 56 | 57 | 58 |
59 |
60 |
61 | 62 | {{item.title}} 63 | Price: {{item.price | currency}} 64 | 65 | 66 | 67 | 68 |
69 |
70 |
71 |
72 | {{item.title}} 73 | Price: {{item.price | currency}}, Qty: {{item.qty}}
74 | 75 | 76 | Total: {{item.price * item.qty | currency }}
77 | 78 | 79 |
80 |
81 |

Grand Total {{ total(cart) | currency }}

82 | 83 |
84 |
85 | 86 | -------------------------------------------------------------------------------- /02-1-filters.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Custom Filter 6 | 10 | 11 | 12 | 13 | 31 | 32 | 33 | 34 |
35 |
36 | {{data.message | reverse }} 37 | 38 |
39 | 40 | -------------------------------------------------------------------------------- /02-2-filters.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | \ 4 | ng-filter 5 | 9 | 10 | 11 | 12 | 32 | 33 | 34 | 35 |
36 | 37 | 38 | General Search:
39 | 40 | 42 | Name Search
43 | Phone number Search
44 | 45 | 46 | 47 | 48 | 49 | 50 |
{{$index+1}}{{person.name}}{{person.phone}}
51 |
52 | 53 | -------------------------------------------------------------------------------- /03-1-directives.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | directives 5 | 9 | 10 | 11 | 12 | 39 | 40 | 41 | 42 |
43 | 44 |
45 | 47 | 48 |
49 | 50 | -------------------------------------------------------------------------------- /03-2-directives.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | directives 5 | 9 | 10 | 11 | 12 | 36 | 37 | 38 | 52 | 53 | 54 |
THIS IS VERY IMPORTANT! ROLL OVER!

55 |
This is not important until you roll over!
56 | 57 | -------------------------------------------------------------------------------- /03-3-directives.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | directives 5 | 8 | 9 | 10 | 11 | 31 | 32 | 33 |
34 | Number of loads: {{data.timesloaded}} 35 |
Books available: {{data.books}} 36 |
37 | Roll over to load more! 38 | 39 |
40 | 41 | -------------------------------------------------------------------------------- /03-4-readinglist.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Directive Communcation 5 | 6 | 7 | 8 | 118 | 119 | 120 |
121 |

Summer Reading List

122 | 123 | 124 | 125 | 126 | 127 |
128 | 129 | -------------------------------------------------------------------------------- /03-5-transculsion.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Directive Transclusion 5 | 6 | 7 | 18 | 19 | 20 |
21 | 22 |
Inner Wrap 1
23 |
Inner Wrap 2
24 |
25 |
26 | 27 | -------------------------------------------------------------------------------- /03-6-elements.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Streamlined Element Creation 5 | 6 | 7 | 8 | 10 | 11 | 26 | 27 | 28 |
29 |

Summer Reading List

30 | 31 | 32 | 33 | 34 | 35 |
36 | 37 | -------------------------------------------------------------------------------- /03-8-compilevslink.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Compile vs. Link 5 | 6 | 7 | 8 | 44 | 45 | 46 |
47 |
48 | {{country.country}} 49 |
50 | 52 | 53 |
54 | 55 | -------------------------------------------------------------------------------- /04-0-scope.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | scope 5 | 6 | 7 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /04-1-scope.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | scope 5 | 6 | 7 | 37 | 38 | 39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 |
47 | 48 | 49 | -------------------------------------------------------------------------------- /04-2-scope.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | scope 5 | 6 | 7 | 26 | 27 | 28 |
29 | From the ctrl scope:{{data.flavor}} 30 | 31 | 32 | From the ctrl scope:{{data.flavor}} 33 | 34 | From the ctrl scope:{{data.flavor}} 35 | 36 | 37 |
38 | 39 | 40 | -------------------------------------------------------------------------------- /04-3-scope.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | scope 5 | 6 | 7 | 26 | 27 | 28 |
29 |
30 |
31 |
32 |
33 | 34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /04-4-review.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | scope review 5 | 6 | 7 | 39 | 40 | 41 |
42 | 43 |
44 | 45 |
46 | 47 | 48 | -------------------------------------------------------------------------------- /05-0-modules.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Modules 5 | 6 | 37 | 38 | 39 |
40 |
41 | 42 | 43 | 44 |
45 | 46 | 47 | -------------------------------------------------------------------------------- /05-1-event.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Events 5 | 6 | 7 | 14 | 15 | 16 |
17 |
Click to see event: {{e.clientX}}
18 |
Double Click to see event: {{e.clientX}}
19 |
Movemouse over here to see event: {{e.clientX}}
20 |
Mouse down to see event: {{e.clientX}}
21 |
Mouse enter to see event: {{e.clientX}}
22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /06-0-templateurl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TemplateUrl 5 | 6 | 23 | 24 | 25 |
26 | 27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /06-1-templatecache.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TemplateUrl 5 | 6 | 31 | 32 | 33 |
34 | 35 |
36 | 37 | 38 | -------------------------------------------------------------------------------- /07-0-ngview.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ng-view 5 | 6 | 7 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /07-1-routing.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ng-view 5 | 6 | 7 | 28 | 29 | 30 | Home | Ask me whats up | Page that doesn't exist
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /07-2-routeParams.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ng-view 5 | 6 | 7 | 28 | 29 | 30 | Send a 'Hello' message | Send 'this is very useful' message 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /07-3-promises.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | promises 5 | 6 | 7 | 49 | 50 | 51 |
52 |
53 | 54 | 55 | -------------------------------------------------------------------------------- /07-4-resolve.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ng-view 5 | 6 | 7 | 51 | 52 | 53 | Home | Ask me whats up | Say bye
54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /07-5-ChangeError.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ng-view 5 | 6 | 7 | 66 | 67 | 68 | 69 | Home | Ask me whats up
70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /08-0-ngAnimate.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ngAnimate 5 | 6 | 7 | 25 | 88 | 89 | 90 | This page demonstrates ngAnimate. 91 |
92 | 93 |
94 | Make visible 95 | 96 |
This is shown if true
97 |
98 |
99 |
100 | 101 |
102 | {{person.name}} | {{person.number}} 103 |
104 |
105 | 106 | 107 |
108 |
109 | Animate me! 110 |
111 |
112 | 113 | -------------------------------------------------------------------------------- /08-1-ngResource.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ngResource 5 | 6 | 7 | 58 | 59 | 60 | This page demonstrates ngResource. 61 |
62 | 63 | Type in a place to search: , Radius: 64 | 65 | 66 |

Done? {{results.done}}

67 |
68 |

{{place.city}}, {{place.country | uppercase}}

69 | 70 | -------------------------------------------------------------------------------- /08-2-onEmitBroadcast.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $on $emit $broadcast 5 | 6 | 7 | 36 | 37 | 38 | 39 | Outer: {{outer}}, Middle: {{middle}}, Inner: {{inner}}
40 |

Here middle and inner don't show up because they are not part of this scope.

41 |

Clicking $broadcast/$emit in any scope also fire the event in that scope itself

42 | 43 | 44 | 45 |
46 | outer: {{outer}}, middle: {{middle}}, inner: {{inner}}
47 |

Here outer is inherited from the parent scope, inner is not available in this scope.

48 | 49 | 50 | 51 | 52 |
53 | outer: {{outer}}, middle: {{middle}}, inner: {{inner}}
54 |

Here outer, middle and inner are available as angularJS looks in the parent scopes for the property we request. But note that here we have overrident the outer property and so doesn't update, it is no longer linked to the first scope.

55 | 56 | 57 |
58 |
59 | 60 | -------------------------------------------------------------------------------- /09-0-forms.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ngResource 5 | 6 | 7 | 18 | 27 | 28 | 29 |
30 | 31 | 32 | 33 |
34 | 35 | 36 | Name:
37 | Email:
38 | 39 | 40 | Your form is: {{userForm.$valid? 'valid' : 'invalid '}} 41 | 42 | 43 |
44 |
45 | 46 | -------------------------------------------------------------------------------- /09-1-compile.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $compile 5 | 6 | 7 | 32 | 33 | 34 | 35 | NOTE: Here all three sections must look identical and each should update each other! But notice that the second box doesn't update anything, this is because we did not use $compile on it.
36 | Regular bound 2-way connection: 37 |
{{data.twoWay}}
38 |
39 | 40 | Uncompiled HTML injected after page compiled: 41 |
42 | 43 | $compiled HTML injected after page compiled: 44 |
45 | 46 | 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Learning AngularJS 2 | ================ 3 | Updates 4 | 5 | **Note: about Angular 2: Angular 2 has many drastic changes, I might get to an Angular 2 tutorial over the summer!** 6 | 7 | ***I noticed how untidy the main folder has become, however I am not going to move any of the files anywhere due to the fact that all the links are now fixed in this README. If there is another tutorial that comes up then I will create a separate folder with the code and README for that curriculum - *Thanks for visiting!* *** 8 | 9 | ![ng!](https://angularjs.org/img/AngularJS-large.png) 10 | 11 | So I've been meaning to learn AngularJS for some time now and I've watched a few videos here and there but kept on dropping and never building anything concrete. This repo will help me track my progress through two curriculums I've found on thinkster.io and codeschool.com: 12 | 13 | 1. [A Better Way to Learn AngularJS](http://www.thinkster.io/angularjs/GtaQ0oMGIl/a-better-way-to-learn-angularjs) 14 | 2. [Shaping up with AngularJS](http://campus.codeschool.com/courses/shaping-up-with-angular-js/intro) 15 | 16 | This repository will also include code from other sources which I will cite in the comments and below when I find them. There are also basic code example as alternative to demos shown in the videos so that we can see more than one example to be able to accurately wrap ones head around. 17 | 18 | This README will also track some codes, gotchas, comments and other shenanigans to help others like me learning AngularJS for the first/second/third time. Hope this helps! 19 | 20 | ##### Prerequisites 21 | - [ ] HTML 22 | - [ ] CSS 23 | - [ ] JS (OOPs, Prototyping, functions, events, error handling) 24 | - [ ] Idea of the Model-View-Controller technique 25 | - [ ] The Document Object Model 26 | 27 | ##### Requirements 28 | - [ ] Web browser 29 | - [ ] Acccess to the O'Rielly AngularJS Book. If you are a student you can access it [here](http://proquest.safaribooksonline.com/book/programming/javascript/9781449355852/firstchapter) using your university VPN. [*AngularJS by Brad Green and Shyam Seshadri (O’Reilly). Copyright 2013 Brad Green and Shyam Seshadri, 978-1-449-34485-6.*] 30 | 31 | ### 00-Concepts 32 | AngularJS relies heavily on the MVC approach: 33 | - a **Model** which contains the data shown to the user in the view and with which the user interacts. (think of it as the place where we store the data) 34 | - a **View** this is what the user sees. (the user interface or the DOM) 35 | - the **controller** which contains all the logic. 36 | 37 | There are some *buzzwords* used in AngularJS: 38 | - **Data Binding** is the sync of data between the model and the view 39 | - **Two way Data Binding** is a feature of angular that says that everything in the document is live. Whenever the input changes the expression is automatically recacluated and the DOM is updated as well. 40 | - **Scope** ~~this is where the variables and data (known as model) are stored, think of it as the traditional *scope* that allows all other components to access the data in the model.~~ So someone pointed out that this definition was vague. After some more reading, it turns out that the Scope is where your application will execute expressions, scopes are nested and the root scope usually doesn't contain anything in it. Without trying to complicate our lift off with definitions, think of the scope *of a controller* as the place where our data is stored which 'forms the glue between the controller and the view'. 41 | - **Templates** all HTML files with angular code are known as templates because angular must fill in expressions and other gadgematics. 42 | - **Directives** apply special behaviour to HTML elements. For example the `ng-app` attribute in our [00-concepts.html](https://github.com/zafarali/learning-angular/blob/master/00-0-concepts.html) file is linked to a directive that automatically initializes the application. When we define `ng-model` attributes to our `` element, we create a directive that stores and updates the value from the `` field to the *scope*. 43 | - **filters** format the value of an expression for display to the user. Filters are very useful and in our [00-concepts.html](https://github.com/zafarali/learning-angular/blob/master/00-0-concepts.html) file we use `currency` to format the output of the expression to resemble a bill or currency. 44 | 45 | The image summarizes [00-1-concepts.html](https://github.com/zafarali/learning-angular/blob/master/00-1-concepts.html) 46 | ![Interaction between Controllers-Scope/Model-View](https://docs.angularjs.org/img/guide/concepts-databinding2.png) *image from [AngularJs Docs](https://docs.angularjs.org/guide/concepts)* 47 | 48 | - **Services** contain all the 'independent logic', which is other words is a way to supply and manipulate data to our application. We use services to allow us to reuse it in other parts of the application. For example in [00-1-concepts.html](https://github.com/zafarali/learning-angular/blob/master/00-1-concepts.html) all the logic was stored within `InvoiceController`. In [00-2-concepts.html](https://github.com/zafarali/learning-angular/blob/master/00-2-concepts.html) we will refactor the code to move the conversion logic into a service in another module. 49 | 50 | - **Dependency Injection** In [00-2-concepts.html](https://github.com/zafarali/learning-angular/blob/master/00-2-concepts.html) we see that `ng-app` defines `invoice-srv-demo` as the main module to use in application. In the defintiion of this module we state that `finance` is a dependency of the main module. We also define the constructor for the controller after passing in the dependency `currencyConverter` from the finance module. This is known as *dependency injection* 51 | 52 | ### 00-Spin 53 | #### The Dot. 54 | Found this gotcha thanks to [this video](http://www.thinkster.io/angularjs/axAQatdKIq/angularjs-the-dot). 55 | ```html 56 | 60 |
61 |
62 | 63 |

{{message}}

64 |
65 |
66 | 67 |

{{message}}

68 |
69 |
70 | ``` 71 | If we set up our code as above, *scope inheritence* is broken. Each new `ng-model` that we set up for the `message` is creating a new instance of message which means there is no longer communication between the two `message`s. To rectify this we place a `data` model on the `$scope` which has the `message` property. I like to think of this as each controller getting its own scope because rectifying the code as shown below also doesn't fix the issue and no data is shared between the two controllers. 72 | ```html 73 | 74 |
75 |
76 | 77 |

{{data.message}}

78 |
79 |
80 | 81 |

{{data.message}}

82 |
83 |
84 | ``` 85 | However editing the code in a way (below) such that there is a scope set up for the entire application will ensure that the scope can sync data between the controllers. 86 | ```html 87 | 88 |
89 | {{data.message}} 90 |
91 |

{{2+2}}

92 | Type in a message: 93 |

{{data.message}}

94 |
95 |
96 | Type in a message: 97 |

{{data.message}}

98 |
99 | ``` 100 | *(this observation is indeed true, we need to have a parent to allow this kind of inheritence)*. We now look at a different way to do this. 101 | #### Data sharing between controllers 102 | This can be done by creating a *factory* which will supply the data. We then bind the local `$scope`s to the `Data` factory where we can then sync data between the controllers. See [00-2-spin.html](https://github.com/zafarali/learning-angular/blob/master/00-2-spin.html). 103 | ```javascript 104 | var myApp = angular.module('myApp', []); 105 | myApp.factory('Data', function(){return{message:"this is important"};}); 106 | function myCtrl($scope,Data){$scope.data = Data;} 107 | function yourCtrl($scope,Data){$scope.data = Data;} 108 | ``` 109 | ### Shopping Cart (01-1-shopping and 01-1-forms) 110 | The [shopping cart](https://github.com/zafarali/learning-angular/blob/master/01-1-shopping.html) example demonstrates some of the other functionality of the AngularJS framework. You may have noticed that we have seen two ways to creating `controller`s: 111 | ```javascript 112 | //method 1 113 | function Ctrl($scope) {}; 114 | //method 2 115 | var myApp = angular.module('myApp', []); 116 | myApp.controller('Ctrl', function($scope){}); 117 | ``` 118 | We can compare the two using our shopping cart app in [this commit](https://github.com/zafarali/learning-angular/commit/ce54e0d417f80a0087035b62e92a6f8030ccd4c0#diff-1d019a5313eee180347d30c7801153a5). Method 2 ensures that we keep our controllers out of the global namespace using the module we defined. 119 | The docs page regarding [forms](https://docs.angularjs.org/guide/forms) we find a whole load of neat tricks and tips that are demonstrated in [01-01-forms.html](https://github.com/zafarali/learning-angular/blob/master/01-1-forms.html). The page also demonstrates the abilities of `ng-show`, `ng-hide`, and validation techniques that AngularJS provides. 120 | ### 02-Filters 121 | #### Custom filters 122 | There's only syntax to learn here, watch this [video](http://www.thinkster.io/angularjs/EnA7rkqH82/angularjs-filters) and see the dummy code I [typed](https://github.com/zafarali/learning-angular/blob/master/02-1-filters.html) up. Another example is shown below using extra arguments that can be used as `text|decimal2binary:true`: 123 | ```javascript 124 | //converts decimal to binary string 125 | app.filter('decimal2binary', function(){ 126 | function convert(num,bool){ 127 | if(bool) { console.log('You specified true'); } 128 | return parseInt(num,10).toString(2); 129 | } 130 | return function(input, bool){ 131 | return convert(input, bool); 132 | } 133 | }); 134 | ``` 135 | #### Searching and filters 136 | We can see an implementation of the search technique in [02-2-filters.html](https://github.com/zafarali/learning-angular/blob/master/02-2-filters.html). Some other built-in AngularJS filters are summarized below: 137 | - `limitTo` will limit the number of results shown 138 | - `orderBy` takes a string and will order the results using the property it maps to 139 | - `lowercase` and `uppercase` turn the results to lower and upper case (these are best applied to the data binding as shown below) 140 | - `date`, `currency` format our data and are self explanatory 141 | - `number` takes a integer and rounds off the data to that decimal place. (eg: 0 would round off to 0dp) 142 | ```html 143 | 144 | {{element.lastname | uppercase}}, {{element.firstname | lowercase}} 145 | 146 | ``` 147 | ### 03-Directives 148 | #### Custom elements 149 | Directives are one of the most impressive features AngularJS has to offer. In our first example we created a directive which is of `restrict`ion `'E'` which means that it is an element. Our directive is simple in that it just shows an image of a calculator created by the `` element. The [commit](https://github.com/zafarali/learning-angular/commit/fa0b6c1864501592e73ef3cea3e47e34c9763942) shows the code in detail. 150 | #### Custom Attributes and Classes 151 | This [commit](https://github.com/zafarali/learning-angular/commit/403aad17fce1eb09e58b759dad63025db5166cf8) demonstrates a custom attribute that we built. Here, instead of setting `restrict:"E"` we set `restrict:"A"` and provide a `link` function which is executed whenever the attribute is attached. If we set `restrict:"C"` then the directive is executed whenever we have the class with that name [(see commit)](https://github.com/zafarali/learning-angular/commit/552ae91250175137f9e2b742883c7973c463dd48). We can also have directives in comments using `restrict:"M"` and the following: 152 | ```html 153 | 154 | ``` 155 | #### Useful Directives 156 | Directives default to `restrict:"A"`. The directive will also pass in the `scope` and `element` which we can use: as shown in [03-2-directives.html](https://github.com/zafarali/learning-angular/commit/d9e6515d2c8dd7b816907f98b9fa8f75472d4956). The directive also passes the `attrs` which is an object with all the attributes of the element. We can exploit this to make our code abstract when we want to add/remove classes. This is demonstrated in [this commit](https://github.com/zafarali/learning-angular/commit/a0636adf5790aeeb7d20489133bdc23d7d338578). We also see the use of `$apply()` to evaluate functions in [this example](https://github.com/zafarali/learning-angular/blob/master/03-3-directives.html). 157 | #### Directive Communication ([03-4-readinglist.html](https://github.com/zafarali/learning-angular/blob/master/03-4-readinglist.html)) 158 | Directives can communicate with each other as shown in the Reading List Example. Here we create a directive called `` and a couple of attributes that are dependent on the `book` directive. Each `` has a local scope as defined. `` also has an API which can control the local scope. Each attribute we define accesses the `` API to manipulate its properties. The properties can be viewed when we roll over it. A streamlined way (albeit without the romance,thriller etc. properties) is shown in [03-6-elements.html](https://github.com/zafarali/learning-angular/blob/master/03-6-elements.html). 159 | - **Transclusion** We also have a `transclude` property which is demonstrated in [03-5-transclusion.html](https://github.com/zafarali/learning-angular/blob/master/03-5-transclusion.html) that allows whatever is inside our custom element to be placed inside it and not overwritten by the template. 160 | - *Nested elements* and how they communicate with each other are demonstrated in [03-7-nested.html](https://github.com/zafarali/learning-angular/blob/master/03-5-transclusion.html) 161 | 162 | #### Directive properties 163 | Here is a summary of the properties I see are most useful in directives: 164 | - `restrict:"E"||"A"||"C"||"M"` this declares how the directive behaves, as an element, attribute, class or comment respectively. We can use any combination of these. 165 | - `template:"string"` allows your directives to have a template. 166 | - `templateUrl:"string"` allows your directive to load a URL as a template. 167 | - `replace:bool` if true it will replace the current element and by default it is false and will append to the element. 168 | - `transclude` Lets you move the children of the directive into a place inside the template. We do this by specifiying `ng-transclude` attribute of the target location. In this example it targets the `` and not the other `
`s: 169 | ```javascript 170 | //... 171 | transclude:true, 172 | template:"
", 173 | //... 174 | ``` 175 | - `link:function()` executes when the directive sets up. It can be useful in setting `timeout`s, or binding `event`s to the element. 176 | - `controller:function()` allows you to set up scope properties and create an interface for other directives to interact with. This is also useful if you have functions in your directive that need to be executed by only your directive. 177 | - `controllerAs: 'String'` allows you to use the [Controller As]() syntax in your directives. *Note that things are bound to `this` and not to `scope`.* Refer to the notes from above for more details on the 'controllerAs' syntax. 178 | -`scope:{}` allows you to create a new scope for the element rather than inherit from the parent. 179 | - `require:['^directives']` makes it mandatory for the current directive to be nested in the parent to ensure it functions correctly. 180 | A quick gotcha to note, when you name your directive `datePicker` when declaring it, you can refer to it as `date-picker` in your HTML. 181 | 182 | #### Pre-link, Post-link and Compile 183 | From the readings it seems there are two important phases when an angular application is being created. 184 | 1. The Loading of the Script (not so important for us right now) 185 | 2. The **compile phase** is when the directives are registered, the templates are applied and the *compile* function is executed. 186 | 3. The **link phase** occurs once the templates have been applied and the compile functions have been executed. In this phase the *link* functions are executed whenever the data in the view is updated. 187 | The main difference I see in them is that the *compile* function is executed once only during the compilation stage while the `link` function is executed once for each instance of the directive. At the moment I do not see an immediate use case for the compile function, however the book suggests that it is useful when you need to modify something in relation to all cases. Note the difference between the function defintions below, the `compile` function doesn't have access to the scope because it is not created yet. 188 | ```javascript 189 | return { 190 | restrict:"", 191 | require:"", 192 | controller:function(scope,element,attrs){}, 193 | compile: function(templateElement, templateAttrs, transclude){}, 194 | link: function(scope, instanceElement, instanceAttrs, controller){} 195 | } 196 | ``` 197 | If we take a look at [03-8-compilevslink.html](https://github.com/zafarali/learning-angular/blob/master/03-8-compilevslink.html), we see the log executes the `controller` and the `compile`'s `pre` and `post` but not the link. Trying different combinations it seems that if you have a `compile`, you cannot have a `link` but you can get the effect of having a `compile` and `link` by setting a `pre` and `post` function to the `compile` function. 198 | *UPDATE: I have just seen a [video](http://www.thinkster.io/angularjs/h02stsC3bY/angularjs-angular-element), it is indeed true that you cannot have a `link` function and a `compile` function. However, if we do choose to have a `compile` function, we can return (from the `compile` function) another function that will become the `link` function. Go see the website for a nice example on how this works. 199 | 200 | ### 04-Scopes 201 | Scopes can be nested. These nested scopes can either be *child scopes* (which inherits properties from its parents) or *isolate scopes* (which doesn't inherit anything). Everything that we try to evaluate for example `{{name}}` which is input via `ng-model='name'` will be held on the *scope*. Thus we can think of scopes as the link between the controllers/directives and the view. 202 | #### Isolate Scope 203 | We can demonstrate a simple way to create an isolate scope for each directive we create as shown [04-0-scope.html](https://github.com/zafarali/learning-angular/blob/master/04-0-scope.html). When we define a directive, a property we can return is `scope`. This can be set to be `true`, `false`, or `{/*stuff inside*/}`. When we set to `false` (by default), it will use the existing scope in the directive. `true` will inherit the scope from the parent. `{}` will create an isolate scope for each directive. When you define an isolate scope there are *binding strategies* or methods of getting data into that scope. They are discussed below. 204 | ##### @ 205 | We demonstrate two methods of using attributes to store data into the directives isolate scope in [04-1-scope.html](https://github.com/zafarali/learning-angular/blob/master/04-1-scope.html) 206 | ##### = 207 | The `@` operator will expect a string to bind the information we want to pass, however, the `=` will expect an object, this allows us to set up a two way binding between the parent scope and our directive scope. [04-2-scope.html](https://github.com/zafarali/learning-angular/blob/master/04-2-scope.html) demonstrates how updating the directive scope updates the parent. Note that in our attribute we are now passing objects and not strings. 208 | ##### & 209 | The `&` operator will evaluate an expression that you pass to it. So it seems that if you are passing values between the controller and the directive you need it to be in an object, and the object must map its properties to the function. This is demonstrated in [04-3-scope.html](https://github.com/zafarali/learning-angular/blob/master/04-3-scope.html). 210 | ##### All together now! 211 | [04-4-review.html](https://github.com/zafarali/learning-angular/blob/master/04-4-review.html) encapsulates all the concepts we have discussed so far. Note that when we use `=`, we assume that the user is going to order from the same bookstore and thus we would like reflect the change in all other directives. 212 | #### Some Comments 213 | * We see that there is * **one** root scope*, and Angular will first look in the current scope before going up to the parent until it reaches the root scope. A demonstration follows: 214 | ```html 215 | 224 |
225 | 226 | Hello {{name}}! You are from {{home}} 227 |
228 | Hello {{name}}! You are from {{home}} 229 |
230 | ``` 231 | Which will print out `Hello John Doe! You are from Canada 232 | Hello Jane Doe! You are from Canada`. This demonstrates the point. 233 | * Broadcasting and Emmiting 234 | `$emit(name, args)` will allow an event to be executed in current and parent scopes. `$broadcast(name,args)` will allow an event to be executed in current and child scopes. This will be demonstrated in future pages but can be seen very nicely on this page [Scope Events Propagation](https://docs.angularjs.org/guide/scope#scope-events-propagation). [See bottom topic on this for more information](#Scope-Communcation) 235 | * `Controller as` Syntax allows us to refer to the Controller by an *alias*: 236 | ```html 237 | 244 |
245 | 246 | {{ctrl1.name}} 247 | 248 |
249 | ``` 250 | It seems to add clarity to the code and in larger applications I think I will definietly be going to use it more often! 251 | 252 | ### 05-Other Paradigms and tiny shenanigans 253 | Some alternative ways of thinking of Controllers and different ways of organizing angular applications is also provided on the thinkster.io page. I summarize them here very briefly: 254 | * Think of setting up a controller like this: 255 | ```javascript 256 | app.controller("Ctrl", function($scope){ 257 | this.hi = 'Hello'; 258 | this.sayHi = function(){ 259 | alert(this.hi); 260 | } 261 | return $scope.Ctrl = this; 262 | }); 263 | ``` 264 | We can access this now using the following html:`
Click
`. This serves to make the controller explicit and closely mimics the `Controller as` syntax above. 265 | * Organization. We can organize and initialize our controllers and directives like this. (however this doesn't work for filters) 266 | ```javascript 267 | var app = angular.module('myApp', []); 268 | var myAppComponents = {}; 269 | 270 | myAppComponents.controllers = {}; 271 | myAppComponents.controllers.AppCtrl1 = function($scope){/*stuff here*/}; 272 | myAppComponents.controllers.AppCtrl2 = function($scope){/*stuff here*/}; 273 | 274 | myAppComponents.directives = {}; 275 | myAppComponents.directives.mydirective = function(){return {/*stuff here*/}}; 276 | 277 | app.directive(myAppComponents.directives); 278 | app.controller(myAppComponents.controllers); 279 | ``` 280 | * When code bases become very large, we need modules. We have already seen that we have our main app in a module but we can actually create modules seperately. We have already shown this in [00-2-concepts.html](https://github.com/zafarali/learning-angular/blob/master/00-2-concepts.html) but just to drive home the point we reiterate using a directive and a factory in [05-0-modules.html](https://github.com/zafarali/learning-angular/blob/master/05-0-modules.html). 281 | 282 | * `$index`: We have already seen in past examples `$index` which holds the index of the current item in an `ng-repeat`. 283 | 284 | #### Mouse Events 285 | We can use AngularJS listeners along with the `$event` object to do some interesting things. The directives are named in the following convention `ng-listener` where listener can be `click`, `dbl-click`, `mouseenter` etc... Demonstrated in [05-1-event.html](https://github.com/zafarali/learning-angular/blob/master/05-1-event.html) is how we use `$event` to log the event. We can, by the same logic, pass the `$event` into a function that deals with the event in question. 286 | 287 | #### Console logging 288 | Angular has a built in method to log things to the console using `$log`. The [documentation](https://docs.angularjs.org/api/ng/service/$log) summarizes everything very simply and has a nice example that demonstrates it. 289 | 290 | #### Observing the model 291 | `$watch(toWatch, toDo, deepWatch)` is a function that allows you to observe changes in your model. We must note that executing this operation returns another function that if executed stops the watching. For example: 292 | ```javascript 293 | $scope.$watch('username', function(){ 294 | if($scope.username=='secret'){ 295 | console.log('You typed in a secret name'); 296 | } 297 | }); 298 | ``` 299 | Now assume we have a `ng-model` input to allow the user to type in the `username`. When the value updates and evaluates to `secret` the message will be logged to the console. 300 | `$watch` can also watch functions to monitor their return function. The `deepWatch` parameter is a boolean. If set to true and an array of objects is passed into the `toWatch` parameter, each property of the object will be checked for changes. 301 | 302 | #### Angular Classes 303 | Angular automatically adds classes to some elements depending on how it's being used. Here are some use cases: 304 | * `ng-invalid`/`ng-valid` will be on an input element depending on if the text inside has passed validation or not 305 | * `ng-pristine`/`ng-dirty` - if the user hasn't interacted with an input element it will have the class of `ng-pristine` and if it has been interacted with it will be `ng-dirty`. 306 | * `ng-binding` is given to any element that has data binding on it. 307 | * `ng-scope` is given to any element with a new scope. 308 | * `ng-class` is an attribute of an element. We pass in an object with keys that are CSS class names and values are conditions. An example follows: 309 | ```javascript 310 |
...
311 | ``` 312 | More information found [here](https://docs.angularjs.org/guide/css-styling) 313 | 314 | #### element() 315 | AngularJS implements jqLite which is a light version of jQuery. Thus if you are using jQuery on your page you can treat it as a jQuery element, if not we can just use the jqLite API to interact with it. We can see which jQuery methods that jqLite supports over at [the Angular Documentation](https://docs.angularjs.org/api/ng/function/angular.element#angular-s-jqlite). 316 | A few quick tip: 317 | * Never use `element` in controllers as controllers only have logic for views. 318 | * Try to avoid using jQuery. If we must there is a [video here](https://www.youtube.com/watch?v=bk-CC61zMZk) which suggests that we keep jQuery manipulation within link functions of directives. *I haven't tried this myself yet* 319 | 320 | ### 06-Template 321 | Templates are an easy way of making your code very organized. [06-0-templateurl.html](https://github.com/zafarali/learning-angular/blob/master/06-0-templateurl.html) demonstrates how to link a partial file into the main view using the `templateUrl` property of a directive. Note that to use `templateUrl` we must have our files on a server. We can use `$templateCache` to load strings of html into the cache to mimic this effect if we do not have a seperate .html file. We then execute it using `app.run()` function. 322 | We can retrieve what's on `$templateCache` using the `get` function and we can insert things into it using the `put` function as seen in the example at [06-1-templatecache.html](https://github.com/zafarali/learning-angular/blob/master/06-1-templatecache.html) 323 | 324 | ### 07-Routing 325 | *This section requires you to have a server running, this can be easily executed by the bash command `php -S localhost:8080` on a Mac terminal* 326 | #### The `app.config` function 327 | In the config phase of our application, there are objects known as providers available for us to use. They generate instances of services. This is not an important concept right now but basically the `.config` sets up what will be available to us in the controllers. 328 | #### `ng-view` and the `$routeProvider` 329 | `ng-view` is a directive that acts as a window that Angular can load views into. In the `config` function, we will inject `$routeProvider` whhere we can configure the different views and the controller associated with the view. The concept itself is difficult to grasp if you have never seen routing before but the syntax is relatively intuitive to pick up. 330 | We call the `.when(pg,{templateUrl:templatePage,controller:pageCtrl})` function on the `$routeProvider` object. The `pg` string is what the page url will look like. the `templatePage` and `pageCtrl` are strings which are matched to the page we want to load into the view and the controller associated with that object. This is demonstrated in [07-0-ngview.html](https://github.com/zafarali/learning-angular/blob/master/07-0-ngview.html). 331 | We can chain multiple `.when()` functions together (which is the common methodology adpoted by most users). There is also an `.otherwise()` function which will be the default page incase a page is not found. This is demonstrated in [07-1-routing.html](https://github.com/zafarali/learning-angular/blob/master/07-1-routing.html) 332 | 333 | **NOTE: The information in the videos and in the book is slightly outdated. AngularJS no longer has `$routeProvider` built into it. We must inject the `ngRoute` module into our application and include a special link to the module. See 07-0-ngview.html for an example.** 334 | 335 | #### `$routeParams` 336 | The `$routeParams` object when injected into a controller lets us access the parameters from the route. We define paramaters into our `$routeProvider` object as follows: 337 | ```javascript 338 | app.config(['$routeProvider', function($routeProvider){ 339 | $routeProvider.when('/path/:message',{ 340 | templateUrl:myUrl, 341 | controller:myCtrl 342 | }); 343 | }]) 344 | ``` 345 | We use the special syntax for `:message` to indicate that this is a parameter. Thus we can load multiple urls with `#/path/X` where X is the message we wish to pass in. Once this is configured we get this parameter in the controller by using `$routeParams.message`. We must note here that in both `:parameter` and `$routeParams.parameter`, the parameter must match to get the correct information. This is demonstrated in [07-2-routeParams.html](https://github.com/zafarali/learning-angular/blob/master/07-2-routeParams.html). Using this same ideology we can pass multiple parameters as follows: `.when('/:parameter1/:parameter2/:parameter3', ...)` and access it using `$routeParams.parameter1` etc. 346 | 347 | #### Dynamic Handling 348 | I call this dynamic handling (sounds cooler) but basically instead of just sending the user to a string we can actually use a function to return a dynamically created URL. The key here is to use the `redirectTo` property when passing the object into the `.when()` function. 349 | Imagine the scenario where you have a blog 'MyAmazingBlog' and you serve `#/blog/postid` for a few years but you want to start a new blog 'ExtraBlogStuff' and want to redirect people to the correct URL. We could write a function as follows: 350 | ```javascript 351 | app.config(['$routeProvider', function($routeProvider){ 352 | $routeProvider.when('/blog/:blogname/:blogpost',{ 353 | 354 | //this returns the correct template for the blog, either MyAmazingBlog or ExtraBlogStuff, if not specified it will move onto //the next .when() 355 | templateUrl:function(routeParams){ 356 | return routeParams.blogname+'.html'; }, 357 | controller:'BlogCtrl' 358 | }) 359 | .when('/blog/:blogpost', { 360 | //here we direct our older linked users to the new blog 361 | redirectTo:function(routeParams){ 362 | return '/blog/MyAmazingBlog/'+routeParams.blogpost; 363 | }); 364 | }]); 365 | ``` 366 | I hope this example clearly demonstrates a use case and how to for using the '$routeParams' and '$routeProvider' objects correctly. 367 | *Note: The other parameters we can pass into the functions within route provider are as follows:* 368 | ```javascript 369 | function(routeParams, path, search){ 370 | //routeParams as we have seen above 371 | //path is the path url in full 372 | //search returns the queries after the path url 373 | //i.e. ?query=true&message=what as a key:value object 374 | return '/'; //we must return a string! 375 | } 376 | ``` 377 | #### Promises 378 | Promises are a way of executing a chain of functions. Some people say it avoids the bracket hell that occurs by passing in functions into functions. (Other benefits include: Error Handling in addition to clearer code) 379 | Angular comes with a promise library called `$q`. The key thing to remember is that we will deal with a `defer` object which we can pass in a sequence of functions to *(making some promises)* and then call the `resolve()` function to execute them. 380 | In [07-3-promises.html](https://github.com/zafarali/learning-angular/blob/master/07-3-promises.html) we demonstrate basic functionality of the promise objects and a slightly more complex version using the passing arguments. There is also a way to handle errors, this is demonstrated in the codeblock below: 381 | ```javascript 382 | defer.promise 383 | .then(function(name){ 384 | return name.split('').reverse().join(''); 385 | }) 386 | .then(function(reversedName){ 387 | //do some more processing 388 | return processedName; 389 | }) 390 | .then(function(display){ 391 | console.log(display); 392 | }, function(error){ 393 | //handling the error in any of the prior steps 394 | }); 395 | ``` 396 | 397 | #### Resolve property for $routeProvider 398 | In addition to passing `templateUrl` and `controller` to the second object parameter of the `.when()` function, we can pass in `resolve` which is a list of promises that need to be resolved before the controller initiates. This allows us to load all necessary data before loading the view. Demonstrated by [this commit](https://github.com/zafarali/learning-angular/commit/2192e8cecc2a39386b9954ff165aaabc17771a79), I reiterate the experiment for clarity: 399 | 1. **URL: #/** This template will never load. This is because our promise is never resolved! 400 | 2. **URL: #/sup** This template loads instantaneously because we resolve the promise and then return it. 401 | 3. **URL: #/bye** This template loads after 3 seconds. This is because we use `$timeout` (which is a wrapper for `setTimeout()`) to `resolve()` the promise after 3 seconds. 402 | 403 | This [video](http://www.thinkster.io/angularjs/6cmY50Dsyf/angularjs-resolve-conventions) demonstrates some conventions used when we use resolve properties in `$routeProvider`. Just to reiterate, all the functions we pass into the resolve properties are added to the Controllers as properties themselves. The video also points out that once the view loads, we can access the result of the resolve promises by using `$route.locals.nameOfResolvePromise`. 404 | 405 | #### Handling `$resolveChangeError`s 406 | *What happens if your promises don't resolve and instead throw errors?* 407 | Our application would never load and nothing would show up no matter what we try to do. In this case we set up another default controller to handle this situation. A demonstration is at [07-5-ChangeError.html](https://github.com/zafarali/learning-angular/blob/master/07-5-ChangeError.html) make sure to read the comments to understand what is happening! 408 | A [video](http://www.thinkster.io/angularjs/8u6fK7qWYv/angularjs-directive-for-route-handling) suggests that we create a directive to handle the `$routeChangeError`. I leave you to click over and read through how its done. 409 | 410 | #### `$location` 411 | `$location` is a wrapper around the `window.location` method/object. It provides some handy getters and setters and can use HTML5 methods when available or default to non-HTML5 methods. Since it is provided by AngularJS it is aware of when things change (We do not need to `watch()` it.) 412 | Here are some methods: 413 | 1. `absUrl()` returns the whole URL including the paths 414 | 2. `host()` returns the host (i.e www.host.com) 415 | 3. `path()` returns the path the app is currently at. 416 | 4. `search()` allows us to get a key value pair for the queries passed in. 417 | 5. `url()` returns the path and the query parameters. 418 | *Note that `path()`, `search()` and `url()` are also setters for the same property.* 419 | 420 | - [ ] To Do The Route Life Cycle 421 | 422 | ### Server Communication 423 | Anyone who has worked with servers and javascript would have come across AJAX and its method of fetching data from the server using `XMLHttpRequest()`. AngularJS makes it easy to deal with these kind of objects by wrapping them as example one shows. 424 | #### `$http` 425 | ```javascript 426 | $http.get('api/user/', {params:{id:'5'}} 427 | ).success(function(data,status,headers,config){ 428 | //continue the application 429 | }).error(function(data,status,headers,config){ 430 | //deal with the error here 431 | }); 432 | ``` 433 | As you can see this nicely wraps around a repetitive feature that we need often. 434 | All return types of the above are promise objects. The `$http` object is called with a `config` object which follows this format: 435 | ```javascript 436 | var config = { 437 | method: "GET" || "POST", //... 438 | url: "urlOfTarget", 439 | params: [{key1:'value1', key2:'value2'}], //this turns into ?key1=value1&key2=value2 440 | data: 'string'|| object, //..to be placed on the server 441 | headers: object, //to be defined later 442 | cache: boolean, //caching the data 443 | timeout:int //how long to wait before expiring 444 | } 445 | ``` 446 | There are some other config properties as well which I am refraining from discussing to keep things simple 447 | Here are some other (shorthand) methods that `$http` provides us with: 448 | 1. `$http.get(url, [config])` 449 | 2. `$http.post(url, data, [config])` 450 | 3. `$http.put(url, data, [config])` 451 | 4. `$http.delete(url, [config])` 452 | 5. `$http.jsonp(url, [config])` 453 | 6. `$http.head(url, [config])` 454 | The `$resource` object is a another method often used to interact with an API. This is explored in the next section. 455 | 456 | #### `$resource` 457 | *This has a dependancy ngResource* 458 | The `$resource` is a wrapper for using an API. We create a resource by calling `$resource(url, parameters, actions, options)` 459 | ```javascript 460 | var UserProfile = $resource('/api/user/:userID', 461 | //get the id from a passed in string. 462 | {userID:'@id'}, 463 | { 464 | //defining a custom action 465 | getBalance: {method:'GET',params:{showBal:true}} 466 | }); 467 | ``` 468 | Manipulating the object is as easy as manipulating any user defined object: 469 | ```javascript 470 | var users = UserProfile.query(function(){ 471 | //this does: 472 | //GET: /api/user/ 473 | //the server returns: 474 | //[{id:1, name:'Jane'}, {id:2, name:'John'}]; 475 | 476 | //we can access specific instaces of the cards as we refer to arrays. I.e users[0], users[1] ... 477 | var user = users[0] 478 | user.name = "Doe" //overrides the object property 'name' to Doe. 479 | user.$save(); 480 | //this does: 481 | //POST: /api/user/1 {id:1, name:'Doe'}, 482 | //server returns the above. 483 | 484 | user.$getBalance(); 485 | //does a GET: /user/1?showBal=true 486 | 487 | }); 488 | ``` 489 | We can even create new instances as we do with regular objects: 490 | ```javascript 491 | var newUser = new UserProfile({name:"James Bond"}); 492 | newUser.$save(); 493 | ``` 494 | The functions/methods available to us without any further modification are: 495 | 1. `.get()` which does a GET request. 496 | 2. `.$save()` which does a POST request. 497 | 3. `.query()` which does a GET request and returns an array. 498 | 4. `.$remove()` which does a DELETE request. 499 | 5. `.$delete()` which does a DELETE request. 500 | The getters and the deleters, `.get()`, `.query()`, `.$remove()` and `.$delete()` can be passed a callback function with `(value,headers)` and the error callback is passed with `httpResponse` argument. 501 | A full example of this would be `UserProfile.get({id:1}, function(data){/*do success stuff*/}, function(response){/*handle error*/})`. 502 | The setter `.$save()` is called with some data to be posted and has the same success/error callback pattern. 503 | A full example of this would be: 504 | `Notes.$save({noteId:2, author:'Camillo'}, "This is an amazing note wow", successCallback, errorCallback)` 505 | 506 | 1. **url** contains a parameterized version of the URL we are going to interact with. For example it can be: `http://www.myexample.com/data.json` or `http://www.myexample.com/api/user/:id`. 507 | 2. **parameters** sets default parameters that we are going to pass into the object. From what I see the most likely use case is with the `@` parameter. This will be elaborated later. 508 | 3. **options** Will be discussed later 509 | 4. **actions** will extend the functionality of the `$resource` object. This was demonstrated above but just for clarity here's another example: 510 | ```javascript 511 | app.factory('Notes', ['$resource', function($resource){ 512 | return $resource('api/notes/:id', null, {'update':{method:'PUT'} 513 | }); 514 | }]); 515 | Notes.update({id:'2'}, "This is amazing!"); 516 | ``` 517 | We can now call `Notes.update({id:id}, data);` after injecting the `Notes` factory into our controller. 518 | This makes our code easier to deal with by only dealing with objects and not with repeated instances of urls. We must note that `$resource` depends on `$http` which will be discussed shortly. 519 | 520 | ##### Notes Regarding Cross Domain Requests 521 | You may or may not know that Javascript cannot make AJAX calls to a domain thats not their own. i.e. your website (assuming you don't work for twitter) cannot ping twitter to get tweets. However, there is a method around this known as padding or *JSONP*. (I found out after the video that Twitter no longer offers this API without authentication, Instead I decided to use the [Meetup API for cities](http://www.meetup.com/meetup_api/docs/2/cities/)) . In the example [08-1-ngResource.html](https://github.com/zafarali/learning-angular/blob/master/08-1-ngResource.html) I override the usual GET method of the resource object with the JSONP method which allows me to access the Meetup API and retrieve nearest cities. Note that not all websites provide a JSONP enabled API. The page is made following the tutorial from [egghead.io](https://www.youtube.com/watch?v=IRelx4-ISbs). [Meetup Cities API](http://www.meetup.com/meetup_api/docs/2/cities/). **Read the comments in 08-1-ngResource.html for in depth explanation of what is happening** 522 | 523 | Another conversation I found online regarding the `ngResource` module is that the above example doesn't demonstrate its complete power. Infact `$resource` should be used when we have objects to `.get()`, manipulate and then `.$save()` back onto the server. 524 | 525 | ### Interesting things to know 526 | Here are a few things I felt like covering to give us a nice break from the very serious factory, provider, module, routing stuff we have been getting into 527 | #### `ngAnimate` 528 | Animations in AngularJS require us to inject a special module known as `ngAnimate` which adds special classes to elements that can be animated in special ways. In [08-0-ngAnimate.html](https://github.com/zafarali/learning-angular/blob/master/08-0-ngAnimate.html) we see three separate cases of how these are done using CSS. 529 | The key thing to remember here is that while the animation is being executed (i.e the transitions and the animations), the class of the element will have `.ng-enter-active`. 530 | 531 | #### Scope Communication 532 | We have seen previously that there are ways to watch for events/changes using `$watch` but here we introduce another way known as `$on`. This monitors the scope for an event of a name. For example: 533 | ```javascript 534 | scope.$on('myEventName', function(event, param1, param2, ...) { 535 | console.log(param1 + ' ' + param2); 536 | scope.doEvent(param1, param2); 537 | }); 538 | 539 | //The above can be invoked by: 540 | scope.$emit('myEventName', 'Hello', 'World'); 541 | //or 542 | scope.$broadcast('myEventName', 'Bye', 'World'); 543 | ``` 544 | What is the difference between `$emit` and `$broadcast`? As mentioned previously `$emit` propagates the event upwards and all controllers listening for `myEventName` in the parent scopes will be alerted. `$broadcast` does the opposite and propagates the event downwards. Note that both these events will also execute in their own scopes. 545 | 546 | A new example here [08-2-onEmitBroadcast.html](https://github.com/zafarali/learning-angular/blob/master/08-2-onEmitBroadcast.html) demonstrates this. Remember that declaring a new controller automatically creates a new scope. The page is also demonstrates inherited scopes and overriding properties. 547 | I've realized that this is one of AngularJS' most powerful feature. 548 | 549 | ### Forms 550 | *Content from this section (Forms) is based off the course [Shaping Up With AngularJS](http://campus.codeschool.com/courses/shaping-up-with-angular-js/)* 551 | Remember when we discussed [Angluar Classes above](https://github.com/zafarali/learning-angular#angular-classes)? AngluarJS provides us with a couple of other nice tricks and features that make form validations easier. Let's look at each of them step by step and then do an example: 552 | - `ng-submit` is an attribute of the `
` element that has the function will be invoked when the user clicks the 'submit' button. Alternatively this function can also be in `ng-click` of the `