├── dist └── .gitkeep ├── tests ├── output │ └── .gitkeep ├── unit │ ├── filter │ │ ├── filter.controller.spec.js │ │ └── filter.filter.spec.js │ ├── service │ │ ├── service.controller.spec.js │ │ └── service.service.spec.js │ ├── directives │ │ └── directives.controller.directive.spec.js │ ├── controller │ │ └── service.controller.spec.js │ └── promise │ │ ├── promise.service.spec.js │ │ └── promise.controller.spec.js └── e2e │ ├── home.spec.js │ ├── examples │ ├── view.spec.js │ ├── error.spec.js │ ├── controller.spec.js │ ├── filter.spec.js │ ├── directives.spec.js │ ├── promise.spec.js │ └── service.spec.js │ └── core.spec.js ├── server ├── routes.js └── server.js ├── app ├── images │ └── favicon.ico ├── examples │ ├── directives │ │ ├── directives.simple.directive.tpl.html │ │ ├── directives.module.js │ │ ├── directives.controller.directive.tpl.html │ │ ├── directives.simple.directive.js │ │ ├── directives.route.js │ │ ├── directives.controller.directive.js │ │ └── directives.tpl.html │ ├── view │ │ ├── view.module.js │ │ ├── view.tpl.html │ │ └── view.route.js │ ├── error │ │ ├── error.module.js │ │ ├── error.tpl.html │ │ └── error.route.js │ ├── filter │ │ ├── filter.module.js │ │ ├── filter.filter.js │ │ ├── filter.controller.js │ │ ├── filter.route.js │ │ └── filter.tpl.html │ ├── promise │ │ ├── promise.module.js │ │ ├── promise.service.js │ │ ├── promise.route.js │ │ ├── promise.tpl.html │ │ └── promise.controller.js │ ├── service │ │ ├── service.module.js │ │ ├── service.controller.js │ │ ├── service.service.js │ │ ├── service.route.js │ │ └── service.tpl.html │ └── controller │ │ ├── controller.module.js │ │ ├── controller.tpl.html │ │ ├── controller.route.js │ │ └── controller.controller.js ├── home │ ├── home.module.js │ ├── home.route.js │ └── home.tpl.html ├── core │ ├── core.module.js │ └── core.nav.controller.js ├── styles │ └── style.css ├── app.js └── index.html ├── gulpfile.js ├── .gitignore ├── protractor.conf.js ├── .jshintrc ├── bower.json ├── package.json ├── karma.conf.js └── README.md /dist/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/output/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/routes.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | 3 | }; 4 | -------------------------------------------------------------------------------- /app/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkern/angular-best-practice/HEAD/app/images/favicon.ico -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | // all gulp tasks are located in the ./build/tasks directory 2 | // gulp configuration is in files in ./build/config directory 3 | require("require-dir")("build/tasks"); 4 | -------------------------------------------------------------------------------- /app/examples/directives/directives.simple.directive.tpl.html: -------------------------------------------------------------------------------- 1 |
2 |

This is the output of <simple-directive></simple-directive>.

3 |
4 | -------------------------------------------------------------------------------- /app/home/home.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; 3 | angular.module("practice.home", [ 4 | // every module has 'practice.core' as dependency 5 | "practice.core" 6 | ]); 7 | })(); 8 | -------------------------------------------------------------------------------- /app/examples/view/view.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; 3 | angular.module("practice.view", [ 4 | // every module has 'practice.core' as dependency 5 | "practice.core" 6 | ]); 7 | })(); 8 | -------------------------------------------------------------------------------- /app/examples/error/error.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; 3 | angular.module("practice.error", [ 4 | // every module has 'practice.core' as dependency 5 | "practice.core" 6 | ]); 7 | })(); 8 | -------------------------------------------------------------------------------- /app/examples/filter/filter.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; 3 | angular.module("practice.filter", [ 4 | // every module has 'practice.core' as dependency 5 | "practice.core" 6 | ]); 7 | })(); 8 | -------------------------------------------------------------------------------- /app/examples/promise/promise.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; 3 | angular.module("practice.promise", [ 4 | // every module has 'practice.core' as dependency 5 | "practice.core" 6 | ]); 7 | })(); 8 | -------------------------------------------------------------------------------- /app/examples/service/service.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; 3 | angular.module("practice.service", [ 4 | // every module has 'practice.core' as dependency 5 | "practice.core" 6 | ]); 7 | })(); 8 | -------------------------------------------------------------------------------- /app/examples/controller/controller.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; 3 | angular.module("practice.controller", [ 4 | // every module has 'practice.core' as dependency 5 | "practice.core" 6 | ]); 7 | })(); 8 | -------------------------------------------------------------------------------- /app/examples/directives/directives.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; 3 | angular.module("practice.directives", [ 4 | // every module has 'practice.core' as dependency 5 | "practice.core" 6 | ]); 7 | })(); 8 | -------------------------------------------------------------------------------- /app/core/core.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; 3 | angular.module("practice.core", [ 4 | // default dependencies for all other modules 5 | // who got 'practice.core' as dependency goes here 6 | "ui.router" 7 | ]); 8 | })(); 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # temp files, logs & reports 2 | tests/output/karma-result.xml 3 | 4 | # gulp generated distributions 5 | /dist/development 6 | /dist/productive 7 | 8 | # dependencies 9 | node_modules/ 10 | bower_components/ 11 | 12 | # system files 13 | Thumbs.db 14 | .DS_Store 15 | 16 | # ide 17 | .idea 18 | 19 | # psydo standard to track empty directories 20 | !.gitkeep 21 | -------------------------------------------------------------------------------- /protractor.conf.js: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | // address of the selenium server 3 | seleniumAddress: "http://localhost:4444/wd/hub", 4 | 5 | // file pattern to match e2e tests 6 | specs: ["tests/e2e/**/*.spec.js"], 7 | 8 | // base url where angular application is reachable 9 | baseUrl: "http://localhost:1337/", 10 | 11 | // browsers to start by protractor 12 | capabilities: { 13 | 'browserName': 'chrome' 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /app/styles/style.css: -------------------------------------------------------------------------------- 1 | html * { outline: none !important; } 2 | h1 { margin-bottom: 25px; } 3 | ul { margin-bottom: 0; } 4 | section.content { padding-top: 65px; } 5 | footer { margin-top: -15px; font-size: .9em; } 6 | .panel-body h2 { margin-top: 40px; } 7 | .panel-body h2:first-of-type { margin-top: 0; } 8 | .panel-body ul { list-style: square inside; padding: 0; } 9 | -------------------------------------------------------------------------------- /tests/unit/filter/filter.controller.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | describe("when using filter controller", function() 4 | { 5 | var controller; 6 | 7 | beforeEach(module("practice.filter")); 8 | beforeEach(inject(function($controller) { 9 | controller = $controller("practice.filterController"); 10 | })); 11 | 12 | it("should have at least one text entry", function() { 13 | expect(controller.entries.length).toBeGreaterThan(0); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /app/examples/directives/directives.controller.directive.tpl.html: -------------------------------------------------------------------------------- 1 |
2 |

This is the output of <controller-directive exchange="data" format="dd.MM.yyyy"></controller-directive>.

3 |
4 | 5 |
6 |

7 | Formatted current date by given format string: 8 | {{controller.date|date:controller.format}} 9 |

10 |
11 | -------------------------------------------------------------------------------- /tests/e2e/home.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | describe("serving the home page", function() { 4 | beforeEach(function() { 5 | browser.get("#/"); 6 | }); 7 | 8 | it("should have a headline h1", function() { 9 | var h1 = element(by.css("h1")); 10 | expect(h1.getText()).not.toBe(""); 11 | }); 12 | 13 | it("should have at least one content box", function() { 14 | var panel = element.all(by.css(".panel .panel-body")); 15 | expect(panel.count()).toBeGreaterThan(0); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /tests/e2e/examples/view.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | describe("serving the view page", function() { 4 | beforeEach(function() { 5 | browser.get("#/view"); 6 | }); 7 | 8 | it("should have a headline h1", function() { 9 | var h1 = element(by.css("h1")); 10 | expect(h1.getText()).not.toBe(""); 11 | }); 12 | 13 | it("should have at least one content box", function() { 14 | var panel = element.all(by.css(".panel .panel-body")); 15 | expect(panel.count()).toBeGreaterThan(0); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /tests/e2e/examples/error.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | describe("serving the error page", function() { 4 | beforeEach(function() { 5 | browser.get("#/error"); 6 | }); 7 | 8 | it("should have a headline h1", function() { 9 | var h1 = element(by.css("h1")); 10 | expect(h1.getText()).not.toBe(""); 11 | }); 12 | 13 | it("should have at least one content box", function() { 14 | var panel = element.all(by.css(".panel .panel-body")); 15 | expect(panel.count()).toBeGreaterThan(0); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /app/app.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | angular.module("practice", [ 4 | // make every module this app uses available here 5 | 6 | // partials module - configured and generated in gulpfile.js 7 | "practice.partials", 8 | 9 | // home screen module 10 | "practice.home", 11 | 12 | // example modules 13 | "practice.controller", 14 | "practice.directives", 15 | "practice.error", 16 | "practice.filter", 17 | "practice.promise", 18 | "practice.service", 19 | "practice.view" 20 | ]); 21 | }()); 22 | -------------------------------------------------------------------------------- /tests/unit/service/service.controller.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | describe("when using service controller", function() 4 | { 5 | var controller; 6 | 7 | beforeEach(module("practice.service")); 8 | beforeEach(inject(function($controller) { 9 | controller = $controller("practice.serviceController", { practiceService: "service" }); 10 | })); 11 | 12 | it("should register service correctly", function() { 13 | expect(controller.service).toBe("service"); 14 | }); 15 | 16 | it("should have a message", function() { 17 | expect(controller.message).toBeDefined(); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /app/examples/service/service.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | angular.module("practice.service") 4 | .controller("practice.serviceController", serviceController); 5 | 6 | // always use $inject to make functions minify-able 7 | // @see https://docs.angularjs.org/guide/di 8 | serviceController.$inject = ["practiceService"]; 9 | 10 | function serviceController(practiceService) { 11 | var self = this; 12 | 13 | // define public variables for own scope 14 | self.service = practiceService; 15 | self.message = "used practiceService.verboseMessage(message) ..."; 16 | } 17 | }()); 18 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "globalstrict": true, 3 | "validthis": true, 4 | "browser" : true, 5 | "browserify" : true, 6 | "devel" : true, 7 | "jquery": true, 8 | "jasmine": true, 9 | "node" : true, 10 | "shelljs" : true, 11 | "globals": { 12 | "console": true, 13 | "__dirname": true, 14 | "require": true, 15 | "angular": false, 16 | "describe": false, 17 | "it": false, 18 | "xdescribe": false, 19 | "xit": false, 20 | "expect": false, 21 | "beforeEach": false, 22 | "afterEach": false, 23 | "module": false, 24 | "inject": false, 25 | "process": true, 26 | "by": true, 27 | "browser": true, 28 | "element": true, 29 | "Buffer": true 30 | } 31 | } -------------------------------------------------------------------------------- /app/examples/filter/filter.filter.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | angular.module("practice.filter") 4 | .filter("startsWith", startsWith); 5 | 6 | function startsWith() { 7 | // a filter is always a function with two parameters 'input' and 'expression' 8 | // and will return the filtered input again, in this case an array list 9 | // @see https://docs.angularjs.org/api/ng/filter/filter 10 | return function(list, expression) { 11 | return list.filter(function(entry) { 12 | if( !expression ) { 13 | return true; 14 | } 15 | 16 | return entry.name.toLowerCase().substr(0, expression.length) === expression.toLowerCase(); 17 | }); 18 | }; 19 | } 20 | }()); 21 | -------------------------------------------------------------------------------- /tests/unit/service/service.service.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | describe("when using the practiceService", function() 4 | { 5 | var practiceService; 6 | 7 | beforeEach(module("practice.service")); 8 | beforeEach(inject(function($injector) { 9 | practiceService = $injector.get("practiceService"); 10 | spyOn(window, "alert"); 11 | })); 12 | 13 | it("should alert 'used practiceService.publicFunction ...'", function() { 14 | practiceService.publicFunction(); 15 | expect(window.alert).toHaveBeenCalledWith("used practiceService.publicFunction ..."); 16 | }); 17 | 18 | it("should alert 'test message'", function() { 19 | practiceService.verboseMessage("test message"); 20 | expect(window.alert).toHaveBeenCalledWith("test message"); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /app/examples/error/error.tpl.html: -------------------------------------------------------------------------------- 1 |

Default Error Page Example

2 |
3 |
4 |

Description:

5 |

This module enable Angular to redirect any unknown routing to /error, like a '404 - Not Found' page.

6 | 7 |

Example Location:

8 |

app/examples/error/

9 | 10 |

Files:

11 | 25 |
26 |
27 | -------------------------------------------------------------------------------- /app/examples/filter/filter.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | angular.module("practice.filter") 4 | .controller("practice.filterController", filterController); 5 | 6 | function filterController() { 7 | var self = this; 8 | 9 | // define public variables for own scope 10 | self.entries = [ 11 | {id: 1, name: "One little duck"}, 12 | {id: 5, name: "Five little ducks"}, 13 | {id: 3, name: "Three little ducks"}, 14 | {id: 8, name: "Eight little ducks"}, 15 | {id: 6, name: "Six little ducks"}, 16 | {id: 2, name: "Two little ducks"}, 17 | {id: 9, name: "Nine little ducks"}, 18 | {id: 4, name: "Four little ducks"}, 19 | {id: 7, name: "Seven little ducks"} 20 | ]; 21 | } 22 | }()); 23 | -------------------------------------------------------------------------------- /app/examples/view/view.tpl.html: -------------------------------------------------------------------------------- 1 |

View Routing Example

2 |
3 |
4 |

Description:

5 |

This example creates a simple view with custom url route.

6 |

In result it will route #/view to template examples/view/view.tpl.html.

7 | 8 |

Example Location:

9 |

app/examples/view/

10 | 11 |

Files:

12 | 26 |
27 |
28 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-best-practice", 3 | "description": "This is a best practice AngularJS package.", 4 | "version": "0.1.5", 5 | "homepage": "https://github.com/eisbehr-/angular-best-practice", 6 | "authors": [{ 7 | "name": "Daniel 'Eisbehr' Kern", 8 | "email": "github@eisbehr.de", 9 | "homepage": "http://eisbehr.de" 10 | }], 11 | "repository": { 12 | "type": "git", 13 | "url": "git://github.com/eisbehr-/angular-best-practice.git" 14 | }, 15 | "keywords": [ 16 | "angular", 17 | "angularjs", 18 | "jasmin", 19 | "karma", 20 | "protractor" 21 | ], 22 | "dependencies": { 23 | "angular": "~1.4.7", 24 | "angular-loader": "~1.4.7", 25 | "angular-messages": "1.4.7", 26 | "angular-ui-router": "0.2.15", 27 | "jquery": "^2.1.4", 28 | "bootstrap": "~3.3.0", 29 | "bootstrap-material-design": "~0.1.5" 30 | }, 31 | "devDependencies": { 32 | "angular-mocks": "^1.4.7" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/unit/directives/directives.controller.directive.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | describe("when using controller directive", function() 4 | { 5 | var controller; 6 | 7 | beforeEach(module("practice.directives")); 8 | beforeEach(inject(function($rootScope, $compile) { 9 | var element = angular.element(""); 10 | var scope = $rootScope; 11 | 12 | $compile(element)(scope); 13 | $rootScope.$digest(); 14 | scope = element.isolateScope() || element.scope(); 15 | 16 | controller = scope.controller; 17 | })); 18 | 19 | it("should have a date", function() { 20 | expect(controller.date).toBeDefined(); 21 | }); 22 | 23 | it("should have exchange data defined", function() { 24 | expect(controller.exchange).toBeDefined(); 25 | }); 26 | 27 | it("should pass date format correctly", function() { 28 | expect(controller.format).toBe("test"); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /tests/e2e/examples/controller.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | describe("serving the controller page", function() { 4 | beforeEach(function() { 5 | browser.get("#/controller"); 6 | }); 7 | 8 | it("should have a headline h1", function() { 9 | var h1 = element(by.css("h1")); 10 | expect(h1.getText()).not.toBe(""); 11 | }); 12 | 13 | it("should have at least one content box", function() { 14 | var panel = element.all(by.css(".panel .panel-body")); 15 | expect(panel.count()).toBeGreaterThan(0); 16 | }); 17 | 18 | it("should alert a correct message", function() { 19 | element(by.model("myName")).sendKeys("test"); 20 | element(by.css("button")).click(); 21 | 22 | browser.wait(protractor.ExpectedConditions.alertIsPresent(), 1000); 23 | 24 | var alertDialog = browser.switchTo().alert(); 25 | expect(alertDialog.getText()).toEqual("Congratulation test, you clicked the button!"); 26 | alertDialog.accept(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /tests/unit/controller/service.controller.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | describe("when using controller example controller", function() 4 | { 5 | var controller; 6 | 7 | beforeEach(module("practice.controller")); 8 | beforeEach(inject(function($controller) { 9 | controller = $controller("practice.controllerController"); 10 | spyOn(window, "alert"); 11 | })); 12 | 13 | it("should have a headline", function() { 14 | expect(controller.headline).toBeDefined(); 15 | }); 16 | 17 | it("should have a location", function() { 18 | expect(controller.location).toBeDefined(); 19 | }); 20 | 21 | it("should have at least on entry", function() { 22 | expect(controller.files.length).toBeGreaterThan(0); 23 | }); 24 | 25 | it("should display correct message", function() { 26 | var name = "test"; 27 | controller.action(name); 28 | 29 | expect(window.alert).toHaveBeenCalledWith("Congratulation " + name + ", you clicked the button!"); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /app/examples/service/service.service.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | angular.module("practice.service") 4 | .service("practiceService", practiceService); 5 | 6 | function practiceService() { 7 | var self = this; 8 | 9 | // define public variables for this service 10 | self.publicFunction = publicFunction; 11 | self.verboseMessage = verboseMessage; 12 | 13 | // function definitions below 14 | 15 | /** 16 | * a public service function 17 | * @returns void 18 | */ 19 | function publicFunction() { 20 | var message = "used practiceService.publicFunction ..."; 21 | self.verboseMessage(message); 22 | } 23 | 24 | /** 25 | * verbose a message to console and alert 26 | * @param {string} message 27 | * @returns void 28 | */ 29 | function verboseMessage(message) { 30 | console.log(message); 31 | alert(message); 32 | } 33 | } 34 | }()); 35 | -------------------------------------------------------------------------------- /server/server.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var express = require("express"); 4 | var bodyParser = require("body-parser"); 5 | var methodOverride = require("method-override"); 6 | var path = require("path"); 7 | var app = express(); 8 | var port = process.env.PORT || 1337; 9 | var environment = process.env.ENV || "development"; 10 | 11 | // get all data/stuff of the body (POST) parameters 12 | app.use(bodyParser.json()); 13 | app.use(bodyParser.json({type: "application/vnd.api+json"})); 14 | app.use(bodyParser.urlencoded({extended: true})); 15 | app.use(methodOverride("X-HTTP-Method-Override")); 16 | 17 | // remap used directories 18 | app.use(express.static(path.join(__dirname, "..", "dist", environment))); 19 | app.use("/bower_components", express.static(path.join(__dirname, ".." , "bower_components"))); 20 | 21 | // routes 22 | require("./routes")(app); 23 | 24 | // start server 25 | app.listen(port); 26 | console.log("Server now listening on http://localhost:" + port + " ..."); 27 | exports = module.exports = app; 28 | -------------------------------------------------------------------------------- /app/examples/directives/directives.simple.directive.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | angular.module("practice.directives") 4 | .directive("simpleDirective", simpleDirective); 5 | 6 | // always use $inject to make functions minify-able 7 | // @see https://docs.angularjs.org/guide/di 8 | simpleDirective.$inject = ["$templateCache"]; 9 | 10 | function simpleDirective($templateCache) { 11 | return { 12 | // restrict directive only to be callable by element declaration '' 13 | restrict: "E", 14 | // don't use a template file, get it from '$templateCache' instead 15 | template: getTemplate 16 | }; 17 | 18 | /** 19 | * get template from cache 20 | * @returns string 21 | */ 22 | function getTemplate() { 23 | // template cache will be generated by gulp -> gulpfile.js 24 | // @see https://docs.angularjs.org/api/ng/service/$templateCache 25 | return $templateCache.get("examples/directives/directives.simple.directive.tpl.html"); 26 | } 27 | } 28 | }()); 29 | -------------------------------------------------------------------------------- /app/core/core.nav.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | angular.module("practice.core") 4 | .controller("practice.core.navController", navController); 5 | 6 | // always use $inject to make functions minify-able 7 | // @see https://docs.angularjs.org/guide/di 8 | navController.$inject = ["$element"]; 9 | 10 | function navController($element) { 11 | var self = this; 12 | 13 | // define public variables for own scope 14 | self.items = $element.find("li"); 15 | self.setActive = setActive; 16 | self.resetActive = resetActive; 17 | 18 | // function definitions below 19 | 20 | /** 21 | * remove active state from menu items 22 | * @param {object} $event 23 | * @returns void 24 | */ 25 | function setActive($event) { 26 | self.resetActive(); 27 | angular.element($event.currentTarget).parent().addClass("active"); 28 | } 29 | 30 | /** 31 | * remove active state from menu items 32 | * @returns void 33 | */ 34 | function resetActive() { 35 | self.items.removeClass("active"); 36 | } 37 | } 38 | }()); 39 | -------------------------------------------------------------------------------- /app/examples/promise/promise.service.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | angular.module("practice.promise") 4 | .service("promiseService", promiseService); 5 | 6 | // always use $inject to make functions minify-able 7 | // @see https://docs.angularjs.org/guide/di 8 | promiseService.$inject = ["$q"]; 9 | 10 | function promiseService($q) { 11 | var self = this; 12 | 13 | // define public variables for this service 14 | self.usePromise = usePromise; 15 | 16 | // function definitions below 17 | 18 | /** 19 | * creates and returns a promise 20 | * @see https://docs.angularjs.org/api/ng/service/$q 21 | * @param {boolean} shouldResolve 22 | * @returns {promise} 23 | */ 24 | function usePromise(shouldResolve) { 25 | var deferral = $q.defer(); 26 | 27 | if( typeof shouldResolve === "boolean" && shouldResolve ) { 28 | deferral.resolve("promiseService.usePromise successful"); 29 | } else { 30 | deferral.reject("promiseService.usePromise failed"); 31 | } 32 | 33 | return deferral.promise; 34 | } 35 | } 36 | }()); 37 | -------------------------------------------------------------------------------- /app/examples/controller/controller.tpl.html: -------------------------------------------------------------------------------- 1 |

{{controller.headline}}

2 |
3 |
4 |

Description:

5 |

This example creates a view-controller pair with custom url route.

6 |

7 | In result it will route #/controller to template examples/controller/controller.tpl.html 8 | and receive most of it's displayed information from the controller and delivers a content function action() for the button below. 9 |

10 | 11 |

Controller Action

12 |
13 | 14 | 15 |
16 | 17 | 18 |

Example Location:

19 |

{{controller.location}}

20 | 21 |

Files:

22 | 28 |
29 |
30 | -------------------------------------------------------------------------------- /tests/e2e/core.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | describe("serving the base layout", function() { 4 | beforeEach(function() { 5 | browser.get("#/"); 6 | }); 7 | 8 | it("should have a page title", function() { 9 | expect(browser.getTitle()).not.toBe(""); 10 | }); 11 | 12 | it("should have a home link on header", function() { 13 | var header = element(by.css('nav .navbar-header a.navbar-brand')); 14 | expect(header.getAttribute("href")).toBe("http://localhost:1337/#/"); 15 | }); 16 | 17 | it("should have global nav-bar entries", function() { 18 | var entries = element.all(by.css('nav ul.nav li')); 19 | expect(entries.count()).toBeGreaterThan(0); 20 | }); 21 | 22 | it("should set active class on click", function() { 23 | var hasClass = function (element, cssClass) { 24 | return element.getAttribute('class').then(function (classes) { 25 | return classes.split(' ').indexOf(cssClass) !== -1; 26 | }); 27 | }; 28 | 29 | var firstEntry = element.all(by.css('nav ul.nav li')).first(); 30 | firstEntry.element(by.css("a")).click(); 31 | 32 | expect(hasClass(firstEntry, 'active')).toBeTruthy(); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /tests/unit/filter/filter.filter.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | describe("when using the startsWith filter", function() 4 | { 5 | var filter, entries; 6 | 7 | beforeEach(angular.mock.module("practice.filter")); 8 | beforeEach(angular.mock.inject(function($filter) { 9 | filter = $filter("startsWith"); 10 | entries = [ 11 | { name: "a" }, 12 | { name: "b" }, 13 | { name: "b" }, 14 | { name: "c" }, 15 | { name: "c" }, 16 | { name: "c" } 17 | ]; 18 | })); 19 | 20 | it("should filter to correct length", function() { 21 | var result = filter(entries, "b"); 22 | expect(result.length).toBe(2); 23 | }); 24 | 25 | it("should return all entries on undefined expression", function() { 26 | var result = filter(entries); 27 | expect(result.length).toBe(entries.length); 28 | }); 29 | 30 | it("should return all entries on empty expression", function() { 31 | var result = filter(entries, ""); 32 | expect(result.length).toBe(entries.length); 33 | }); 34 | 35 | it("should return nothing on non containing search", function() { 36 | var result = filter(entries, "d"); 37 | expect(result.length).toBe(0); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /app/examples/view/view.route.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; 3 | angular.module("practice.view") 4 | .config(route); 5 | 6 | // always use $inject to make functions minify-able 7 | // @see https://docs.angularjs.org/guide/di 8 | route.$inject = ["$stateProvider"]; 9 | 10 | function route($stateProvider) { 11 | // create a url route 12 | // @see https://angular-ui.github.io/ui-router/site/ 13 | $stateProvider.state("view", { 14 | url: "/view", 15 | // don't use a template file, get it from '$templateCache' instead 16 | templateProvider: getTemplate 17 | }); 18 | 19 | // always use $inject to make functions minify-able 20 | // @see https://docs.angularjs.org/guide/di 21 | getTemplate.$inject = ["$templateCache"]; 22 | 23 | /** 24 | * get template from cache 25 | * @param {$templateCache} $templateCache 26 | * @returns string 27 | */ 28 | function getTemplate($templateCache) { 29 | // template cache will be generated by gulp -> gulpfile.js 30 | // @see https://docs.angularjs.org/api/ng/service/$templateCache 31 | return $templateCache.get("examples/view/view.tpl.html"); 32 | } 33 | } 34 | }()); 35 | -------------------------------------------------------------------------------- /tests/e2e/examples/filter.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | describe("serving the filter page", function() { 4 | beforeEach(function() { 5 | browser.get("#/filter"); 6 | }); 7 | 8 | it("should have a headline h1", function() { 9 | var h1 = element(by.css("h1")); 10 | expect(h1.getText()).not.toBe(""); 11 | }); 12 | 13 | it("should have at least one content box", function() { 14 | var panel = element.all(by.css(".panel .panel-body")); 15 | expect(panel.count()).toBeGreaterThan(0); 16 | }); 17 | 18 | it("should filter to a correct amount", function() { 19 | element(by.model("query")).sendKeys("one"); 20 | var entries = element.all(by.css("ul.results li")); 21 | 22 | expect(entries.count()).toBe(1); 23 | }); 24 | 25 | it("should return nothing on wrong input", function() { 26 | element(by.model("query")).sendKeys("test"); 27 | var entries = element.all(by.css("ul.results li")); 28 | 29 | expect(entries.count()).toBe(0); 30 | }); 31 | 32 | it("should update displayed amount on filter", function() { 33 | element(by.model("query")).sendKeys("one"); 34 | var results = element(by.css("span.results")); 35 | 36 | expect(results.getText()).toBe("1"); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /tests/e2e/examples/directives.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | describe("serving the directives page", function() { 4 | beforeEach(function() { 5 | browser.get("#/directives"); 6 | }); 7 | 8 | it("should have a headline h1", function() { 9 | var h1 = element(by.css("h1")); 10 | expect(h1.getText()).not.toBe(""); 11 | }); 12 | 13 | it("should have at least one content box", function() { 14 | var panel = element.all(by.css(".panel .panel-body")); 15 | expect(panel.count()).toBeGreaterThan(0); 16 | }); 17 | 18 | it("should update text in controller directive", function() { 19 | var outerInput = element(by.model("data")), 20 | innerInput = element(by.model("controller.exchange")); 21 | 22 | outerInput.clear().sendKeys("test").then(function() { 23 | expect(innerInput.getAttribute("value")).toEqual("test"); 24 | }); 25 | }); 26 | 27 | it("should update text out of controller directive", function() { 28 | var outerInput = element(by.model("data")), 29 | innerInput = element(by.model("controller.exchange")); 30 | 31 | innerInput.clear().sendKeys("test").then(function() { 32 | expect(outerInput.getAttribute("value")).toEqual("test"); 33 | }); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /app/examples/directives/directives.route.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; 3 | angular.module("practice.directives") 4 | .config(route); 5 | 6 | // always use $inject to make functions minify-able 7 | // @see https://docs.angularjs.org/guide/di 8 | route.$inject = ["$stateProvider"]; 9 | 10 | function route($stateProvider) { 11 | // create a url route 12 | // @see https://angular-ui.github.io/ui-router/site/ 13 | $stateProvider.state("directives", { 14 | url: "/directives", 15 | // don't use a template file, get it from '$templateCache' instead 16 | templateProvider: getTemplate 17 | }); 18 | 19 | // always use $inject to make functions minify-able 20 | // @see https://docs.angularjs.org/guide/di 21 | getTemplate.$inject = ["$templateCache"]; 22 | 23 | /** 24 | * get template from cache 25 | * @param {$templateCache} $templateCache 26 | * @returns string 27 | */ 28 | function getTemplate($templateCache) { 29 | // template cache will be generated by gulp -> gulpfile.js 30 | // @see https://docs.angularjs.org/api/ng/service/$templateCache 31 | return $templateCache.get("examples/directives/directives.tpl.html"); 32 | } 33 | } 34 | }()); 35 | -------------------------------------------------------------------------------- /tests/e2e/examples/promise.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | describe("serving the promise page", function() { 4 | beforeEach(function() { 5 | browser.get("#/promise"); 6 | }); 7 | 8 | it("should have a headline h1", function() { 9 | var h1 = element(by.css("h1")); 10 | expect(h1.getText()).not.toBe(""); 11 | }); 12 | 13 | it("should have at least one content box", function() { 14 | var panel = element.all(by.css(".panel .panel-body")); 15 | expect(panel.count()).toBeGreaterThan(0); 16 | }); 17 | 18 | it("should alert a correct message on resolve", function() { 19 | element.all(by.css("button")).first().click(); 20 | 21 | browser.wait(protractor.ExpectedConditions.alertIsPresent(), 1000); 22 | 23 | var alertDialog = browser.switchTo().alert(); 24 | expect(alertDialog.getText()).toEqual("promiseService.usePromise successful"); 25 | alertDialog.accept(); 26 | }); 27 | 28 | it("should alert a correct message on reject", function() { 29 | element.all(by.css("button")).last().click(); 30 | 31 | browser.wait(protractor.ExpectedConditions.alertIsPresent(), 1000); 32 | 33 | var alertDialog = browser.switchTo().alert(); 34 | expect(alertDialog.getText()).toEqual("promiseService.usePromise failed"); 35 | alertDialog.accept(); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /app/examples/filter/filter.route.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; 3 | angular.module("practice.filter") 4 | .config(route); 5 | 6 | // always use $inject to make functions minify-able 7 | // @see https://docs.angularjs.org/guide/di 8 | route.$inject = ["$stateProvider"]; 9 | 10 | function route($stateProvider) { 11 | // create a url route 12 | // @see https://angular-ui.github.io/ui-router/site/ 13 | $stateProvider.state("filter", { 14 | url: "/filter", 15 | controller: "practice.filterController as controller", 16 | // don't use a template file, get it from '$templateCache' instead 17 | templateProvider: getTemplate 18 | }); 19 | 20 | // always use $inject to make functions minify-able 21 | // @see https://docs.angularjs.org/guide/di 22 | getTemplate.$inject = ["$templateCache"]; 23 | 24 | /** 25 | * get template from cache 26 | * @param {$templateCache} $templateCache 27 | * @returns string 28 | */ 29 | function getTemplate($templateCache) { 30 | // template cache will be generated by gulp -> gulpfile.js 31 | // @see https://docs.angularjs.org/api/ng/service/$templateCache 32 | return $templateCache.get("examples/filter/filter.tpl.html"); 33 | } 34 | } 35 | }()); 36 | -------------------------------------------------------------------------------- /app/examples/promise/promise.route.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; 3 | angular.module("practice.promise") 4 | .config(route); 5 | 6 | // always use $inject to make functions minify-able 7 | // @see https://docs.angularjs.org/guide/di 8 | route.$inject = ["$stateProvider"]; 9 | 10 | function route($stateProvider) { 11 | // create a url route 12 | // @see https://angular-ui.github.io/ui-router/site/ 13 | $stateProvider.state("promise", { 14 | url: "/promise", 15 | controller: "practice.promiseController as controller", 16 | // don't use a template file, get it from '$templateCache' instead 17 | templateProvider: getTemplate 18 | }); 19 | 20 | // always use $inject to make functions minify-able 21 | // @see https://docs.angularjs.org/guide/di 22 | getTemplate.$inject = ["$templateCache"]; 23 | 24 | /** 25 | * get template from cache 26 | * @param {$templateCache} $templateCache 27 | * @returns string 28 | */ 29 | function getTemplate($templateCache) { 30 | // template cache will be generated by gulp -> gulpfile.js 31 | // @see https://docs.angularjs.org/api/ng/service/$templateCache 32 | return $templateCache.get("examples/promise/promise.tpl.html"); 33 | } 34 | } 35 | }()); 36 | -------------------------------------------------------------------------------- /app/examples/service/service.route.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; 3 | angular.module("practice.service") 4 | .config(route); 5 | 6 | // always use $inject to make functions minify-able 7 | // @see https://docs.angularjs.org/guide/di 8 | route.$inject = ["$stateProvider"]; 9 | 10 | function route($stateProvider) { 11 | // create a url route 12 | // @see https://angular-ui.github.io/ui-router/site/ 13 | $stateProvider.state("service", { 14 | url: "/service", 15 | controller: "practice.serviceController as controller", 16 | // don't use a template file, get it from '$templateCache' instead 17 | templateProvider: getTemplate 18 | }); 19 | 20 | // always use $inject to make functions minify-able 21 | // @see https://docs.angularjs.org/guide/di 22 | getTemplate.$inject = ["$templateCache"]; 23 | 24 | /** 25 | * get template from cache 26 | * @param {$templateCache} $templateCache 27 | * @returns string 28 | */ 29 | function getTemplate($templateCache) { 30 | // template cache will be generated by gulp -> gulpfile.js 31 | // @see https://docs.angularjs.org/api/ng/service/$templateCache 32 | return $templateCache.get("examples/service/service.tpl.html"); 33 | } 34 | } 35 | }()); 36 | -------------------------------------------------------------------------------- /app/examples/controller/controller.route.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; 3 | angular.module("practice.controller") 4 | .config(route); 5 | 6 | // always use $inject to make functions minify-able 7 | // @see https://docs.angularjs.org/guide/di 8 | route.$inject = ["$stateProvider"]; 9 | 10 | function route($stateProvider) { 11 | // create a url route 12 | // @see https://angular-ui.github.io/ui-router/site/ 13 | $stateProvider.state("controller", { 14 | url: "/controller", 15 | controller: "practice.controllerController as controller", 16 | // don't use a template file, get it from '$templateCache' instead 17 | templateProvider: getTemplate 18 | }); 19 | 20 | // always use $inject to make functions minify-able 21 | // @see https://docs.angularjs.org/guide/di 22 | getTemplate.$inject = ["$templateCache"]; 23 | 24 | /** 25 | * get template from cache 26 | * @param {$templateCache} $templateCache 27 | * @returns string 28 | */ 29 | function getTemplate($templateCache) { 30 | // template cache will be generated by gulp -> gulpfile.js 31 | // @see https://docs.angularjs.org/api/ng/service/$templateCache 32 | return $templateCache.get("examples/controller/controller.tpl.html"); 33 | } 34 | } 35 | }()); 36 | -------------------------------------------------------------------------------- /tests/e2e/examples/service.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | describe("serving the service page", function() { 4 | beforeEach(function() { 5 | browser.get("#/service"); 6 | }); 7 | 8 | it("should have a headline h1", function() { 9 | var h1 = element(by.css("h1")); 10 | expect(h1.getText()).not.toBe(""); 11 | }); 12 | 13 | it("should have at least one content box", function() { 14 | var panel = element.all(by.css(".panel .panel-body")); 15 | expect(panel.count()).toBeGreaterThan(0); 16 | }); 17 | 18 | it("should alert a correct message on publicFunction button", function() { 19 | element.all(by.css("button")).first().click(); 20 | 21 | browser.wait(protractor.ExpectedConditions.alertIsPresent(), 1000); 22 | 23 | var alertDialog = browser.switchTo().alert(); 24 | expect(alertDialog.getText()).toEqual("used practiceService.publicFunction ..."); 25 | alertDialog.accept(); 26 | }); 27 | 28 | it("should alert a correct message on verboseMessage button", function() { 29 | element(by.model("controller.message")).clear().sendKeys("test"); 30 | element.all(by.css("button")).last().click(); 31 | 32 | browser.wait(protractor.ExpectedConditions.alertIsPresent(), 1000); 33 | 34 | var alertDialog = browser.switchTo().alert(); 35 | expect(alertDialog.getText()).toEqual("test"); 36 | alertDialog.accept(); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /app/home/home.route.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; 3 | angular.module("practice.home") 4 | .config(route); 5 | 6 | // always use $inject to make functions minify-able 7 | // @see https://docs.angularjs.org/guide/di 8 | route.$inject = ["$stateProvider", "$urlRouterProvider"]; 9 | 10 | function route($stateProvider, $urlRouterProvider) { 11 | // create a url route 12 | // @see https://angular-ui.github.io/ui-router/site/ 13 | $stateProvider.state("home", { 14 | url: "/", 15 | // don't use a template file, get it from '$templateCache' instead 16 | templateProvider: getTemplate 17 | }); 18 | 19 | // route empty request to home page 20 | // @see https://docs.angularjs.org/api/ngRoute/provider/$routeProvider 21 | $urlRouterProvider.when("", "/"); 22 | 23 | // always use $inject to make functions minify-able 24 | // @see: https://docs.angularjs.org/guide/di 25 | getTemplate.$inject = ["$templateCache"]; 26 | 27 | /** 28 | * get template from cache 29 | * @param {$templateCache} $templateCache 30 | * @returns string 31 | */ 32 | function getTemplate($templateCache) { 33 | // template cache will be generated by gulp -> gulpfile.js 34 | // @see https://docs.angularjs.org/api/ng/service/$templateCache 35 | return $templateCache.get("home/home.tpl.html"); 36 | } 37 | } 38 | }()); 39 | -------------------------------------------------------------------------------- /app/examples/controller/controller.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | angular.module("practice.controller") 4 | .controller("practice.controllerController", controllerController); 5 | 6 | // always use $inject to make functions minify-able 7 | // @see https://docs.angularjs.org/guide/di 8 | controllerController.$inject = ["$location"]; 9 | 10 | function controllerController($location) { 11 | var self = this; 12 | 13 | // define public variables for own scope 14 | self.headline = "View-Controller Example"; 15 | self.location = "app/examples" + $location.path() + "/"; 16 | self.files = [ 17 | {name: "controller.module.js", description: "module creation"}, 18 | {name: "controller.route.js", description: "module routing"}, 19 | {name: "controller.controller.js", description: "view controller"}, 20 | {name: "controller.tpl.html", description: "content template"} 21 | ]; 22 | self.action = action; 23 | 24 | // function definitions below 25 | 26 | /** 27 | * alert and log a simple message for demonstration 28 | * @param {string} nameInput 29 | * @returns void 30 | */ 31 | function action(nameInput) { 32 | var name = nameInput ? nameInput : "Angular", 33 | message = "Congratulation " + name + ", you clicked the button!"; 34 | 35 | console.log(message); 36 | alert(message); 37 | } 38 | } 39 | }()); 40 | -------------------------------------------------------------------------------- /app/examples/error/error.route.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; 3 | angular.module("practice.error") 4 | .config(route); 5 | 6 | // always use $inject to make functions minify-able 7 | // @see https://docs.angularjs.org/guide/di 8 | route.$inject = ["$stateProvider", "$urlRouterProvider"]; 9 | 10 | function route($stateProvider, $urlRouterProvider) { 11 | // create a url route 12 | // @see https://angular-ui.github.io/ui-router/site/ 13 | $stateProvider.state("error", { 14 | url: "/error", 15 | // don't use a template file, get it from '$templateCache' instead 16 | templateProvider: getTemplate 17 | }); 18 | 19 | // route every unknown request to error page 20 | // @see https://docs.angularjs.org/api/ngRoute/provider/$routeProvider 21 | $urlRouterProvider.otherwise("/error"); 22 | 23 | // always use $inject to make functions minify-able 24 | // @see https://docs.angularjs.org/guide/di 25 | getTemplate.$inject = ["$templateCache"]; 26 | 27 | /** 28 | * get template from cache 29 | * @param {$templateCache} $templateCache 30 | * @returns string 31 | */ 32 | function getTemplate($templateCache) { 33 | // template cache will be generated by gulp -> gulpfile.js 34 | // @see https://docs.angularjs.org/api/ng/service/$templateCache 35 | return $templateCache.get("examples/error/error.tpl.html"); 36 | } 37 | } 38 | }()); 39 | -------------------------------------------------------------------------------- /app/examples/promise/promise.tpl.html: -------------------------------------------------------------------------------- 1 |

Using Promises

2 |
3 |
4 |

Description:

5 |

This example creates a simple promise names usePromise inside the promiseService service.

6 |

Promises enables you to react on .then() and .catch() inside your app.

7 | 8 |

Use Promise

9 |

10 | Trigger the promise by the buttons below. 11 | Choose to let them success (resolve) or fail (reject). 12 |

13 | 14 | 15 | 16 |

Example Location:

17 |

app/examples/promises/

18 | 19 |

Files:

20 | 42 |
43 |
44 | -------------------------------------------------------------------------------- /app/examples/filter/filter.tpl.html: -------------------------------------------------------------------------------- 1 |

Custom Filter Example

2 |
3 |
4 |

Description:

5 |

This example creates a simple filter named startsWith, e.g. usable by ng-repeat.

6 | 7 |

Use Filter

8 |

Try filter the list below by typing in something.

9 |
10 | 11 | 12 |
13 |

Results: {{result.length}}

14 | 21 | 22 |

Example Location:

23 |

app/examples/filter/

24 | 25 |

Files:

26 | 44 |
45 |
46 | -------------------------------------------------------------------------------- /app/examples/promise/promise.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | angular.module("practice.promise") 4 | .controller("practice.promiseController", promiseController); 5 | 6 | // always use $inject to make functions minify-able 7 | // @see https://docs.angularjs.org/guide/di 8 | promiseController.$inject = ["promiseService"]; 9 | 10 | function promiseController(promiseService) { 11 | var self = this; 12 | 13 | // define public variables for own scope 14 | self.executeSuccessful = executeSuccessful; 15 | self.executeFailure = executeFailure; 16 | self.usePromise = usePromise; 17 | 18 | // function definitions below 19 | 20 | /** 21 | * use promiseService promise and let it resolve 22 | * @returns {promise} 23 | */ 24 | function executeSuccessful() { 25 | return self.usePromise(true); 26 | } 27 | 28 | /** 29 | * use promiseService promise and let it reject 30 | * @returns {promise} 31 | */ 32 | function executeFailure() { 33 | return self.usePromise(false); 34 | } 35 | 36 | /** 37 | * use promiseService promise and determine if it should resolve 38 | * @param {boolean} shouldResolve 39 | * @returns {promise} 40 | */ 41 | function usePromise(shouldResolve) { 42 | var promise = promiseService.usePromise(shouldResolve); 43 | 44 | promise.then(function(response) { 45 | console.log(response); 46 | alert(response); 47 | }).catch(function(error) { 48 | console.log(error); 49 | alert(error); 50 | }); 51 | 52 | return promise; 53 | } 54 | } 55 | }()); 56 | -------------------------------------------------------------------------------- /app/examples/service/service.tpl.html: -------------------------------------------------------------------------------- 1 |

Service Example

2 |
3 |
4 |

Description:

5 |

This example creates a simple service named practiceService with two public functions publicFunction and verboseMessage.

6 | 7 |

Use Service

8 |

9 | Trigger the service function by buttons below. 10 | Type in a custom message to demonstrate passing parameters. 11 |

12 |
13 | 14 | 15 |
16 | 17 | 18 | 19 |

Example Location:

20 |

app/examples/service/

21 | 22 |

Files:

23 | 45 |
46 |
47 | -------------------------------------------------------------------------------- /app/examples/directives/directives.controller.directive.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | angular.module("practice.directives") 4 | .directive("controllerDirective", controllerDirective); 5 | 6 | // always use $inject to make functions minify-able 7 | // @see https://docs.angularjs.org/guide/di 8 | controllerDirective.$inject = ["$templateCache"]; 9 | 10 | function controllerDirective($templateCache) { 11 | return { 12 | controller: controller, 13 | controllerAs: "controller", 14 | // bind all variables directly to controller as well 15 | bindToController: true, 16 | // restrict directive only to be callable by element declaration '' 17 | restrict: "E", 18 | scope: { 19 | // declares variable 'format' as one-way-binding 20 | format: "@", 21 | 22 | // declares variable 'exchange' as two-way-binding 23 | exchange: "=" 24 | }, 25 | // don't use a template file, get it from '$templateCache' instead 26 | template: getTemplate 27 | }; 28 | 29 | function controller() { 30 | var self = this; 31 | 32 | // define public variables for own scope 33 | self.date = new Date(); 34 | self.exchange = "some exchanged information"; 35 | } 36 | 37 | /** 38 | * get template from cache 39 | * @returns string 40 | */ 41 | function getTemplate() { 42 | // template cache will be generated by gulp -> gulpfile.js 43 | // @see https://docs.angularjs.org/api/ng/service/$templateCache 44 | return $templateCache.get("examples/directives/directives.controller.directive.tpl.html"); 45 | } 46 | } 47 | }()); 48 | -------------------------------------------------------------------------------- /app/home/home.tpl.html: -------------------------------------------------------------------------------- 1 |

AngularJS - Best Practice

2 |
3 |
4 |

What does this App?

5 |

It contains some examples of angular components and their best practice usages.

6 | 7 |

Why is this best practice?

8 |

9 | There are some projects and persons out there, defining some pseudo standards using angular. 10 | I'll adapted their ideas and created this project to combine everything for me and others. 11 | Feel free to let me know if you got some better ideas. :) 12 |

13 |

Inspirations:

14 | 21 | 22 | 30 | 31 |

Select an Example

32 | 41 |
42 |
43 | -------------------------------------------------------------------------------- /app/examples/directives/directives.tpl.html: -------------------------------------------------------------------------------- 1 |

Directives Example

2 |
3 |
4 |

Description:

5 |

This example creates a two directives simpleDirective and controllerDirective.

6 |

The results of this directives can be seen below.

7 | 8 |

Simple Directive

9 |

The simple-directive just display a template without any further actions.

10 | 11 | 12 |

Directive with Controller

13 |

14 | The controller-directive has an own controller, like a view-controller. 15 | Beside this the directive exchanges data between itself and the parent view. 16 | Just type something in the input field below ... 17 |

18 |
19 | 20 |
21 | 22 | 23 |

Example Location:

24 |

app/examples/directives/

25 | 26 |

Files:

27 | 57 |
58 |
59 | -------------------------------------------------------------------------------- /tests/unit/promise/promise.service.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | describe("when using the promiseService", function() 4 | { 5 | var $q, $rootScope, promiseService; 6 | 7 | beforeEach(module("practice.promise")); 8 | beforeEach(inject(function(_$q_, _$rootScope_, $injector) { 9 | $q = _$q_; 10 | $rootScope = _$rootScope_; 11 | promiseService = $injector.get("promiseService"); 12 | })); 13 | 14 | it("should be resolve on 'true'", function() { 15 | var result = false, 16 | deferred = $q.defer(), 17 | promise = deferred.promise; 18 | 19 | promise.then(function() { 20 | result = true; 21 | }); 22 | 23 | promiseService.usePromise(true).then(function() { 24 | deferred.resolve(); 25 | }); 26 | 27 | $rootScope.$digest(); 28 | expect(result).toBeTruthy(); 29 | }); 30 | 31 | it("should be reject on 'false'", function() { 32 | var result = true, 33 | deferred = $q.defer(), 34 | promise = deferred.promise; 35 | 36 | promise.catch(function() { 37 | result = false; 38 | }); 39 | 40 | promiseService.usePromise(false).catch(function() { 41 | deferred.reject(); 42 | }); 43 | 44 | $rootScope.$digest(); 45 | expect(result).toBeFalsy(); 46 | }); 47 | 48 | it("should be reject on string", function() { 49 | var result = true, 50 | deferred = $q.defer(), 51 | promise = deferred.promise; 52 | 53 | promise.catch(function() { 54 | result = false; 55 | }); 56 | 57 | promiseService.usePromise("string").catch(function() { 58 | deferred.reject(); 59 | }); 60 | 61 | $rootScope.$digest(); 62 | expect(result).toBeFalsy(); 63 | }); 64 | 65 | it("should be reject on integer", function() { 66 | var result = true, 67 | deferred = $q.defer(), 68 | promise = deferred.promise; 69 | 70 | promise.catch(function() { 71 | result = false; 72 | }); 73 | 74 | promiseService.usePromise(1337).catch(function() { 75 | deferred.reject(); 76 | }); 77 | 78 | $rootScope.$digest(); 79 | expect(result).toBeFalsy(); 80 | }); 81 | }); 82 | -------------------------------------------------------------------------------- /tests/unit/promise/promise.controller.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | describe("when using promise controller public functions", function() 4 | { 5 | var $q, $rootScope, controller, promiseService; 6 | 7 | beforeEach(module("practice.promise")); 8 | beforeEach(inject(function(_$q_, _$rootScope_, $controller, $injector) { 9 | $q = _$q_; 10 | $rootScope = _$rootScope_; 11 | promiseService = $injector.get("promiseService"); 12 | controller = $controller("practice.promiseController", { promiseService: promiseService }); 13 | })); 14 | 15 | it("should be resolve on 'executeSuccessful'", function() { 16 | var result = false, 17 | deferred = $q.defer(), 18 | promise = deferred.promise; 19 | 20 | promise.then(function() { 21 | result = true; 22 | }); 23 | 24 | controller.executeSuccessful().then(function() { 25 | deferred.resolve(); 26 | }); 27 | 28 | $rootScope.$digest(); 29 | expect(result).toBeTruthy(); 30 | }); 31 | 32 | it("should be reject on 'executeFailure'", function() { 33 | var result = true, 34 | deferred = $q.defer(), 35 | promise = deferred.promise; 36 | 37 | promise.catch(function() { 38 | result = false; 39 | }); 40 | 41 | controller.executeFailure().catch(function() { 42 | deferred.reject(); 43 | }); 44 | 45 | $rootScope.$digest(); 46 | expect(result).toBeFalsy(); 47 | }); 48 | 49 | it("should be resolve on 'usePromise(true)'", function() { 50 | var result = false, 51 | deferred = $q.defer(), 52 | promise = deferred.promise; 53 | 54 | promise.then(function() { 55 | result = true; 56 | }); 57 | 58 | controller.usePromise(true).then(function() { 59 | deferred.resolve(); 60 | }); 61 | 62 | $rootScope.$digest(); 63 | expect(result).toBeTruthy(); 64 | }); 65 | 66 | it("should be reject on 'usePromise(false)'", function() { 67 | var result = true, 68 | deferred = $q.defer(), 69 | promise = deferred.promise; 70 | 71 | promise.catch(function() { 72 | result = false; 73 | }); 74 | 75 | controller.usePromise(false).catch(function() { 76 | deferred.reject(); 77 | }); 78 | 79 | $rootScope.$digest(); 80 | expect(result).toBeFalsy(); 81 | }); 82 | }); 83 | -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Angular Practice App 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 35 | 36 |
37 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-best-practice", 3 | "version": "0.1.5", 4 | "title": "AngularJS - Best Practice", 5 | "description": "This is a best practice AngularJS package.", 6 | "homepage": "https://github.com/eisbehr-/angular-best-practice", 7 | "bugs": "http://github.com/eisbehr-/angular-best-practice/issues", 8 | "repository": { 9 | "type": "git", 10 | "url": "git@github.com:eisbehr-/angular-best-practice.git" 11 | }, 12 | "author": { 13 | "name": "Daniel 'Eisbehr' Kern", 14 | "email": "github@eisbehr.de", 15 | "url": "http://eisbehr.de" 16 | }, 17 | "keywords": [ 18 | "angular", 19 | "angularjs", 20 | "jasmin", 21 | "karma", 22 | "protractor" 23 | ], 24 | "devDependencies": { 25 | "bower": "^1.3.1", 26 | "body-parser": "^1.9.2", 27 | "del": "^1.1.1", 28 | "event-stream": "^3.2.2", 29 | "express": "^4.10.1", 30 | "gulp": "^3.8.10", 31 | "gulp-angular-filesort": "^1.0.4", 32 | "gulp-bower-assets": "^0.0.3", 33 | "gulp-concat": "^2.4.3", 34 | "gulp-htmlhint": "0.0.9", 35 | "gulp-htmlmin": "^1.0.0", 36 | "gulp-inject": "^1.1.1", 37 | "gulp-jshint": "^1.9.2", 38 | "gulp-less": "^3.0.3", 39 | "gulp-livereload": "^3.7.0", 40 | "gulp-load-plugins": "^0.8.0", 41 | "gulp-minify-css": "^0.4.5", 42 | "gulp-ng-html2js": "^0.2.0", 43 | "gulp-nodemon": "^1.0.5", 44 | "gulp-order": "^1.1.1", 45 | "gulp-print": "^1.1.0", 46 | "gulp-rename": "^1.2.2", 47 | "gulp-rev": "^6.0.1", 48 | "gulp-sass": "^1.3.2", 49 | "gulp-sourcemaps": "^1.3.0", 50 | "gulp-tap": "^0.1.3", 51 | "gulp-uglify": "^1.1.0", 52 | "gulp-util": "^3.0.7", 53 | "jshint-stylish": "^1.0.0", 54 | "jasmine-core": "^2.3.4", 55 | "karma": "~0.12", 56 | "karma-chrome-launcher": "^0.1.12", 57 | "karma-firefox-launcher": "^0.1.6", 58 | "karma-phantomjs-launcher": "^0.2.1", 59 | "karma-jasmine": "^0.3.5", 60 | "karma-junit-reporter": "^0.2.2", 61 | "main-bower-files": "^2.5.0", 62 | "method-override": "^2.3.0", 63 | "q": "^1.1.2", 64 | "require-dir": "^0.3.0", 65 | "phantomjs": "^1.9.18", 66 | "protractor": "^2.1.0", 67 | "shelljs": "^0.2.6" 68 | }, 69 | "scripts": { 70 | "postinstall": "bower install", 71 | "prestart": "npm install", 72 | "start": "gulp watch-dev", 73 | "pretest": "npm install", 74 | "test": "karma start karma.conf.js", 75 | "test-single-run": "karma start karma.conf.js --single-run", 76 | "preupdate-webdriver": "npm install", 77 | "update-webdriver": "webdriver-manager update", 78 | "prestart-webdriver": "npm run update-webdriver", 79 | "start-webdriver": "webdriver-manager start", 80 | "preprotractor": "npm run update-webdriver", 81 | "protractor": "protractor protractor.conf.js", 82 | "protractor-direct": "protractor protractor.conf.js" 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | module.exports = function(config) { 3 | config.set({ 4 | // base path that will be used to resolve all patterns (eg. files, exclude) 5 | basePath : './', 6 | 7 | // frameworks to use 8 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 9 | frameworks: ['jasmine'], 10 | 11 | // list of files / patterns to load in the browser 12 | files : [ 13 | // angular dependencies 14 | 'bower_components/angular/angular.js', 15 | 'bower_components/angular-mocks/angular-mocks.js', 16 | 'bower_components/angular-ui-router/release/angular-ui-router.js', 17 | // app - module definitions first 18 | 'app/**/*.module.js', 19 | 'app/**/*.js', 20 | // templates 21 | 'app/**/*.html', 22 | // tests 23 | 'tests/**/*.spec.js' 24 | ], 25 | 26 | // list of files to exclude 27 | exclude: [ 28 | 'tests/output/**/*.spec.js', 29 | 'tests/e2e/**/*.spec.js' 30 | ], 31 | 32 | // pre-process matching files before serving them to the browser 33 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 34 | preprocessors: { 35 | 'app/examples/**/*.html': 'html2js' 36 | }, 37 | 38 | // test results reporter to use 39 | // possible values: 'dots', 'progress' 40 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 41 | reporters: [ 42 | 'progress', 43 | 'junit' 44 | ], 45 | 46 | // web server port 47 | port: 9876, 48 | 49 | // enable / disable colors in the output (reporters and logs) 50 | colors: true, 51 | 52 | // level of logging 53 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 54 | logLevel: config.LOG_INFO, 55 | 56 | // enable / disable watching file and executing tests whenever any file changes 57 | autoWatch: true, 58 | 59 | // start these browsers 60 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 61 | browsers: [ 62 | 'Chrome', 63 | 'Firefox', 64 | 'PhantomJS' 65 | ], 66 | 67 | // Continuous Integration mode 68 | // if true, Karma captures browsers, runs the tests and exits 69 | singleRun: false, 70 | 71 | // plugins to load by Karma 72 | plugins : [ 73 | 'karma-chrome-launcher', 74 | 'karma-firefox-launcher', 75 | 'karma-phantomjs-launcher', 76 | 'karma-jasmine', 77 | 'karma-junit-reporter' 78 | ], 79 | 80 | // junit report configuration 81 | junitReporter : { 82 | // results will be saved as $outputDir/$browserName.xml 83 | outputDir: '', 84 | 85 | // if included, results will be saved as $outputDir/$browserName/$outputFile 86 | outputFile: "tests/output/karma-result.xml", 87 | 88 | // suite will become the package name attribute in xml test suite element 89 | suite: 'unit', 90 | 91 | // add browser name to report and classes names 92 | useBrowserName: true 93 | } 94 | }); 95 | }; 96 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AngularJS Best-Practice App Package 2 | 3 | ### Table of Contents 4 | * [What is this?](#what-is-this) 5 | * [Features](#features) 6 | * [Requirements](#requirements) 7 | * [Installation](#installation) 8 | * [Run Application and start development Server](#run-application-and-start-development-server) 9 | * [Run Tests](#run-tests) 10 | * [Run UI Tests](#run-ui-tests) 11 | * [Build Application for Deployment](#build-application-for-deployment) 12 | * [Why bower AND npm?](#why-bower-and-npm) 13 | * [Bugs / Feature request](#bugs--feature-request) 14 | 15 | --- 16 | 17 | ## What is this? 18 | This small AngularJS application contains some simple examples explaining the components of angular. 19 | It tries to use the best-practice design pattern for everything and is inspired by following projects: 20 | - [johnpapa/angular-styleguide](https://github.com/johnpapa/angular-styleguide) 21 | - [angular/angular-seed](https://github.com/angular/angular-seed) 22 | - [paislee/healthy-gulp-angular](https://github.com/paislee/healthy-gulp-angular) 23 | - [lordkada/healthy-gulp-angular](https://github.com/lordkada/healthy-gulp-angular) 24 | - [Gregor Woiwode](https://github.com/GregOnNet) 25 | 26 | ## Features 27 | Beside the AngularJS demonstrations this package even contain a complete setup. 28 | Usable as template for future projects. 29 | Containing: 30 | - dependency loading and startup with [npm](http://npmjs.com) and [bower](http://bower.io) 31 | - better IDE support with [jshin](http://jshint.com) by [.jshintrc](https://github.com/jshint/jshint/blob/master/examples/.jshintrc) file 32 | - included simple development web-server with [node.js](http://nodejs.org) and [express](http://expressjs.com) 33 | - testing angular with [jasmin](https://jasmine.github.io) and [karma](https://karma-runner.github.io) 34 | - ui testing with [jasmin](https://jasmine.github.io) and [protractor](https://angular.github.io/protractor) 35 | - deployment build with [gulp](http://gulpjs.com) 36 | 37 | ## Requirements 38 | You need [node.js](http://nodejs.org) with [npm](http://npmjs.com) on your machine. 39 | For some automatically npm builds you will even need a version of [python](http://www.python.org) installed, but this is not necessary to run the app itself. 40 | 41 | ## Installation 42 | This app will install all required dependencies automatically. 43 | Just start the commands below in the root folder where you stored the package. 44 | ```SH 45 | $ npm install 46 | ``` 47 | 48 | ## Run Application and start development Server 49 | To run this app in your browser just start everything whit the comment below in the applications root folder. 50 | It will update everything an start a simple web server on ``http://localhost:1337/`` 51 | ```SH 52 | $ npm start 53 | ``` 54 | 55 | ## Run Tests 56 | All unit tests are performed with [jasmin](https://jasmine.github.io) and [karma](https://karma-runner.github.io) and can be configured in `karma.conf.js`. 57 | Predefined are dependencies for `PhantomJS`, `Firefox` and `Chrome`. 58 | On windows you may have to define the environment variables `FIREFOX_BIN` and `CHROME_BIN` to locate your browsers correctly. 59 | 60 | Run command below to execute all unit test: 61 | ```SH 62 | $ npm test 63 | ``` 64 | 65 | ## Run UI Tests 66 | All end-to-end tests are performed with [jasmin](https://jasmine.github.io) and [protractor](https://angular.github.io/protractor) and can be configures in `protractor.conf.js`. 67 | Make sure your development web-server and `webdriver-manager` is running. 68 | You will need three open shells to accomplish that. 69 | 70 | You can run test in different Browsers. 71 | By default of this package `Chrome` is predefined. 72 | On windows you my need to add the installation path of your browsers to the `PATH` environment variable. 73 | 74 | **Start Web-Server:** 75 | ```SH 76 | $ npm start 77 | ``` 78 | **Start Webdriver-Manager:** 79 | ```SH 80 | $ npm run start-webdriver 81 | ``` 82 | **Execute e2e tests:** 83 | ```SH 84 | $ npm run protractor 85 | ``` 86 | 87 | ## Build Application for Deployment 88 | Development and productive builds are handled by [gulp](http://gulpjs.com). 89 | There are a bunch of pre-defined task you can execute. 90 | To build a clean productive environment run the task below. 91 | The result will be stored unter `dist/productive/` 92 | ```SH 93 | $ gulp clean-build-app-prod 94 | ``` 95 | 96 | ## Why bower AND npm? 97 | It is possible to do everything by `package.json` over `npn`. 98 | But the idea is to split the dependencies in development and browser/client files. 99 | So `npm` contains everything for development, and `bower` defines the dependencies available to the user in browser. 100 | 101 | ## Bugs / Feature request 102 | Please [report](http://github.com/eisbehr-/angular-best-practice/issues) bugs and feel free to [ask](http://github.com/eisbehr-/angular-best-practice/issues) for new features directly on GitHub. 103 | --------------------------------------------------------------------------------