├── .bowerrc ├── .editorconfig ├── .gitattributes ├── .gitignore ├── .jshintrc ├── .travis.yml ├── .yo-rc.json ├── Gruntfile.js ├── README.md ├── angular-display-advanced.png ├── app ├── .buildignore ├── .htaccess ├── 404.html ├── angular.json ├── angular2.json ├── favicon.ico ├── images │ └── yeoman.png ├── index.html ├── robots.txt ├── scripts │ ├── app.js │ ├── controllers │ │ ├── directives.js │ │ ├── module.js │ │ ├── organization.js │ │ └── service.js │ ├── directives │ │ ├── directive-example.js │ │ ├── inner-directive.js │ │ └── module.js │ ├── providers │ │ └── gravatar2.js │ ├── routes.js │ └── services │ │ ├── gravatar.js │ │ └── module.js ├── styles │ └── main.css └── views │ ├── a-module.html │ ├── directive-example.html │ ├── directives.html │ ├── inner-directive.html │ ├── module.html │ ├── organization.html │ └── service.html ├── bower.json └── package.json /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # Change these settings to your own preference 11 | indent_style = space 12 | indent_size = 2 13 | 14 | # We recommend you to keep these unchanged 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist 3 | /.tmp 4 | /.sass-cache 5 | /bower_components 6 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": true, 3 | "browser": true, 4 | "curly": true, 5 | "eqeqeq": true, 6 | "esnext": true, 7 | "latedef": true, 8 | "noarg": true, 9 | "node": true, 10 | "strict": true, 11 | "undef": true, 12 | "unused": true, 13 | "globals": { 14 | "angular": false 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - 'iojs' 5 | - '0.12' 6 | - '0.10' 7 | before_script: 8 | - 'npm install -g bower grunt-cli' 9 | - 'bower install' 10 | -------------------------------------------------------------------------------- /.yo-rc.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | // Generated on 2015-07-18 using generator-angular 0.12.1 2 | 'use strict'; 3 | 4 | // # Globbing 5 | // for performance reasons we're only matching one level down: 6 | // 'test/spec/{,*/}*.js' 7 | // use this if you want to recursively match all subfolders: 8 | // 'test/spec/**/*.js' 9 | 10 | module.exports = function (grunt) { 11 | 12 | // Time how long tasks take. Can help when optimizing build times 13 | require('time-grunt')(grunt); 14 | 15 | // Automatically load required Grunt tasks 16 | require('jit-grunt')(grunt, { 17 | useminPrepare: 'grunt-usemin', 18 | ngtemplates: 'grunt-angular-templates', 19 | cdnify: 'grunt-google-cdn' 20 | }); 21 | 22 | // Configurable paths for the application 23 | var appConfig = { 24 | app: require('./bower.json').appPath || 'app', 25 | dist: 'dist' 26 | }; 27 | 28 | // Define the configuration for all the tasks 29 | grunt.initConfig({ 30 | 31 | // Project settings 32 | yeoman: appConfig, 33 | 34 | // Watches files for changes and runs tasks based on the changed files 35 | watch: { 36 | bower: { 37 | files: ['bower.json'], 38 | tasks: ['wiredep'] 39 | }, 40 | js: { 41 | files: ['<%= yeoman.app %>/scripts/{,*/}*.js'], 42 | tasks: ['newer:jshint:all'], 43 | options: { 44 | livereload: '<%= connect.options.livereload %>' 45 | } 46 | }, 47 | jsTest: { 48 | files: ['test/spec/{,*/}*.js'], 49 | tasks: ['newer:jshint:test', 'karma'] 50 | }, 51 | styles: { 52 | files: ['<%= yeoman.app %>/styles/{,*/}*.css'], 53 | tasks: ['newer:copy:styles', 'autoprefixer'] 54 | }, 55 | gruntfile: { 56 | files: ['Gruntfile.js'] 57 | }, 58 | livereload: { 59 | options: { 60 | livereload: '<%= connect.options.livereload %>' 61 | }, 62 | files: [ 63 | '<%= yeoman.app %>/{,*/}*.html', 64 | '.tmp/styles/{,*/}*.css', 65 | '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}' 66 | ] 67 | } 68 | }, 69 | 70 | // The actual grunt server settings 71 | connect: { 72 | options: { 73 | port: 9000, 74 | // Change this to '0.0.0.0' to access the server from outside. 75 | hostname: 'localhost', 76 | livereload: 35729 77 | }, 78 | livereload: { 79 | options: { 80 | open: true, 81 | middleware: function (connect) { 82 | return [ 83 | connect.static('.tmp'), 84 | connect().use( 85 | '/bower_components', 86 | connect.static('./bower_components') 87 | ), 88 | connect().use( 89 | '/app/styles', 90 | connect.static('./app/styles') 91 | ), 92 | connect.static(appConfig.app) 93 | ]; 94 | } 95 | } 96 | }, 97 | test: { 98 | options: { 99 | port: 9001, 100 | middleware: function (connect) { 101 | return [ 102 | connect.static('.tmp'), 103 | connect.static('test'), 104 | connect().use( 105 | '/bower_components', 106 | connect.static('./bower_components') 107 | ), 108 | connect.static(appConfig.app) 109 | ]; 110 | } 111 | } 112 | }, 113 | dist: { 114 | options: { 115 | open: true, 116 | base: '<%= yeoman.dist %>' 117 | } 118 | } 119 | }, 120 | 121 | // Make sure code styles are up to par and there are no obvious mistakes 122 | jshint: { 123 | options: { 124 | jshintrc: '.jshintrc', 125 | reporter: require('jshint-stylish') 126 | }, 127 | all: { 128 | src: [ 129 | 'Gruntfile.js', 130 | '<%= yeoman.app %>/scripts/{,*/}*.js' 131 | ] 132 | }, 133 | test: { 134 | options: { 135 | jshintrc: 'test/.jshintrc' 136 | }, 137 | src: ['test/spec/{,*/}*.js'] 138 | } 139 | }, 140 | 141 | // Empties folders to start fresh 142 | clean: { 143 | dist: { 144 | files: [{ 145 | dot: true, 146 | src: [ 147 | '.tmp', 148 | '<%= yeoman.dist %>/{,*/}*', 149 | '!<%= yeoman.dist %>/.git{,*/}*' 150 | ] 151 | }] 152 | }, 153 | server: '.tmp' 154 | }, 155 | 156 | // Add vendor prefixed styles 157 | autoprefixer: { 158 | options: { 159 | browsers: ['last 1 version'] 160 | }, 161 | server: { 162 | options: { 163 | map: true, 164 | }, 165 | files: [{ 166 | expand: true, 167 | cwd: '.tmp/styles/', 168 | src: '{,*/}*.css', 169 | dest: '.tmp/styles/' 170 | }] 171 | }, 172 | dist: { 173 | files: [{ 174 | expand: true, 175 | cwd: '.tmp/styles/', 176 | src: '{,*/}*.css', 177 | dest: '.tmp/styles/' 178 | }] 179 | } 180 | }, 181 | 182 | // Automatically inject Bower components into the app 183 | wiredep: { 184 | app: { 185 | src: ['<%= yeoman.app %>/index.html'], 186 | ignorePath: /\.\.\// 187 | }, 188 | test: { 189 | devDependencies: true, 190 | src: '<%= karma.unit.configFile %>', 191 | ignorePath: /\.\.\//, 192 | fileTypes:{ 193 | js: { 194 | block: /(([\s\t]*)\/{2}\s*?bower:\s*?(\S*))(\n|\r|.)*?(\/{2}\s*endbower)/gi, 195 | detect: { 196 | js: /'(.*\.js)'/gi 197 | }, 198 | replace: { 199 | js: '\'{{filePath}}\',' 200 | } 201 | } 202 | } 203 | } 204 | }, 205 | 206 | // Renames files for browser caching purposes 207 | filerev: { 208 | dist: { 209 | src: [ 210 | '<%= yeoman.dist %>/scripts/{,*/}*.js', 211 | '<%= yeoman.dist %>/styles/{,*/}*.css', 212 | '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}', 213 | '<%= yeoman.dist %>/styles/fonts/*' 214 | ] 215 | } 216 | }, 217 | 218 | // Reads HTML for usemin blocks to enable smart builds that automatically 219 | // concat, minify and revision files. Creates configurations in memory so 220 | // additional tasks can operate on them 221 | useminPrepare: { 222 | html: '<%= yeoman.app %>/index.html', 223 | options: { 224 | dest: '<%= yeoman.dist %>', 225 | flow: { 226 | html: { 227 | steps: { 228 | js: ['concat', 'uglifyjs'], 229 | css: ['cssmin'] 230 | }, 231 | post: {} 232 | } 233 | } 234 | } 235 | }, 236 | 237 | // Performs rewrites based on filerev and the useminPrepare configuration 238 | usemin: { 239 | html: ['<%= yeoman.dist %>/{,*/}*.html'], 240 | css: ['<%= yeoman.dist %>/styles/{,*/}*.css'], 241 | js: ['<%= yeoman.dist %>/scripts/{,*/}*.js'], 242 | options: { 243 | assetsDirs: [ 244 | '<%= yeoman.dist %>', 245 | '<%= yeoman.dist %>/images', 246 | '<%= yeoman.dist %>/styles' 247 | ], 248 | patterns: { 249 | js: [[/(images\/[^''""]*\.(png|jpg|jpeg|gif|webp|svg))/g, 'Replacing references to images']] 250 | } 251 | } 252 | }, 253 | 254 | // The following *-min tasks will produce minified files in the dist folder 255 | // By default, your `index.html`'s will take care of 256 | // minification. These next options are pre-configured if you do not wish 257 | // to use the Usemin blocks. 258 | // cssmin: { 259 | // dist: { 260 | // files: { 261 | // '<%= yeoman.dist %>/styles/main.css': [ 262 | // '.tmp/styles/{,*/}*.css' 263 | // ] 264 | // } 265 | // } 266 | // }, 267 | // uglify: { 268 | // dist: { 269 | // files: { 270 | // '<%= yeoman.dist %>/scripts/scripts.js': [ 271 | // '<%= yeoman.dist %>/scripts/scripts.js' 272 | // ] 273 | // } 274 | // } 275 | // }, 276 | // concat: { 277 | // dist: {} 278 | // }, 279 | 280 | imagemin: { 281 | dist: { 282 | files: [{ 283 | expand: true, 284 | cwd: '<%= yeoman.app %>/images', 285 | src: '{,*/}*.{png,jpg,jpeg,gif}', 286 | dest: '<%= yeoman.dist %>/images' 287 | }] 288 | } 289 | }, 290 | 291 | svgmin: { 292 | dist: { 293 | files: [{ 294 | expand: true, 295 | cwd: '<%= yeoman.app %>/images', 296 | src: '{,*/}*.svg', 297 | dest: '<%= yeoman.dist %>/images' 298 | }] 299 | } 300 | }, 301 | 302 | htmlmin: { 303 | dist: { 304 | options: { 305 | collapseWhitespace: true, 306 | conservativeCollapse: true, 307 | collapseBooleanAttributes: true, 308 | removeCommentsFromCDATA: true 309 | }, 310 | files: [{ 311 | expand: true, 312 | cwd: '<%= yeoman.dist %>', 313 | src: ['*.html'], 314 | dest: '<%= yeoman.dist %>' 315 | }] 316 | } 317 | }, 318 | 319 | ngtemplates: { 320 | dist: { 321 | options: { 322 | module: 'advancedTopicsApp', 323 | htmlmin: '<%= htmlmin.dist.options %>', 324 | usemin: 'scripts/scripts.js' 325 | }, 326 | cwd: '<%= yeoman.app %>', 327 | src: 'views/{,*/}*.html', 328 | dest: '.tmp/templateCache.js' 329 | } 330 | }, 331 | 332 | // ng-annotate tries to make the code safe for minification automatically 333 | // by using the Angular long form for dependency injection. 334 | ngAnnotate: { 335 | dist: { 336 | files: [{ 337 | expand: true, 338 | cwd: '.tmp/concat/scripts', 339 | src: '*.js', 340 | dest: '.tmp/concat/scripts' 341 | }] 342 | } 343 | }, 344 | 345 | // Replace Google CDN references 346 | cdnify: { 347 | dist: { 348 | html: ['<%= yeoman.dist %>/*.html'] 349 | } 350 | }, 351 | 352 | // Copies remaining files to places other tasks can use 353 | copy: { 354 | dist: { 355 | files: [{ 356 | expand: true, 357 | dot: true, 358 | cwd: '<%= yeoman.app %>', 359 | dest: '<%= yeoman.dist %>', 360 | src: [ 361 | '*.{ico,png,txt}', 362 | '.htaccess', 363 | '*.html', 364 | 'images/{,*/}*.{webp}', 365 | 'styles/fonts/{,*/}*.*' 366 | ] 367 | }, { 368 | expand: true, 369 | cwd: '.tmp/images', 370 | dest: '<%= yeoman.dist %>/images', 371 | src: ['generated/*'] 372 | }, { 373 | expand: true, 374 | cwd: 'bower_components/bootstrap/dist', 375 | src: 'fonts/*', 376 | dest: '<%= yeoman.dist %>' 377 | }] 378 | }, 379 | styles: { 380 | expand: true, 381 | cwd: '<%= yeoman.app %>/styles', 382 | dest: '.tmp/styles/', 383 | src: '{,*/}*.css' 384 | } 385 | }, 386 | 387 | // Run some tasks in parallel to speed up the build process 388 | concurrent: { 389 | server: [ 390 | 'copy:styles' 391 | ], 392 | test: [ 393 | 'copy:styles' 394 | ], 395 | dist: [ 396 | 'copy:styles', 397 | 'imagemin', 398 | 'svgmin' 399 | ] 400 | }, 401 | 402 | // Test settings 403 | karma: { 404 | unit: { 405 | configFile: 'test/karma.conf.js', 406 | singleRun: true 407 | } 408 | } 409 | }); 410 | 411 | 412 | grunt.registerTask('serve', 'Compile then start a connect web server', function (target) { 413 | if (target === 'dist') { 414 | return grunt.task.run(['build', 'connect:dist:keepalive']); 415 | } 416 | 417 | grunt.task.run([ 418 | 'clean:server', 419 | 'wiredep', 420 | 'concurrent:server', 421 | 'autoprefixer:server', 422 | 'connect:livereload', 423 | 'watch' 424 | ]); 425 | }); 426 | 427 | grunt.registerTask('server', 'DEPRECATED TASK. Use the "serve" task instead', function (target) { 428 | grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.'); 429 | grunt.task.run(['serve:' + target]); 430 | }); 431 | 432 | grunt.registerTask('test', [ 433 | 'clean:server', 434 | 'wiredep', 435 | 'concurrent:test', 436 | 'autoprefixer', 437 | 'connect:test', 438 | 'karma' 439 | ]); 440 | 441 | grunt.registerTask('build', [ 442 | 'clean:dist', 443 | 'wiredep', 444 | 'useminPrepare', 445 | 'concurrent:dist', 446 | 'autoprefixer', 447 | 'ngtemplates', 448 | 'concat', 449 | 'ngAnnotate', 450 | 'copy:dist', 451 | 'cdnify', 452 | 'cssmin', 453 | 'uglify', 454 | 'filerev', 455 | 'usemin', 456 | 'htmlmin' 457 | ]); 458 | 459 | grunt.registerTask('default', [ 460 | 'newer:jshint', 461 | 'test', 462 | 'build' 463 | ]); 464 | }; 465 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [](https://angular.io) 2 | 3 | AngularJS : Advanced Topics 4 | ================ 5 | 6 | A project aimed to help the user master AngularJS advanced topics. Each unit contains a tutorial with concepts, examples and best practices. 7 | 8 | Topics 9 | ================ 10 | - Routing and ($routeProvider and $routeParams) 11 | - Directives ($scope and Scope) 12 | - Directives (Require and Link attributes) 13 | - Services (Factory Pattern and $resource) 14 | - Provider Service Pattern 15 | 16 | Suggested prerequisites 17 | ==================== 18 | [](https://github.com/MartinChavez/Learn-Javascript) 19 | [](https://github.com/MartinChavez/HTML-CSS) 20 | [](https://github.com/MartinChavez/HTML-CSS-Advanced-Topics) 21 | [](https://github.com/MartinChavez/AngularJs-Basics) 22 | 23 | Tools 24 | ==================== 25 | [](https://nodejs.org/) 26 | [](http://yeoman.io/) 27 | [](https://github.com/gruntjs/grunt) 28 | [](http://bower.io/) 29 | [](https://www.npmjs.com/) 30 | 31 | Routes and $routeProvider 32 | ==================== 33 | ```Javascript 34 | /* Routes*/ 35 | //Angular routes allow us to map URLs to use templates so that every time the current route changes, 36 | //the included view changes with it 37 | 38 | /* $routeProvider*/ 39 | //$routeProvider allows you to specify Routes in the Angular application 40 | 41 | //It is a good practice to re-declare your application module in every new file 42 | angular.module('advancedTopicsApp').config(function ($routeProvider) { 43 | 44 | //Inside module.config, we can use one of $routeProvider's methods to define routes 45 | 46 | /* .when (path, route)*/ 47 | //Adds a new route definition to the $route service 48 | 49 | /* .otherwise (params)*/ 50 | //Sets route definition that will be used on route change when no other route definition is matched 51 | 52 | //You only need to define $routeProvider once and use method chaining 53 | $routeProvider 54 | .when('/', { 55 | /* Routing Components*/ 56 | //It is possible to associate routes with templates and controllers 57 | templateUrl: 'views/organization.html', 58 | //It is a good practice to link to an already existing controller 59 | controller: 'OrganizationCtrl', 60 | //You can use 'controllerAs' to assign an alias to this controller 61 | controllerAs: 'organization' 62 | }) 63 | .when('/service', { 64 | templateUrl: 'views/service.html', 65 | controller: 'ServiceCtrl', 66 | controllerAs: 'service' 67 | }) 68 | .when('/directives', { 69 | templateUrl: 'views/directives.html', 70 | controller: 'DirectivesCtrl', 71 | controllerAs: 'directives' 72 | }) 73 | //Declaring routes based on Id's 74 | //By passing in $routeParams we can obtain identifiers and utilize them 75 | .when('/module/:id', { 76 | templateUrl: 'views/module.html', 77 | controller: 'ModuleCtrl', 78 | controllerAs: 'module' 79 | }) 80 | .otherwise({ 81 | redirectTo: '/' 82 | }); 83 | }); 84 | ``` 85 | Directives ($scope and Scope) 86 | ==================== 87 | ```Javascript 88 | /*Directives*/ 89 | //Directives Inherit their parent's scope by default 90 | angular.module("advancedTopicsApp") 91 | .directive("module", function () { 92 | 93 | /* $scope */ 94 | return { 95 | restrict: "E", 96 | templateUrl: "views/a-module.html", 97 | //Isolating the Scope 98 | 99 | //By passing an object to the scope option, you create an isolated scope. 100 | //This tells the directive to keep scope inside itself and not to inherit or share with others 101 | scope: { 102 | //You can pass as many bindings as you need 103 | 104 | //title:"@" passes in a string 105 | title: "=", // '=' is a two-way binding, 106 | id: "=" 107 | }, 108 | //There are three options when binding data to an isolated scope: @,= and & characters 109 | 110 | /*Link*/ 111 | //The link function is run after the directive has been compiled and linked up 112 | //This is the best place to do any DOM manipulation or logic functionality 113 | 114 | //element: refers to the outermost element of the directive 115 | //attrs stands for attributes 116 | link: function (scope, element, attrs) { 117 | element.on("click", function () { 118 | element("div.module p").toggleClass("hidden"); 119 | }); 120 | 121 | } 122 | // By using the $scope variable, you can avoid using alias by binding the local variables to $scope 123 | //This is very helpful in the views, since you don't need to reference any controller 124 | 125 | }; 126 | 127 | /*Important: Difference between $scope and Scope Object*/ 128 | 129 | //The scope object is used to isolate a directive's scope 130 | //$scope is used to set values and functions on the scope 131 | }); 132 | ``` 133 | 134 | Directives (Require and Link attributes) 135 | ==================== 136 | ```Javascript 137 | angular.module("advancedTopicsApp") 138 | .directive("innerDirective", function () { 139 | 140 | return { 141 | restrict: "E", 142 | templateUrl: "views/inner-directive.html", 143 | scope:{ 144 | innerDirective:"=" 145 | }, 146 | /*Require directive*/ 147 | //It allows to share a controller between directives 148 | // ^ indicates that you are looking for a parent directive 149 | require:"^directiveExample", 150 | 151 | /*Link's 4th parameter*/ 152 | //The required directive's controller is passed in as link's 4th parameter and can have any name 153 | link: function(scope,element,attrs,DirectivesCtrl){ 154 | 155 | scope.makeActive = function(){ 156 | DirectivesCtrl.setActive(scope.innerDirective); 157 | } 158 | 159 | scope.innerDirectiveActive = function (){ 160 | return DirectivesCtrl.getActive() === scope.innerDirective.name; 161 | 162 | } 163 | } 164 | }; 165 | }); 166 | ``` 167 | Services (Factory Pattern and $resource) 168 | ==================== 169 | ```Javascript 170 | /* Services*/ 171 | //Services should hold functions responsible for connecting and fetching data, then sharing it across our application 172 | 173 | //Service Factory 174 | //This a naming convention 175 | angular.module("advancedTopicsApp").factory("Module",function ModuleFactory($http, $resource){ 176 | 177 | 178 | //By using $resource you implement all the required methods for CRUD 179 | return $resource("angular2.json",{},{ 180 | update:{ 181 | method:"PUT" 182 | } 183 | 184 | }); 185 | ``` 186 | Provider Service Pattern 187 | ==================== 188 | ```Javascript 189 | /*Provider Service Recipe*/ 190 | //It allows more configuration than a factory 191 | 192 | //Providers run before everything else,so the only thing you can inject to them is other providers 193 | angular.module("advancedTopicsApp").provider("Gravatar2", function Gravatar2Provider() { 194 | 195 | var avatarSize = 80; //Default size 196 | var avatarUrl = "http://www.gravatar.com/avatar/"; 197 | 198 | this.setSize = function(size){ 199 | avatarSize = size; 200 | }; 201 | 202 | 203 | //The $get function is where you return an object and inject services 204 | this.$get = function() { 205 | return function(email) { 206 | return avatarUrl + CryptoJS.MD5(email) + "?size=" + avatarSize.toString(); 207 | }; 208 | }; 209 | 210 | }); 211 | ``` 212 | 213 | Best Practices 214 | ==================== 215 | ```Javascript 216 | angular.module('advancedTopicsApp') 217 | .controller('OrganizationCtrl', function ($http) { 218 | 219 | //It is a good practice to assign 'this' to a variable in order to use 'this' keyword inside the callback 220 | var controller = this; 221 | $http({method:'GET', url: 'angular.json'}).success(function(data){ 222 | controller.modules = data.modules; 223 | }); 224 | ``` 225 | 226 | Install 227 | ==================== 228 | ```Terminal 229 | npm install 230 | bower install 231 | ``` 232 | 233 | Run and Play 234 | ==================== 235 | ```Terminal 236 | grunt serve 237 | ``` 238 | 239 | 240 | ## Author 241 | 242 | **[Martin Chavez](https://github.com/MartinChavez)** 243 | 244 | Continue Learning 245 | ==================== 246 | [](https://github.com/MartinChavez/Learn-Javascript) 247 | [](https://github.com/MartinChavez/Node.js-Tutorial) 248 | [](https://github.com/MartinChavez/AngularJs-Basics) 249 | [](https://github.com/MartinChavez/AngularJS-Advanced-Topics) 250 | [](https://github.com/MartinChavez/CSharp) 251 | [](https://github.com/MartinChavez/LINQ) 252 | [](https://github.com/MartinChavez/jQueryBasics) 253 | [](https://github.com/MartinChavez/HTML-CSS) 254 | [](https://github.com/MartinChavez/HTML-CSS-Advanced-Topics) 255 | -------------------------------------------------------------------------------- /angular-display-advanced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinChavez/AngularJS-Advanced-Topics/321b00f08770d1279fbfda29c57437d7b2fd5945/angular-display-advanced.png -------------------------------------------------------------------------------- /app/.buildignore: -------------------------------------------------------------------------------- 1 | *.coffee -------------------------------------------------------------------------------- /app/.htaccess: -------------------------------------------------------------------------------- 1 | # Apache Configuration File 2 | 3 | # (!) Using `.htaccess` files slows down Apache, therefore, if you have access 4 | # to the main server config file (usually called `httpd.conf`), you should add 5 | # this logic there: http://httpd.apache.org/docs/current/howto/htaccess.html. 6 | 7 | # ############################################################################## 8 | # # CROSS-ORIGIN RESOURCE SHARING (CORS) # 9 | # ############################################################################## 10 | 11 | # ------------------------------------------------------------------------------ 12 | # | Cross-domain AJAX requests | 13 | # ------------------------------------------------------------------------------ 14 | 15 | # Enable cross-origin AJAX requests. 16 | # http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity 17 | # http://enable-cors.org/ 18 | 19 | # 20 | # Header set Access-Control-Allow-Origin "*" 21 | # 22 | 23 | # ------------------------------------------------------------------------------ 24 | # | CORS-enabled images | 25 | # ------------------------------------------------------------------------------ 26 | 27 | # Send the CORS header for images when browsers request it. 28 | # https://developer.mozilla.org/en/CORS_Enabled_Image 29 | # http://blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html 30 | # http://hacks.mozilla.org/2011/11/using-cors-to-load-webgl-textures-from-cross-domain-images/ 31 | 32 | 33 | 34 | 35 | SetEnvIf Origin ":" IS_CORS 36 | Header set Access-Control-Allow-Origin "*" env=IS_CORS 37 | 38 | 39 | 40 | 41 | # ------------------------------------------------------------------------------ 42 | # | Web fonts access | 43 | # ------------------------------------------------------------------------------ 44 | 45 | # Allow access from all domains for web fonts 46 | 47 | 48 | 49 | Header set Access-Control-Allow-Origin "*" 50 | 51 | 52 | 53 | 54 | # ############################################################################## 55 | # # ERRORS # 56 | # ############################################################################## 57 | 58 | # ------------------------------------------------------------------------------ 59 | # | 404 error prevention for non-existing redirected folders | 60 | # ------------------------------------------------------------------------------ 61 | 62 | # Prevent Apache from returning a 404 error for a rewrite if a directory 63 | # with the same name does not exist. 64 | # http://httpd.apache.org/docs/current/content-negotiation.html#multiviews 65 | # http://www.webmasterworld.com/apache/3808792.htm 66 | 67 | Options -MultiViews 68 | 69 | # ------------------------------------------------------------------------------ 70 | # | Custom error messages / pages | 71 | # ------------------------------------------------------------------------------ 72 | 73 | # You can customize what Apache returns to the client in case of an error (see 74 | # http://httpd.apache.org/docs/current/mod/core.html#errordocument), e.g.: 75 | 76 | ErrorDocument 404 /404.html 77 | 78 | 79 | # ############################################################################## 80 | # # INTERNET EXPLORER # 81 | # ############################################################################## 82 | 83 | # ------------------------------------------------------------------------------ 84 | # | Better website experience | 85 | # ------------------------------------------------------------------------------ 86 | 87 | # Force IE to render pages in the highest available mode in the various 88 | # cases when it may not: http://hsivonen.iki.fi/doctype/ie-mode.pdf. 89 | 90 | 91 | Header set X-UA-Compatible "IE=edge" 92 | # `mod_headers` can't match based on the content-type, however, we only 93 | # want to send this header for HTML pages and not for the other resources 94 | 95 | Header unset X-UA-Compatible 96 | 97 | 98 | 99 | # ------------------------------------------------------------------------------ 100 | # | Cookie setting from iframes | 101 | # ------------------------------------------------------------------------------ 102 | 103 | # Allow cookies to be set from iframes in IE. 104 | 105 | # 106 | # Header set P3P "policyref=\"/w3c/p3p.xml\", CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\"" 107 | # 108 | 109 | # ------------------------------------------------------------------------------ 110 | # | Screen flicker | 111 | # ------------------------------------------------------------------------------ 112 | 113 | # Stop screen flicker in IE on CSS rollovers (this only works in 114 | # combination with the `ExpiresByType` directives for images from below). 115 | 116 | # BrowserMatch "MSIE" brokenvary=1 117 | # BrowserMatch "Mozilla/4.[0-9]{2}" brokenvary=1 118 | # BrowserMatch "Opera" !brokenvary 119 | # SetEnvIf brokenvary 1 force-no-vary 120 | 121 | 122 | # ############################################################################## 123 | # # MIME TYPES AND ENCODING # 124 | # ############################################################################## 125 | 126 | # ------------------------------------------------------------------------------ 127 | # | Proper MIME types for all files | 128 | # ------------------------------------------------------------------------------ 129 | 130 | 131 | 132 | # Audio 133 | AddType audio/mp4 m4a f4a f4b 134 | AddType audio/ogg oga ogg 135 | 136 | # JavaScript 137 | # Normalize to standard type (it's sniffed in IE anyways): 138 | # http://tools.ietf.org/html/rfc4329#section-7.2 139 | AddType application/javascript js jsonp 140 | AddType application/json json 141 | 142 | # Video 143 | AddType video/mp4 mp4 m4v f4v f4p 144 | AddType video/ogg ogv 145 | AddType video/webm webm 146 | AddType video/x-flv flv 147 | 148 | # Web fonts 149 | AddType application/font-woff woff 150 | AddType application/vnd.ms-fontobject eot 151 | 152 | # Browsers usually ignore the font MIME types and sniff the content, 153 | # however, Chrome shows a warning if other MIME types are used for the 154 | # following fonts. 155 | AddType application/x-font-ttf ttc ttf 156 | AddType font/opentype otf 157 | 158 | # Make SVGZ fonts work on iPad: 159 | # https://twitter.com/FontSquirrel/status/14855840545 160 | AddType image/svg+xml svg svgz 161 | AddEncoding gzip svgz 162 | 163 | # Other 164 | AddType application/octet-stream safariextz 165 | AddType application/x-chrome-extension crx 166 | AddType application/x-opera-extension oex 167 | AddType application/x-shockwave-flash swf 168 | AddType application/x-web-app-manifest+json webapp 169 | AddType application/x-xpinstall xpi 170 | AddType application/xml atom rdf rss xml 171 | AddType image/webp webp 172 | AddType image/x-icon ico 173 | AddType text/cache-manifest appcache manifest 174 | AddType text/vtt vtt 175 | AddType text/x-component htc 176 | AddType text/x-vcard vcf 177 | 178 | 179 | 180 | # ------------------------------------------------------------------------------ 181 | # | UTF-8 encoding | 182 | # ------------------------------------------------------------------------------ 183 | 184 | # Use UTF-8 encoding for anything served as `text/html` or `text/plain`. 185 | AddDefaultCharset utf-8 186 | 187 | # Force UTF-8 for certain file formats. 188 | 189 | AddCharset utf-8 .atom .css .js .json .rss .vtt .webapp .xml 190 | 191 | 192 | 193 | # ############################################################################## 194 | # # URL REWRITES # 195 | # ############################################################################## 196 | 197 | # ------------------------------------------------------------------------------ 198 | # | Rewrite engine | 199 | # ------------------------------------------------------------------------------ 200 | 201 | # Turning on the rewrite engine and enabling the `FollowSymLinks` option is 202 | # necessary for the following directives to work. 203 | 204 | # If your web host doesn't allow the `FollowSymlinks` option, you may need to 205 | # comment it out and use `Options +SymLinksIfOwnerMatch` but, be aware of the 206 | # performance impact: http://httpd.apache.org/docs/current/misc/perf-tuning.html#symlinks 207 | 208 | # Also, some cloud hosting services require `RewriteBase` to be set: 209 | # http://www.rackspace.com/knowledge_center/frequently-asked-question/why-is-mod-rewrite-not-working-on-my-site 210 | 211 | 212 | Options +FollowSymlinks 213 | # Options +SymLinksIfOwnerMatch 214 | RewriteEngine On 215 | # RewriteBase / 216 | 217 | 218 | # ------------------------------------------------------------------------------ 219 | # | Suppressing / Forcing the "www." at the beginning of URLs | 220 | # ------------------------------------------------------------------------------ 221 | 222 | # The same content should never be available under two different URLs especially 223 | # not with and without "www." at the beginning. This can cause SEO problems 224 | # (duplicate content), therefore, you should choose one of the alternatives and 225 | # redirect the other one. 226 | 227 | # By default option 1 (no "www.") is activated: 228 | # http://no-www.org/faq.php?q=class_b 229 | 230 | # If you'd prefer to use option 2, just comment out all the lines from option 1 231 | # and uncomment the ones from option 2. 232 | 233 | # IMPORTANT: NEVER USE BOTH RULES AT THE SAME TIME! 234 | 235 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 236 | 237 | # Option 1: rewrite www.example.com → example.com 238 | 239 | 240 | RewriteCond %{HTTPS} !=on 241 | RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] 242 | RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L] 243 | 244 | 245 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 246 | 247 | # Option 2: rewrite example.com → www.example.com 248 | 249 | # Be aware that the following might not be a good idea if you use "real" 250 | # subdomains for certain parts of your website. 251 | 252 | # 253 | # RewriteCond %{HTTPS} !=on 254 | # RewriteCond %{HTTP_HOST} !^www\..+$ [NC] 255 | # RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L] 256 | # 257 | 258 | 259 | # ############################################################################## 260 | # # SECURITY # 261 | # ############################################################################## 262 | 263 | # ------------------------------------------------------------------------------ 264 | # | Content Security Policy (CSP) | 265 | # ------------------------------------------------------------------------------ 266 | 267 | # You can mitigate the risk of cross-site scripting and other content-injection 268 | # attacks by setting a Content Security Policy which whitelists trusted sources 269 | # of content for your site. 270 | 271 | # The example header below allows ONLY scripts that are loaded from the current 272 | # site's origin (no inline scripts, no CDN, etc). This almost certainly won't 273 | # work as-is for your site! 274 | 275 | # To get all the details you'll need to craft a reasonable policy for your site, 276 | # read: http://html5rocks.com/en/tutorials/security/content-security-policy (or 277 | # see the specification: http://w3.org/TR/CSP). 278 | 279 | # 280 | # Header set Content-Security-Policy "script-src 'self'; object-src 'self'" 281 | # 282 | # Header unset Content-Security-Policy 283 | # 284 | # 285 | 286 | # ------------------------------------------------------------------------------ 287 | # | File access | 288 | # ------------------------------------------------------------------------------ 289 | 290 | # Block access to directories without a default document. 291 | # Usually you should leave this uncommented because you shouldn't allow anyone 292 | # to surf through every directory on your server (which may includes rather 293 | # private places like the CMS's directories). 294 | 295 | 296 | Options -Indexes 297 | 298 | 299 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 300 | 301 | # Block access to hidden files and directories. 302 | # This includes directories used by version control systems such as Git and SVN. 303 | 304 | 305 | RewriteCond %{SCRIPT_FILENAME} -d [OR] 306 | RewriteCond %{SCRIPT_FILENAME} -f 307 | RewriteRule "(^|/)\." - [F] 308 | 309 | 310 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 311 | 312 | # Block access to backup and source files. 313 | # These files may be left by some text editors and can pose a great security 314 | # danger when anyone has access to them. 315 | 316 | 317 | Order allow,deny 318 | Deny from all 319 | Satisfy All 320 | 321 | 322 | # ------------------------------------------------------------------------------ 323 | # | Secure Sockets Layer (SSL) | 324 | # ------------------------------------------------------------------------------ 325 | 326 | # Rewrite secure requests properly to prevent SSL certificate warnings, e.g.: 327 | # prevent `https://www.example.com` when your certificate only allows 328 | # `https://secure.example.com`. 329 | 330 | # 331 | # RewriteCond %{SERVER_PORT} !^443 332 | # RewriteRule ^ https://example-domain-please-change-me.com%{REQUEST_URI} [R=301,L] 333 | # 334 | 335 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 336 | 337 | # Force client-side SSL redirection. 338 | 339 | # If a user types "example.com" in his browser, the above rule will redirect him 340 | # to the secure version of the site. That still leaves a window of opportunity 341 | # (the initial HTTP connection) for an attacker to downgrade or redirect the 342 | # request. The following header ensures that browser will ONLY connect to your 343 | # server via HTTPS, regardless of what the users type in the address bar. 344 | # http://www.html5rocks.com/en/tutorials/security/transport-layer-security/ 345 | 346 | # 347 | # Header set Strict-Transport-Security max-age=16070400; 348 | # 349 | 350 | # ------------------------------------------------------------------------------ 351 | # | Server software information | 352 | # ------------------------------------------------------------------------------ 353 | 354 | # Avoid displaying the exact Apache version number, the description of the 355 | # generic OS-type and the information about Apache's compiled-in modules. 356 | 357 | # ADD THIS DIRECTIVE IN THE `httpd.conf` AS IT WILL NOT WORK IN THE `.htaccess`! 358 | 359 | # ServerTokens Prod 360 | 361 | 362 | # ############################################################################## 363 | # # WEB PERFORMANCE # 364 | # ############################################################################## 365 | 366 | # ------------------------------------------------------------------------------ 367 | # | Compression | 368 | # ------------------------------------------------------------------------------ 369 | 370 | 371 | 372 | # Force compression for mangled headers. 373 | # http://developer.yahoo.com/blogs/ydn/posts/2010/12/pushing-beyond-gzipping 374 | 375 | 376 | SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding 377 | RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding 378 | 379 | 380 | 381 | # Compress all output labeled with one of the following MIME-types 382 | # (for Apache versions below 2.3.7, you don't need to enable `mod_filter` 383 | # and can remove the `` and `` lines 384 | # as `AddOutputFilterByType` is still in the core directives). 385 | 386 | AddOutputFilterByType DEFLATE application/atom+xml \ 387 | application/javascript \ 388 | application/json \ 389 | application/rss+xml \ 390 | application/vnd.ms-fontobject \ 391 | application/x-font-ttf \ 392 | application/x-web-app-manifest+json \ 393 | application/xhtml+xml \ 394 | application/xml \ 395 | font/opentype \ 396 | image/svg+xml \ 397 | image/x-icon \ 398 | text/css \ 399 | text/html \ 400 | text/plain \ 401 | text/x-component \ 402 | text/xml 403 | 404 | 405 | 406 | 407 | # ------------------------------------------------------------------------------ 408 | # | Content transformations | 409 | # ------------------------------------------------------------------------------ 410 | 411 | # Prevent some of the mobile network providers from modifying the content of 412 | # your site: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.5. 413 | 414 | # 415 | # Header set Cache-Control "no-transform" 416 | # 417 | 418 | # ------------------------------------------------------------------------------ 419 | # | ETag removal | 420 | # ------------------------------------------------------------------------------ 421 | 422 | # Since we're sending far-future expires headers (see below), ETags can 423 | # be removed: http://developer.yahoo.com/performance/rules.html#etags. 424 | 425 | # `FileETag None` is not enough for every server. 426 | 427 | Header unset ETag 428 | 429 | 430 | FileETag None 431 | 432 | # ------------------------------------------------------------------------------ 433 | # | Expires headers (for better cache control) | 434 | # ------------------------------------------------------------------------------ 435 | 436 | # The following expires headers are set pretty far in the future. If you don't 437 | # control versioning with filename-based cache busting, consider lowering the 438 | # cache time for resources like CSS and JS to something like 1 week. 439 | 440 | 441 | 442 | ExpiresActive on 443 | ExpiresDefault "access plus 1 month" 444 | 445 | # CSS 446 | ExpiresByType text/css "access plus 1 year" 447 | 448 | # Data interchange 449 | ExpiresByType application/json "access plus 0 seconds" 450 | ExpiresByType application/xml "access plus 0 seconds" 451 | ExpiresByType text/xml "access plus 0 seconds" 452 | 453 | # Favicon (cannot be renamed!) 454 | ExpiresByType image/x-icon "access plus 1 week" 455 | 456 | # HTML components (HTCs) 457 | ExpiresByType text/x-component "access plus 1 month" 458 | 459 | # HTML 460 | ExpiresByType text/html "access plus 0 seconds" 461 | 462 | # JavaScript 463 | ExpiresByType application/javascript "access plus 1 year" 464 | 465 | # Manifest files 466 | ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds" 467 | ExpiresByType text/cache-manifest "access plus 0 seconds" 468 | 469 | # Media 470 | ExpiresByType audio/ogg "access plus 1 month" 471 | ExpiresByType image/gif "access plus 1 month" 472 | ExpiresByType image/jpeg "access plus 1 month" 473 | ExpiresByType image/png "access plus 1 month" 474 | ExpiresByType video/mp4 "access plus 1 month" 475 | ExpiresByType video/ogg "access plus 1 month" 476 | ExpiresByType video/webm "access plus 1 month" 477 | 478 | # Web feeds 479 | ExpiresByType application/atom+xml "access plus 1 hour" 480 | ExpiresByType application/rss+xml "access plus 1 hour" 481 | 482 | # Web fonts 483 | ExpiresByType application/font-woff "access plus 1 month" 484 | ExpiresByType application/vnd.ms-fontobject "access plus 1 month" 485 | ExpiresByType application/x-font-ttf "access plus 1 month" 486 | ExpiresByType font/opentype "access plus 1 month" 487 | ExpiresByType image/svg+xml "access plus 1 month" 488 | 489 | 490 | 491 | # ------------------------------------------------------------------------------ 492 | # | Filename-based cache busting | 493 | # ------------------------------------------------------------------------------ 494 | 495 | # If you're not using a build process to manage your filename version revving, 496 | # you might want to consider enabling the following directives to route all 497 | # requests such as `/css/style.12345.css` to `/css/style.css`. 498 | 499 | # To understand why this is important and a better idea than `*.css?v231`, read: 500 | # http://stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring 501 | 502 | # 503 | # RewriteCond %{REQUEST_FILENAME} !-f 504 | # RewriteCond %{REQUEST_FILENAME} !-d 505 | # RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpg|gif)$ $1.$3 [L] 506 | # 507 | 508 | # ------------------------------------------------------------------------------ 509 | # | File concatenation | 510 | # ------------------------------------------------------------------------------ 511 | 512 | # Allow concatenation from within specific CSS and JS files, e.g.: 513 | # Inside of `script.combined.js` you could have 514 | # 515 | # 516 | # and they would be included into this single file. 517 | 518 | # 519 | # 520 | # Options +Includes 521 | # AddOutputFilterByType INCLUDES application/javascript application/json 522 | # SetOutputFilter INCLUDES 523 | # 524 | # 525 | # Options +Includes 526 | # AddOutputFilterByType INCLUDES text/css 527 | # SetOutputFilter INCLUDES 528 | # 529 | # 530 | 531 | # ------------------------------------------------------------------------------ 532 | # | Persistent connections | 533 | # ------------------------------------------------------------------------------ 534 | 535 | # Allow multiple requests to be sent over the same TCP connection: 536 | # http://httpd.apache.org/docs/current/en/mod/core.html#keepalive. 537 | 538 | # Enable if you serve a lot of static content but, be aware of the 539 | # possible disadvantages! 540 | 541 | # 542 | # Header set Connection Keep-Alive 543 | # 544 | -------------------------------------------------------------------------------- /app/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page Not Found :( 6 | 136 | 137 | 138 |
139 |

Not found :(

140 |

Sorry, but the page you were trying to view does not exist.

141 |

It looks like this was the result of either:

142 | 146 | 149 | 150 |
151 | 152 | 153 | -------------------------------------------------------------------------------- /app/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "modules": [ 3 | {"id": "1" , "name": "ngAnimate"}, 4 | {"id": "2" , "name": "ngCookies"}, 5 | {"id": "3" , "name": "ngResource"} 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /app/angular2.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"id": "1" , "name": "ngAnimate"}, 3 | {"id": "2" , "name": "ngCookies"}, 4 | {"id": "3" , "name": "ngResource"} 5 | ] 6 | 7 | -------------------------------------------------------------------------------- /app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinChavez/AngularJS-Advanced-Topics/321b00f08770d1279fbfda29c57437d7b2fd5945/app/favicon.ico -------------------------------------------------------------------------------- /app/images/yeoman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinChavez/AngularJS-Advanced-Topics/321b00f08770d1279fbfda29c57437d7b2fd5945/app/images/yeoman.png -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AngularJS: Advanced Topics 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 26 | 27 | 28 |
29 | 53 |
54 | 55 | 56 | 57 |
58 |
59 |
60 | 61 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /app/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org 2 | 3 | User-agent: * 4 | Disallow: 5 | -------------------------------------------------------------------------------- /app/scripts/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular 4 | .module('advancedTopicsApp', [ 5 | 'ngAnimate', 6 | 'ngCookies', 7 | 'ngResource', 8 | //Once you included ngRoute in the index.html (as a script reference), 9 | //the whole application has access to this service. 10 | //You can then use ngRoute as a dependency 11 | 'ngRoute', 12 | 'ngSanitize', 13 | 'ngTouch' 14 | ]).config(function (Gravatar2Provider){ 15 | 16 | Gravatar2Provider.setSize(150); 17 | }); 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/scripts/controllers/directives.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('advancedTopicsApp') 4 | .controller('DirectivesCtrl', function () { 5 | 6 | /*The filter Filter*/ 7 | //Selects a subset of items from an array and returns it as a new array 8 | // | filter:"a" 9 | // | filter: {category: {name: 'query'}} 10 | 11 | }); 12 | -------------------------------------------------------------------------------- /app/scripts/controllers/module.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('advancedTopicsApp') 4 | .controller('ModuleCtrl', function ($http, $routeParams) { 5 | var controller = this; 6 | 7 | if($routeParams.id == 1){ 8 | controller.module = { name: "ngAnimate"} 9 | } 10 | if($routeParams.id == 2){ 11 | controller.module = { name: "ngCookies"} 12 | } 13 | if($routeParams.id == 3){ 14 | controller.module = { name: "ngResource"} 15 | } 16 | }); 17 | -------------------------------------------------------------------------------- /app/scripts/controllers/organization.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('advancedTopicsApp') 4 | .controller('OrganizationCtrl', function ($http) { 5 | 6 | //It is a good practice to assign 'this' to a variable in order to use 'this' keyword inside the callback 7 | var controller = this; 8 | $http({method:'GET', url: 'angular.json'}).success(function(data){ 9 | controller.modules = data.modules; 10 | }); 11 | 12 | //You can create functions that will be utilized by forms 13 | this.create = function(module){ 14 | 15 | } 16 | 17 | }); 18 | -------------------------------------------------------------------------------- /app/scripts/controllers/service.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('advancedTopicsApp') 4 | .controller('ServiceCtrl', function ($scope,$http, Module, Gravatar, Gravatar2) { 5 | 6 | var controller = $scope; 7 | controller.user = { 8 | email: "martin.chavez@live.com" 9 | }; 10 | 11 | //Module.all().success(function(data){ 12 | // console.log(data); 13 | // controller.modules = data.modules; 14 | // }); 15 | 16 | //To fetch all of the items, you can use the query method 17 | controller.modules = Module.query(); 18 | 19 | //To delete 20 | //controller.modules = Module.$delete(module); 21 | 22 | //To get a single resource 23 | //Module.get({id:2}); 24 | 25 | //To create a new resource 26 | //Module.save({id:2}) 27 | 28 | controller.gravatarUrl = Gravatar(controller.user.email); 29 | controller.gravatarUrl2 = Gravatar2(controller.user.email); 30 | 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /app/scripts/directives/directive-example.js: -------------------------------------------------------------------------------- 1 | angular.module("advancedTopicsApp") 2 | .directive("directiveExample", function (Module) { 3 | 4 | return { 5 | replace: true, 6 | restrict: "E", 7 | templateUrl: "views/directive-example.html", 8 | link: function(scope, element, attrs){ 9 | console.log(Module.query()); 10 | scope.innerDirectives = Module.query(); 11 | }, 12 | controller: function($scope){ 13 | this.setActive = function(innerDirective){ 14 | $scope.active = innerDirective.active; 15 | } 16 | 17 | this.getActive = function(){ 18 | return $scope.active; 19 | } 20 | } 21 | }; 22 | }); 23 | -------------------------------------------------------------------------------- /app/scripts/directives/inner-directive.js: -------------------------------------------------------------------------------- 1 | angular.module("advancedTopicsApp") 2 | .directive("innerDirective", function () { 3 | 4 | return { 5 | restrict: "E", 6 | templateUrl: "views/inner-directive.html", 7 | scope:{ 8 | innerDirective:"=" 9 | }, 10 | /*Require directive*/ 11 | //It allows to share a controller between directives 12 | // ^ indicates that you are looking for a parent directive 13 | require:"^directiveExample", 14 | 15 | /*Link's 4th parameter*/ 16 | //The required directive's controller is passed in as link's 4th parameter and can have any name 17 | link: function(scope,element,attrs,DirectivesCtrl){ 18 | 19 | scope.makeActive = function(){ 20 | DirectivesCtrl.setActive(scope.innerDirective); 21 | } 22 | 23 | scope.innerDirectiveActive = function (){ 24 | return DirectivesCtrl.getActive() === scope.innerDirective.name; 25 | 26 | } 27 | } 28 | }; 29 | }); 30 | -------------------------------------------------------------------------------- /app/scripts/directives/module.js: -------------------------------------------------------------------------------- 1 | /*Directives*/ 2 | //Directives Inherit their parent's scope by default 3 | angular.module("advancedTopicsApp") 4 | .directive("module", function () { 5 | 6 | /* $scope */ 7 | return { 8 | restrict: "E", 9 | templateUrl: "views/a-module.html", 10 | //Isolating the Scope 11 | 12 | //By passing an object to the scope option, you create an isolated scope. 13 | //This tells the directive to keep scope inside itself and not to inherit or share with others 14 | scope: { 15 | //You can pass as many bindings as you need 16 | 17 | //title:"@" passes in a string 18 | title: "=", // '=' is a two-way binding, 19 | id: "=" 20 | }, 21 | //There are three options when binding data to an isolated scope: @,= and & characters 22 | 23 | /*Link*/ 24 | //The link function is run after the directive has been compiled and linked up 25 | //This is the best place to do any DOM manipulation or logic functionality 26 | 27 | //element: refers to the outermost element of the directive 28 | //attrs stands for attributes 29 | link: function (scope, element, attrs) { 30 | element.on("click", function () { 31 | element("div.module p").toggleClass("hidden"); 32 | }); 33 | 34 | } 35 | // By using the $scope variable, you can avoid using alias by binding the local variables to $scope 36 | //This is very helpful in the views, since you don't need to reference any controller 37 | 38 | }; 39 | 40 | /*Important: Difference between $scope and Scope Object*/ 41 | 42 | //The scope object is used to isolate a directive's scope 43 | //$scope is used to set values and functions on the scope 44 | }); 45 | -------------------------------------------------------------------------------- /app/scripts/providers/gravatar2.js: -------------------------------------------------------------------------------- 1 | /*Provider Service Recipe*/ 2 | //It allows more configuration than a factory 3 | 4 | //Providers run before everything else,so the only thing you can inject to them is other providers 5 | angular.module("advancedTopicsApp").provider("Gravatar2", function Gravatar2Provider() { 6 | 7 | var avatarSize = 80; //Default size 8 | var avatarUrl = "http://www.gravatar.com/avatar/"; 9 | 10 | this.setSize = function(size){ 11 | avatarSize = size; 12 | }; 13 | 14 | 15 | //The $get function is where you return an object and inject services 16 | this.$get = function() { 17 | return function(email) { 18 | return avatarUrl + CryptoJS.MD5(email) + "?size=" + avatarSize.toString(); 19 | }; 20 | }; 21 | 22 | }); 23 | -------------------------------------------------------------------------------- /app/scripts/routes.js: -------------------------------------------------------------------------------- 1 | /* Routes*/ 2 | //Angular routes allow us to map URLs to use templates so that every time the current route changes, 3 | //the included view changes with it 4 | 5 | /* $routeProvider*/ 6 | //$routeProvider allows you to specify Routes in the Angular application 7 | 8 | //It is a good practice to re-declare your application module in every new file 9 | angular.module('advancedTopicsApp').config(function ($routeProvider) { 10 | 11 | //Inside module.config, we can use one of $routeProvider's methods to define routes 12 | 13 | /* .when (path, route)*/ 14 | //Adds a new route definition to the $route service 15 | 16 | /* .otherwise (params)*/ 17 | //Sets route definition that will be used on route change when no other route definition is matched 18 | 19 | //You only need to define $routeProvider once and use method chaining 20 | $routeProvider 21 | .when('/', { 22 | /* Routing Components*/ 23 | //It is possible to associate routes with templates and controllers 24 | templateUrl: 'views/organization.html', 25 | //It is a good practice to link to an already existing controller 26 | controller: 'OrganizationCtrl', 27 | //You can use 'controllerAs' to assign an alias to this controller 28 | controllerAs: 'organization' 29 | }) 30 | .when('/service', { 31 | templateUrl: 'views/service.html', 32 | controller: 'ServiceCtrl', 33 | controllerAs: 'service' 34 | }) 35 | .when('/directives', { 36 | templateUrl: 'views/directives.html', 37 | controller: 'DirectivesCtrl', 38 | controllerAs: 'directives' 39 | }) 40 | //Declaring routes based on Id's 41 | //By passing in $routeParams we can obtain identifiers and utilize them 42 | .when('/module/:id', { 43 | templateUrl: 'views/module.html', 44 | controller: 'ModuleCtrl', 45 | controllerAs: 'module' 46 | }) 47 | .otherwise({ 48 | redirectTo: '/' 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /app/scripts/services/gravatar.js: -------------------------------------------------------------------------------- 1 | 2 | //Service Factory 3 | angular.module("advancedTopicsApp").factory("Gravatar", function GravatarFactory() { 4 | 5 | var avatarSize = 80; //Default size 6 | var avatarUrl = "http://www.gravatar.com/avatar/"; 7 | 8 | 9 | return function(email){ 10 | return avatarUrl + CryptoJS.MD5(email) + "?size=" + avatarSize.toString(); 11 | }; 12 | 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /app/scripts/services/module.js: -------------------------------------------------------------------------------- 1 | /* Services*/ 2 | //Services should hold functions responsible for connecting and fetching data, then sharing it across our application 3 | 4 | //Service Factory 5 | //This a naming convention 6 | angular.module("advancedTopicsApp").factory("Module",function ModuleFactory($http, $resource){ 7 | 8 | 9 | //By using $resource you implement all the required methods for CRUD 10 | return $resource("angular2.json",{},{ 11 | update:{ 12 | method:"PUT" 13 | } 14 | 15 | }); 16 | 17 | /* Old code 18 | return { 19 | all: function() { 20 | return $http({method: 'GET', url: 'angular.json'}); 21 | }, 22 | create:function(module) { 23 | return $http({method: 'POST', url: 'angular.json', data: module}); 24 | 25 | } 26 | } 27 | */ 28 | }); 29 | -------------------------------------------------------------------------------- /app/styles/main.css: -------------------------------------------------------------------------------- 1 | .browsehappy { 2 | margin: 0.2em 0; 3 | background: #ccc; 4 | color: #000; 5 | padding: 0.2em 0; 6 | } 7 | 8 | body { 9 | padding: 0; 10 | } 11 | 12 | /* Everything but the jumbotron gets side spacing for mobile first views */ 13 | .header, 14 | .marketing, 15 | .footer { 16 | padding-left: 15px; 17 | padding-right: 15px; 18 | } 19 | 20 | /* Custom page header */ 21 | .header { 22 | border-bottom: 1px solid #e5e5e5; 23 | margin-bottom: 10px; 24 | } 25 | /* Make the masthead heading the same height as the navigation */ 26 | .header h3 { 27 | margin-top: 0; 28 | margin-bottom: 0; 29 | line-height: 40px; 30 | padding-bottom: 19px; 31 | } 32 | 33 | /* Custom page footer */ 34 | .footer { 35 | padding-top: 19px; 36 | color: #777; 37 | border-top: 1px solid #e5e5e5; 38 | } 39 | 40 | .container-narrow > hr { 41 | margin: 30px 0; 42 | } 43 | 44 | /* Main marketing message and sign up button */ 45 | .jumbotron { 46 | text-align: center; 47 | border-bottom: 1px solid #e5e5e5; 48 | } 49 | .jumbotron .btn { 50 | font-size: 21px; 51 | padding: 14px 24px; 52 | } 53 | 54 | /* Supporting marketing content */ 55 | .marketing { 56 | margin: 40px 0; 57 | } 58 | .marketing p + h4 { 59 | margin-top: 28px; 60 | } 61 | 62 | /* Responsive: Portrait tablets and up */ 63 | @media screen and (min-width: 768px) { 64 | .container { 65 | max-width: 730px; 66 | } 67 | 68 | /* Remove the padding we set earlier */ 69 | .header, 70 | .marketing, 71 | .footer { 72 | padding-left: 0; 73 | padding-right: 0; 74 | } 75 | /* Space out the masthead */ 76 | .header { 77 | margin-bottom: 30px; 78 | } 79 | /* Remove the bottom border on the jumbotron for visual effect */ 80 | .jumbotron { 81 | border-bottom: 0; 82 | } 83 | } 84 | 85 | .module{ 86 | position: relative; 87 | } 88 | 89 | module p.hidden{ 90 | display: none; 91 | } 92 | -------------------------------------------------------------------------------- /app/views/a-module.html: -------------------------------------------------------------------------------- 1 |
2 | {{title}} 3 | 4 |
5 | -------------------------------------------------------------------------------- /app/views/directive-example.html: -------------------------------------------------------------------------------- 1 |
2 |

Outer Directive

3 | {{innerDirectives}} 4 | 5 | 6 | 7 |
8 | -------------------------------------------------------------------------------- /app/views/directives.html: -------------------------------------------------------------------------------- 1 |
2 |

Directives

3 | 4 |

5 | 6 |

7 |
8 | 9 |
10 |

Directives

11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | -------------------------------------------------------------------------------- /app/views/inner-directive.html: -------------------------------------------------------------------------------- 1 |
2 |

Inner directive

3 |

{{innerDirective.name}}

4 |

{{name}}

5 |
6 | -------------------------------------------------------------------------------- /app/views/module.html: -------------------------------------------------------------------------------- 1 |
2 |

Modules

3 | {{module.module}} 4 |

5 | {{module.module.name}} 6 |

7 |
8 | 9 |
10 | {{module.module.name}} 11 |
12 | -------------------------------------------------------------------------------- /app/views/organization.html: -------------------------------------------------------------------------------- 1 |
2 |

Organization of files

3 | 4 |

5 | It is a good practice to separate controllers, services, filters and directives into individual directories. 6 |

7 |
8 | 9 |
10 |

Controllers

11 | 14 | 15 |

Views

16 | 22 | 23 |

Index file

24 | 27 |

Routes

28 | 48 |

$http service

49 | 57 |
58 | -------------------------------------------------------------------------------- /app/views/service.html: -------------------------------------------------------------------------------- 1 |
2 |

Services

3 | 4 |

5 | Services should hold functions responsible for connecting and fetching data, then sharing it across our application 6 |

7 |
8 | 9 | 10 |
11 |

Service Recipes

12 | 16 |

Factory service

17 | 24 | 25 | 26 | 27 | {{user.email}} 28 | 29 | 30 | 31 | 32 | {{user.email}} 33 | 34 |
35 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "advanced-topics", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "angular": "^1.3.0", 6 | "bootstrap": "^3.2.0", 7 | "angular-animate": "^1.3.0", 8 | "angular-cookies": "^1.3.0", 9 | "angular-resource": "^1.3.0", 10 | "angular-route": "^1.3.0", 11 | "angular-sanitize": "^1.3.0", 12 | "angular-touch": "^1.3.0" 13 | }, 14 | "devDependencies": { 15 | "angular-mocks": "^1.3.0" 16 | }, 17 | "appPath": "app", 18 | "moduleName": "advancedTopicsApp", 19 | "overrides": { 20 | "bootstrap": { 21 | "main": [ 22 | "less/bootstrap.less", 23 | "dist/css/bootstrap.css", 24 | "dist/js/bootstrap.js" 25 | ] 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "advancedtopics", 3 | "private": true, 4 | "devDependencies": { 5 | "grunt": "^0.4.5", 6 | "grunt-angular-templates": "^0.5.7", 7 | "grunt-autoprefixer": "^2.0.0", 8 | "grunt-concurrent": "^1.0.0", 9 | "grunt-contrib-clean": "^0.6.0", 10 | "grunt-contrib-concat": "^0.5.0", 11 | "grunt-contrib-connect": "^0.9.0", 12 | "grunt-contrib-copy": "^0.7.0", 13 | "grunt-contrib-cssmin": "^0.12.0", 14 | "grunt-contrib-htmlmin": "^0.4.0", 15 | "grunt-contrib-imagemin": "^0.9.2", 16 | "grunt-contrib-jshint": "^0.11.0", 17 | "grunt-contrib-uglify": "^0.7.0", 18 | "grunt-contrib-watch": "^0.6.1", 19 | "grunt-filerev": "^2.1.2", 20 | "grunt-google-cdn": "^0.4.3", 21 | "grunt-karma": "*", 22 | "grunt-newer": "^1.1.0", 23 | "grunt-ng-annotate": "^0.9.2", 24 | "grunt-svgmin": "^2.0.0", 25 | "grunt-usemin": "^3.0.0", 26 | "grunt-wiredep": "^2.0.0", 27 | "jit-grunt": "^0.9.1", 28 | "jshint-stylish": "^1.0.0", 29 | "karma-jasmine": "*", 30 | "karma-phantomjs-launcher": "*", 31 | "time-grunt": "^1.0.0" 32 | }, 33 | "engines": { 34 | "node": ">=0.10.0" 35 | }, 36 | "scripts": { 37 | "test": "grunt test" 38 | } 39 | } 40 | --------------------------------------------------------------------------------