li {
19 | display: inline;
20 | }
21 |
22 | .menu > li:before {
23 | content: "|";
24 | padding-right: 0.3em;
25 | }
26 |
27 | .menu > li:nth-child(1):before {
28 | content: "";
29 | padding: 0;
30 | }
31 |
--------------------------------------------------------------------------------
/Labs/Unit Testing AngularJS Components/End/app/lib/jasmine/MIT.LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2008-2011 Pivotal Labs
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/Labs/Unit Testing AngularJS Components/End/app/lib/jasmine/jasmine_favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanWahlin/AngularJSEndToEndCourseCode/12cf7f9f1213e481fa1c140f761e7e766a555845/Labs/Unit Testing AngularJS Components/End/app/lib/jasmine/jasmine_favicon.png
--------------------------------------------------------------------------------
/Labs/Unit Testing AngularJS Components/End/app/reminders.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
20 |
21 | Angular Reminder App
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | Add
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | {{reminder}}
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/Labs/Unit Testing AngularJS Components/End/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 | // Generated on Sat Mar 22 2014 20:03:21 GMT-0700 (US Mountain Standard Time)
3 |
4 | module.exports = function(config) {
5 | config.set({
6 |
7 | // base path that will be used to resolve all patterns (eg. files, exclude)
8 | basePath: '',
9 |
10 |
11 | // frameworks to use
12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
13 | frameworks: ['jasmine'],
14 |
15 |
16 | // list of files / patterns to load in the browser
17 | files: [
18 | 'app/lib/angular.js',
19 | 'app/lib/angular-*.js',
20 | 'app/*.js',
21 | 'test/unit/*.js'
22 | ],
23 |
24 |
25 | // list of files to exclude
26 | exclude: [
27 |
28 | ],
29 |
30 |
31 | // preprocess matching files before serving them to the browser
32 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
33 | preprocessors: {
34 |
35 | },
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: ['progress'],
42 |
43 |
44 | // web server port
45 | port: 9876,
46 |
47 |
48 | // enable / disable colors in the output (reporters and logs)
49 | colors: true,
50 |
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 |
57 | // enable / disable watching file and executing tests whenever any file changes
58 | autoWatch: true,
59 |
60 |
61 | // start these browsers
62 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
63 | browsers: ['Chrome'],
64 |
65 |
66 | // Continuous Integration mode
67 | // if true, Karma captures browsers, runs the tests and exits
68 | singleRun: false
69 | });
70 | };
71 |
--------------------------------------------------------------------------------
/Labs/Unit Testing AngularJS Components/End/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "unit-testing",
3 | "description": "Unit Testing Demos",
4 | "devDependencies": {
5 | "phantomjs-prebuilt": "^2.1.14",
6 | "karma": "^1.5.0",
7 | "karma-jasmine": "^1.1.0",
8 | "karma-ng-scenario": "^1.0.0",
9 | "karma-chrome-launcher": "^2.0.0",
10 | "jasmine": "^2.5.3",
11 | "express": "^4.15.2"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Labs/Unit Testing AngularJS Components/End/server.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var app = express();
3 |
4 | app.use(express.static(__dirname));
5 |
6 | app.listen(8000);
7 | console.log('Listening on port 8000');
--------------------------------------------------------------------------------
/Labs/Unit Testing AngularJS Components/End/test/unit/controllersSpec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('ReminderController Test', function() {
4 | var scope, controller;
5 | var mockFactory = {
6 | reminders:['reminder1','reminder2'],
7 | get: function (){
8 | return this.reminders;
9 | },
10 | put:function(content){
11 | this.reminders.push(content);
12 | }
13 | };
14 |
15 | beforeEach(function() {
16 | module('reminderApp');
17 |
18 | inject(function($rootScope, $controller) {
19 | scope = $rootScope.$new();
20 | controller = $controller("ReminderController",
21 | {$scope: scope, reminderFactory:mockFactory });
22 | });
23 | });
24 | it('should return reminders array with 2 elements, add one,' +
25 | ' and return 3', function() {
26 | expect(scope.reminders.length).toBe(2);
27 | scope.reminder = "reminder3";
28 | scope.createReminder();
29 | expect(scope.reminders.length).toBe(3);
30 | });
31 |
32 |
33 |
34 | });
35 |
--------------------------------------------------------------------------------
/Labs/Unit Testing AngularJS Components/End/test/unit/servicesSpec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('reminderFactory tests', function (){
4 | var factory;
5 |
6 | //excuted before each "it" is run.
7 | beforeEach(function (){
8 |
9 | module('reminderApp');
10 |
11 | //inject factory for testing
12 | inject(function(reminderFactory) {
13 | factory = reminderFactory;
14 | });
15 |
16 | var store = {reminder1:'reminder1',reminder2:'reminder2',reminder3:'reminder3'};
17 |
18 | spyOn(localStorage, 'getItem').and.callFake(function (key) {
19 | return store[key];
20 | });
21 |
22 | spyOn(localStorage, 'setItem').and.callFake(function (key, value) {
23 | return store[key] = value + '';
24 | });
25 |
26 | spyOn(localStorage, 'clear').and.callFake(function () {
27 | store = {};
28 | });
29 |
30 | spyOn(Object, 'keys').and.callFake(function (key) {
31 | var keys=[];
32 | for(var key in store)
33 | keys.push(key);
34 | return keys;
35 | });
36 |
37 | });
38 |
39 | it('should have get and put functions', function () {
40 | expect(angular.isFunction(factory.get)).toBe(true);
41 | expect(angular.isFunction(factory.put)).toBe(true);
42 | });
43 |
44 | it('should return 3 reminders initially', function () {
45 | var result = factory.get();
46 | expect(result.length).toBe(3);
47 | });
48 |
49 | it('should return 4 reminders after adding one more', function () {
50 | factory.put('reminder4');
51 | var result = factory.get();
52 | expect(result.length).toBe(4);
53 | });
54 |
55 |
56 |
57 | });
58 |
--------------------------------------------------------------------------------
/Labs/Working with Controllers and Watches/Begin/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Using Watches in Controllers
5 |
6 |
7 |
8 |
9 |
Actions
10 |
11 |
12 |
13 |
14 | Assign New Customers
15 | Add Customer
16 | Edit Customer
17 |
18 |
19 |
20 |
24 |
25 |
--------------------------------------------------------------------------------
/Samples/AngularJSStarterDemo/app/views/customers.html:
--------------------------------------------------------------------------------
1 |
2 | Search:
3 |
4 |
Customers:
5 |
11 |
--------------------------------------------------------------------------------
/Samples/AngularJSStarterDemo/app/views/orders.html:
--------------------------------------------------------------------------------
1 | Orders
2 |
3 | CustomerID: {{ customerId }}
4 |
5 |
6 |
7 | Baseball
8 | $9.99
9 |
10 |
11 | Bat
12 | $19.99
13 |
14 |
15 |
16 |
17 |
18 | Customers
--------------------------------------------------------------------------------
/Samples/AngularJSStarterDemo/customers.json:
--------------------------------------------------------------------------------
1 | [
2 | {"id": 1, "name":"Ted", "total": 5.996},
3 | {"id": 2, "name":"Michelle", "total": 10.994},
4 | {"id": 3, "name":"Zed", "total": 10.99},
5 | {"id": 4, "name":"Tina", "total": 15.994}
6 | ]
--------------------------------------------------------------------------------
/Samples/AngularJSStarterDemo/index.html:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 | Angular App
18 |
19 |
20 |
21 | AngularJS in 20-ish Minutes
22 |
23 |
24 |
25 |
26 |
27 |
28 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/Samples/AngularJSStarterDemo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angularjs-app",
3 | "version": "1.0.0",
4 | "description": "Sample App",
5 | "author": "Dan Wahlin",
6 | "dependencies": {
7 | "express": "^4.15.2"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Samples/AngularJSStarterDemo/server.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var app = express();
3 |
4 | app.use(express.static(__dirname));
5 |
6 | app.listen(8000);
7 | console.log('Listening on port 8000');
--------------------------------------------------------------------------------
/Samples/AngularJSStarterDemo/snippets.js:
--------------------------------------------------------------------------------
1 | $scope.customers = [
2 | {"id": 1, "name":"Ted", "total": 5.996},
3 | {"id": 2, "name":"Michelle", "total": 10.994},
4 | {"id": 3, "name":"Zed", "total": 10.99},
5 | {"id": 4, "name":"Tina", "total": 15.994}
6 | ];
7 |
8 |
9 | app.config(function($routeProvider) {
10 | $routeProvider.when('/',
11 | {
12 | controller: 'CustomersController',
13 | templateUrl: 'app/views/customers.html'
14 | })
15 | .when('/orders',
16 | {
17 | controller: 'OrdersController',
18 | templateUrl: 'app/views/orders.html'
19 | })
20 | });
21 |
22 |
23 | app.factory('customersFactory', function($http) {
24 | var factory = {};
25 | factory.getCustomers = function() {
26 | return $http.get('/customers.json');
27 | };
28 | return factory;
29 | });
--------------------------------------------------------------------------------
/Samples/BroadcastAndEmit/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Broadcast and Emit
6 |
7 |
8 |
9 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | Root scope
MyEvent count: {{count}}
26 |
27 |
28 | $emit('MyEvent')
29 | $broadcast('MyEvent')
30 |
31 | Middle scope MyEvent count: {{count}}
32 |
33 |
34 | Leaf scope MyEvent count: {{count}}
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/Samples/Directives/compile.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Using Compile in a Directive
5 |
6 |
7 |
9 |
10 |
Using Compile in a Directive
11 | Open the console to see the output of compile, pre-link, and post-link.
12 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Samples/Directives/component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Component Demo
5 |
6 |
7 |
8 |
10 |
11 |
Using a Component
12 |
13 |
Parent Customers
14 |
17 |
18 |
Customer Component
19 | Note that changes in component update the parent...don't do this!
20 |
21 |
24 |
25 |
26 |
Customer Component (no changes in component)
27 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/Samples/Directives/controller.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Using a Controller in a Directive
5 |
6 |
7 |
8 |
10 |
11 | Parent Scope Customers:
12 |
13 |
14 |
15 |
Directive with Controller
16 | Attribute:
17 |
18 | Element:
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Samples/Directives/controllerAs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Using controllerAs in a Directive
5 |
6 |
7 |
8 |
10 |
11 | Parent Scope Customers:
12 |
13 |
14 |
15 |
Directive with Controller
16 | Attribute:
17 |
18 | Element:
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Samples/Directives/controllerNotUsed.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Directive without a Controller
5 |
6 |
7 |
8 |
10 |
11 | Parent Scope Customers:
12 |
13 |
14 |
15 |
Directive without a Controller (naive example)
16 | Attribute:
17 |
18 | Element:
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Samples/Directives/controllerPassingParameter1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Controller Passing a Parameter
5 |
6 |
7 |
8 |
10 |
11 | Parent Scope Customers:
12 |
13 |
14 |
15 |
Directive with Controller
16 | Attribute:
17 |
18 | Element:
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Samples/Directives/controllerPassingParameter2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Controller Passing a Parameter
5 |
6 |
7 |
8 |
10 |
11 | Parent Scope Customers:
12 |
13 |
14 |
15 |
Directive with Controller
16 | Attribute:
17 |
18 | Element:
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Samples/Directives/isolateScope.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Isolate Scope Directive
5 |
6 |
7 |
8 |
10 |
11 |
Isolate Scope Directive
12 | Directive output (no output since parent scope isn't shared)
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Samples/Directives/isolateScopeWithModel.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Isolate Scope Directive
5 |
6 |
7 |
8 |
10 |
11 |
Directive with Isolate Scope and Model (uses =)
12 | This relies on the "=" isolate scope property to pass data into the directive.
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/Samples/Directives/isolateScopeWithModelAndElement.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Isolate Scope Directive
5 |
6 |
7 |
8 |
10 |
11 |
Directive with isolate Scope and Model (uses = and restrict)
12 |
13 | Attribute:
14 |
15 |
16 |
17 | Element:
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Samples/Directives/isolateScopeWithModelAndEvent.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Isolate Scope Directive
5 |
6 |
7 |
8 |
10 |
11 |
Directive with isolate Scope, Model and Event
12 |
13 | Parent scope values: {{ customer.name }}, {{ customer.street }}
14 |
15 |
16 |
17 | This will call the controller's changeData() method from the directive.
18 |
19 |
20 |
21 | Attribute:
22 |
23 |
24 |
25 |
26 | Element:
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/Samples/Directives/isolateScopeWithModelEventAndArray.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Isolate Scope Directive
5 |
6 |
7 |
8 |
10 |
11 |
Directive with isolate Scope, Model, Event, and Array
12 |
13 | Parent Scope Customers:
14 |
15 |
16 |
17 |
18 | Attribute:
19 |
20 | Element:
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Samples/Directives/isolateScopeWithString.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Isolate Scope Directive
5 |
6 |
7 |
8 |
10 |
11 |
Directive with Isolate Scope and String Passed In (uses @)
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Samples/Directives/js/compileDirective.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var app = angular.module('directivesModule');
4 |
5 | app.directive('compileDirective', function () {
6 | return {
7 | restrict: 'A',
8 | compile: function(tElem, tAttrs) {
9 | console.log('Compile output: ' + tElem.html());
10 | console.log('');
11 | return {
12 | pre: function(scope, elem, attrs){
13 | console.log('\nPre link output: ' + elem.html());
14 | console.log('');
15 | },
16 | post: function(scope, elem, attrs){
17 | console.log('\nPost link output: ' + elem.html());
18 | console.log('');
19 | }
20 | }
21 | }
22 | };
23 | });
24 |
25 | }());
--------------------------------------------------------------------------------
/Samples/Directives/js/component.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | function CustomerDetailController() {
4 | var ctrl = this;
5 |
6 | ctrl.$onInit = function() {
7 | console.log('onInit called in component');
8 | console.log(ctrl.customer);
9 | };
10 |
11 | //Could add additional functionality here (functions to call for example)
12 | }
13 |
14 | angular.module('directivesModule')
15 | .component('customerDetail', {
16 |
17 | template: `
18 |
19 | Name:
20 | Change
21 |
22 | `,
23 | controller: CustomerDetailController,
24 | bindings: {
25 | customer: '<', //One-way binding (but be careful not to change data in comnponent)
26 | changeCustomer: '&' //Expression/function binding
27 | }
28 |
29 | });
30 |
31 | angular.module('directivesModule')
32 | .component('customerDetailNoChanges', {
33 |
34 | template: 'Name: {{ $ctrl.customer.name }}
',
35 | controller: CustomerDetailController,
36 | bindings: {
37 | customer: '<'
38 | }
39 |
40 | });
41 |
42 | }());
--------------------------------------------------------------------------------
/Samples/Directives/js/controllerAsDirective.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var app = angular.module('directivesModule');
4 |
5 | app.directive('controllerAs', function () {
6 |
7 | var controller = function () {
8 |
9 | var vm = this;
10 |
11 | function init() {
12 | //Create a copy of the original data that’s passed in
13 | vm.items = angular.copy(vm.datasource);
14 | }
15 |
16 | init();
17 |
18 | vm.addItem = function () {
19 | vm.add();
20 |
21 | //Add new customer to directive scope
22 | vm.items.push({
23 | name: 'New Directive Controller Item'
24 | });
25 | };
26 | };
27 |
28 | var template = 'Add Item ' +
29 | '';
30 |
31 | return {
32 | restrict: 'EA', //Default for 1.3+
33 | scope: {
34 | datasource: '=',
35 | add: '&',
36 | },
37 | controller: controller,
38 | controllerAs: 'vm',
39 | bindToController: true, //required in 1.3+ with controllerAs
40 | template: template
41 | };
42 | });
43 |
44 | }());
--------------------------------------------------------------------------------
/Samples/Directives/js/controllerDirective.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var app = angular.module('directivesModule');
4 |
5 | app.directive('controller', function () {
6 |
7 | var controller = ['$scope', function ($scope) {
8 |
9 | function init() {
10 | //Create a copy of the original data that’s passed in
11 | $scope.items = angular.copy($scope.datasource);
12 | }
13 |
14 | init();
15 |
16 | $scope.addItem = function () {
17 | $scope.add();
18 |
19 | //Add new customer to directive scope
20 | $scope.items.push({
21 | name: 'New Directive Controller Item'
22 | });
23 | };
24 | }],
25 |
26 | template = 'Add Item ' +
27 | '{{ ::item.name }} ';
28 |
29 | return {
30 | restrict: 'EA', //Default in 1.3+
31 | scope: {
32 | datasource: '=',
33 | add: '&',
34 | },
35 | controller: controller,
36 | template: template
37 | };
38 | });
39 |
40 | }());
--------------------------------------------------------------------------------
/Samples/Directives/js/controllerNotUsed.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var app = angular.module('directivesModule');
4 |
5 | app.directive('controllerNotUsed', function () {
6 |
7 | var link = function (scope, element, attrs) {
8 |
9 | //Create a copy of the original data that’s passed in
10 | var items = angular.copy(scope.datasource);
11 |
12 | function init() {
13 | var html = 'Add Item
';
14 | element.html(html);
15 |
16 | element.on('click', function(event) {
17 | if (event.srcElement.id === 'addItem') {
18 | addItem();
19 | event.preventDefault();
20 | }
21 | });
22 | }
23 |
24 | function addItem() {
25 | //Call external function passed in with &
26 | scope.add();
27 |
28 | //Add new customer to the local collection
29 | items.push({
30 | name: 'New Directive Customer'
31 | });
32 |
33 | render();
34 | }
35 |
36 | function render() {
37 | var html = '';
38 | for (var i=0,len=items.length;i' + items[i].name + ''
40 | }
41 | html += ' ';
42 |
43 | element.find('div').html(html);
44 | }
45 |
46 | init();
47 | render();
48 | };
49 |
50 |
51 | return {
52 | restrict: 'EA',
53 | scope: {
54 | datasource: '=',
55 | add: '&',
56 | },
57 | link: link
58 | };
59 | });
60 |
61 | }());
--------------------------------------------------------------------------------
/Samples/Directives/js/controllerPassingParameter1Directive.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var app = angular.module('directivesModule');
4 |
5 | app.directive('controllerPassingParameter1', function () {
6 | var controller = function () {
7 |
8 | var vm = this;
9 |
10 | function init() {
11 | vm.items = angular.copy(vm.datasource);
12 | }
13 | init();
14 |
15 | vm.addItem = function () {
16 | //Call external scope's function
17 | var name = 'New Customer Added by Directive';
18 | vm.add({name: name});
19 |
20 | //Add new item to directive scope
21 | vm.items.push({
22 | name: name
23 | });
24 | };
25 | },
26 |
27 | template = 'Add Item ' +
28 | '{{ ::item.name }} ';
29 |
30 | return {
31 | restrict: 'EA',
32 | scope: {
33 | datasource: '=',
34 | add: '&',
35 | },
36 | controller: controller,
37 | controllerAs: 'vm',
38 | bindToController: true,
39 | template: template
40 | };
41 | });
42 | }());
--------------------------------------------------------------------------------
/Samples/Directives/js/controllerPassingParameter2Directive.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var app = angular.module('directivesModule');
4 |
5 | app.directive('controllerPassingParameter2', function () {
6 | var controller = function () {
7 |
8 | var vm = this;
9 |
10 | function init() {
11 | vm.items = angular.copy(vm.datasource);
12 | }
13 | init();
14 |
15 | vm.addItem = function () {
16 | //Call external scope's function
17 | var name = 'New Customer Added by Directive';
18 | vm.add()(name);
19 |
20 | //Add new item to directive scope
21 | vm.items.push({
22 | name: name
23 | });
24 | };
25 | },
26 |
27 | template = 'Add Item ' +
28 | '{{ ::item.name }} ';
29 |
30 | return {
31 | restrict: 'EA',
32 | scope: {
33 | datasource: '=',
34 | add: '&',
35 | },
36 | controller: controller,
37 | controllerAs: 'vm',
38 | bindToController: true,
39 | template: template
40 | };
41 | });
42 | }());
--------------------------------------------------------------------------------
/Samples/Directives/js/directivesController.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var app = angular.module('directivesModule', []);
4 |
5 | var injectParams = ['$scope'];
6 |
7 | var CustomersController = function ($scope) {
8 | var counter = 0;
9 | $scope.tasks = [{ title: 'Task 1' }];
10 | $scope.customer = {
11 | name: 'David',
12 | street: '1234 Anywhere St.'
13 | };
14 |
15 | $scope.customers = [
16 | {
17 | name: 'David',
18 | street: '1234 Anywhere St.',
19 | age: 25,
20 | url: 'index.html'
21 | },
22 | {
23 | name: 'Tina',
24 | street: '1800 Crest St.',
25 | age: 35,
26 | url: 'index.html'
27 | },
28 | {
29 | name: 'Michelle',
30 | street: '890 Main St.',
31 | age: 29,
32 | url: 'index.html'
33 | },
34 | {
35 | name: 'John',
36 | street: '444 Cedar St.',
37 | age: 18,
38 | url: 'index.html'
39 | }
40 | ];
41 |
42 | $scope.addCustomer = function (name) {
43 | console.log(name);
44 | counter++;
45 | $scope.customers.push({
46 | name: (name) ? name : 'New Customer' + counter,
47 | street: counter + ' Cedar Point St.',
48 | age: counter
49 | });
50 | };
51 |
52 | $scope.changeData = function () {
53 | counter++;
54 | $scope.customer = {
55 | name: 'James',
56 | street: counter + ' Cedar Point St.'
57 | };
58 | };
59 |
60 | $scope.changeName = function(customer) {
61 | customer.name = 'foo';
62 | };
63 | };
64 |
65 | CustomersController.$inject = injectParams;
66 |
67 | app.controller('CustomersController', CustomersController);
68 |
69 | }());
--------------------------------------------------------------------------------
/Samples/Directives/js/isolateScopeDirective.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var app = angular.module('directivesModule');
4 |
5 | app.directive('isolateScope', function () {
6 | return {
7 | scope: {},
8 | template: 'Name: {{customer.name}} Street: {{customer.street}}'
9 | };
10 | });
11 |
12 | }());
--------------------------------------------------------------------------------
/Samples/Directives/js/isolateScopeWithModelAndElementDirective.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var app = angular.module('directivesModule');
4 |
5 | app.directive('isolateScopeWithModelAndElement', function () {
6 | return {
7 | restrict: 'EA', //Restrict to Element and Attribute
8 | scope: {
9 | datasource: '='
10 | },
11 | template: 'Name: {{datasource.name}} Street: {{datasource.street}}'
12 | };
13 | });
14 |
15 | }());
--------------------------------------------------------------------------------
/Samples/Directives/js/isolateScopeWithModelAndEventDirective.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var app = angular.module('directivesModule');
4 |
5 | app.directive('isolateScopeWithModelAndEvent', function () {
6 | return {
7 | restrict: 'EA',
8 | scope: {
9 | datasource: '=',
10 | click: '&'
11 | },
12 | template: 'Name: {{datasource.name}} Street: {{datasource.street}} Change Data '
13 | };
14 | });
15 |
16 | }());
--------------------------------------------------------------------------------
/Samples/Directives/js/isolateScopeWithModelDirective.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var app = angular.module('directivesModule');
4 |
5 | app.directive('isolateScopeWithModel', function () {
6 | return {
7 | scope: {
8 | datasource: '=' //Two-way data binding
9 | },
10 | template: 'Name: {{datasource.name}} Street: {{datasource.street}}'
11 | };
12 | });
13 |
14 | }());
--------------------------------------------------------------------------------
/Samples/Directives/js/isolateScopeWithModelEventAndArrayDirective.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var app = angular.module('directivesModule');
4 |
5 | app.directive('isolateScopeWithModelEventAndArray', function () {
6 | return {
7 | restrict: 'EA',
8 | scope: {
9 | datasource: '=',
10 | add: '&',
11 | },
12 | template: 'Change Data '
13 | };
14 | });
15 |
16 | }());
--------------------------------------------------------------------------------
/Samples/Directives/js/isolateScopeWithStringDirective.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var app = angular.module('directivesModule');
4 |
5 | app.directive('isolateScopeWithString', function () {
6 | return {
7 | scope: {
8 | name: '@' //Two-way data binding
9 | },
10 | template: 'Name: {{name}}'
11 | };
12 | });
13 |
14 | }());
--------------------------------------------------------------------------------
/Samples/Directives/js/lazyLoadDirective.js:
--------------------------------------------------------------------------------
1 | //Based upon the idea shown at https://www.youtube.com/watch?v=NlxqFADso6M
2 | (function() {
3 |
4 | var app = angular.module('directivesModule');
5 |
6 | app.directive('lazyLoad', ['$interpolate', function ($interpolate) {
7 |
8 | var compile = function(tElem, tAttrs) {
9 | var interpolateFunc = $interpolate(tAttrs.lazyLoad);
10 | tAttrs.$set('lazyLoad', null);
11 |
12 | return function(scope, elem, attrs) {
13 | elem.on(attrs.trigger, function(event) {
14 | var attr = attrs.attribute;
15 | if (!elem.attr(attr)) {
16 | var val = interpolateFunc(scope);
17 | elem.attr(attr, val);
18 | }
19 | });
20 | };
21 | };
22 |
23 | return {
24 | restrict: 'A',
25 | compile: compile
26 | };
27 | }]);
28 |
29 | }());
--------------------------------------------------------------------------------
/Samples/Directives/js/linkDirective.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var app = angular.module('directivesModule');
4 |
5 | app.directive('linkDirective', function () {
6 | return {
7 | restrict: 'A',
8 | link: function ($scope, element, attrs) {
9 | element.on('click', function () {
10 | element.html('You clicked me!');
11 | });
12 | element.on('mouseenter', function () {
13 | element.css('background-color', 'yellow');
14 | });
15 | element.on('mouseleave', function () {
16 | element.css('background-color', 'white');
17 | });
18 | }
19 | };
20 | });
21 |
22 | }());
--------------------------------------------------------------------------------
/Samples/Directives/js/mapGeoLocationDirective.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var app = angular.module('directivesModule', []);
4 |
5 | app.directive('mapGeoLocation', ['$window', function ($window) {
6 | var template = 'looking up geolocation...
' +
7 | '
',
8 | mapContainer = null,
9 | status = null;
10 |
11 | function link(scope, elem, attrs) {
12 | status = angular.element(document.getElementById('status'));
13 | mapContainer = angular.element(document.getElementById('map'));
14 |
15 | mapContainer.attr('style', 'height:' + scope.height + 'px;width:' + scope.width + 'px');
16 | $window.navigator.geolocation.getCurrentPosition(mapLocation, geoError);
17 | }
18 |
19 | function mapLocation(pos) {
20 | status.html('Found your location! Longitude: ' + pos.coords.longitude +
21 | ' Latitude: ' + pos.coords.latitude);
22 |
23 | var latlng = new google.maps.LatLng(pos.coords.latitude, pos.coords.longitude);
24 | var options = {
25 | zoom: 15,
26 | center: latlng,
27 | mapTypeControl: true,
28 | mapTypeId: google.maps.MapTypeId.ROADMAP
29 | };
30 |
31 | var map = new google.maps.Map(mapContainer[0], options);
32 |
33 | var marker = new google.maps.Marker({
34 | position: latlng,
35 | map: map,
36 | title:"Your location"
37 | });
38 | }
39 |
40 | function geoError(error) {
41 | status.html('failed lookup ' + error.message);
42 | }
43 |
44 | return {
45 | restrict: 'A',
46 | scope: {
47 | height: '@',
48 | width: '@'
49 | },
50 | link: link,
51 | template: template
52 | };
53 |
54 | }]);
55 |
56 | }());
--------------------------------------------------------------------------------
/Samples/Directives/js/sharedScopeDirective.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var app = angular.module('directivesModule');
4 |
5 | app.directive('sharedScope', function () {
6 | return {
7 | template: 'Name: {{customer.name}} Street: {{customer.street}}'
8 | };
9 | });
10 |
11 | }());
--------------------------------------------------------------------------------
/Samples/Directives/js/transclusionDirective.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var app = angular.module('directivesModule');
4 |
5 | app.directive('transclusion', function () {
6 | return {
7 | restrict: 'E',
8 | transclude: true,
9 | scope: {
10 | tasks: '='
11 | },
12 | controller: function ($scope) {
13 | $scope.addTask = function () {
14 |
15 | if (!$scope.tasks) $scope.tasks = [];
16 |
17 | $scope.tasks.push({
18 | title: $scope.title
19 | });
20 |
21 | };
22 | },
23 | template: 'Name:
' +
24 | '
Add Task ' +
25 | '
' +
26 | ' ' +
27 | '
'
28 | };
29 | });
30 |
31 | }());
--------------------------------------------------------------------------------
/Samples/Directives/lazyLoad.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Lazy Attribute Loader Directive
5 |
9 |
10 |
11 |
12 |
14 |
15 |
Lazy Attribute Loader
16 | The lazy-load directive will cause attribute values to be loaded when a specific trigger
17 | (such as mouseenter) fires.
18 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Samples/Directives/link.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Simple DOM Directive
5 |
6 |
7 |
8 |
10 |
11 |
Simple DOM Directive
12 | Mouse over the Click Me!.
13 |
Click Me!
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Samples/Directives/mapGeoLocation.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Geolocation Mapping Directive
5 |
6 |
7 |
8 | Geolocation Mapping Directive
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Samples/Directives/sharedScope.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Shared Scope Directive
5 |
6 |
7 |
9 |
10 |
Shared Scope Directive
11 | Directive output:
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/Samples/Directives/tableHelperController.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Table Helper DOM Directive
5 |
11 |
12 |
13 |
14 |
16 |
17 |
Table Helper DOM Directive
18 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Samples/Directives/tableHelperDOM.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Table Helper DOM Directive
5 |
12 |
13 |
14 |
15 |
17 |
18 |
Table Helper DOM Directive
19 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Samples/Directives/tableHelperDOMWithParse.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Table Helper DOM Directive with Parse
5 |
12 |
13 |
14 |
15 |
17 |
18 |
Table Helper DOM Directive with Parse
19 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Samples/Directives/tableHelperDomWithNgModel.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Table Helper DOM Directive
5 |
11 |
12 |
13 |
14 |
16 |
17 |
Table Helper DOM Directive
18 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Samples/Directives/transclusion.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Shared Scope Directive
5 |
6 |
7 |
8 |
10 |
11 |
Directive with Transclusion
12 |
13 |
14 |
15 | {{ task.title }}
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Samples/HybridSPADemo/.nuget/NuGet.Config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Samples/HybridSPADemo/.nuget/NuGet.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanWahlin/AngularJSEndToEndCourseCode/12cf7f9f1213e481fa1c140f761e7e766a555845/Samples/HybridSPADemo/.nuget/NuGet.exe
--------------------------------------------------------------------------------
/Samples/HybridSPADemo/HybridSPADemo.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.31101.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HybridSPADemo", "HybridSPADemo\HybridSPADemo.csproj", "{4CC4A2C2-2A1A-4B6F-9927-A6C29E8EC407}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{25726D2F-1E4C-4820-B98E-FD1FA7CE95A1}"
9 | ProjectSection(SolutionItems) = preProject
10 | .nuget\NuGet.Config = .nuget\NuGet.Config
11 | .nuget\NuGet.exe = .nuget\NuGet.exe
12 | .nuget\NuGet.targets = .nuget\NuGet.targets
13 | EndProjectSection
14 | EndProject
15 | Global
16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
17 | Debug|Any CPU = Debug|Any CPU
18 | Release|Any CPU = Release|Any CPU
19 | EndGlobalSection
20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
21 | {4CC4A2C2-2A1A-4B6F-9927-A6C29E8EC407}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
22 | {4CC4A2C2-2A1A-4B6F-9927-A6C29E8EC407}.Debug|Any CPU.Build.0 = Debug|Any CPU
23 | {4CC4A2C2-2A1A-4B6F-9927-A6C29E8EC407}.Release|Any CPU.ActiveCfg = Release|Any CPU
24 | {4CC4A2C2-2A1A-4B6F-9927-A6C29E8EC407}.Release|Any CPU.Build.0 = Release|Any CPU
25 | EndGlobalSection
26 | GlobalSection(SolutionProperties) = preSolution
27 | HideSolutionNode = FALSE
28 | EndGlobalSection
29 | EndGlobal
30 |
--------------------------------------------------------------------------------
/Samples/HybridSPADemo/HybridSPADemo/App_Start/RouteConfig.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Web;
5 | using System.Web.Mvc;
6 | using System.Web.Routing;
7 |
8 | namespace HybridSPADemo
9 | {
10 | public class RouteConfig
11 | {
12 | public static void RegisterRoutes(RouteCollection routes)
13 | {
14 | routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
15 |
16 | routes.MapRoute(
17 | name: "Default",
18 | url: "{controller}/{action}/{id}",
19 | defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
20 | );
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Samples/HybridSPADemo/HybridSPADemo/Controllers/ViewsController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Web;
5 | using System.Web.Mvc;
6 |
7 | namespace HybridSPADemo.Controllers
8 | {
9 | public class ViewsController : Controller
10 | {
11 | //
12 | // GET: /Views/
13 | public ActionResult Orders()
14 | {
15 | return View();
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/Samples/HybridSPADemo/HybridSPADemo/Global.asax:
--------------------------------------------------------------------------------
1 | <%@ Application Codebehind="Global.asax.cs" Inherits="HybridSPADemo.MvcApplication" Language="C#" %>
2 |
--------------------------------------------------------------------------------
/Samples/HybridSPADemo/HybridSPADemo/Global.asax.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Web;
5 | using System.Web.Mvc;
6 | using System.Web.Routing;
7 |
8 | namespace HybridSPADemo
9 | {
10 | public class MvcApplication : System.Web.HttpApplication
11 | {
12 | protected void Application_Start()
13 | {
14 | AreaRegistration.RegisterAllAreas();
15 | RouteConfig.RegisterRoutes(RouteTable.Routes);
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Samples/HybridSPADemo/HybridSPADemo/HybridSPADemo.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ProjectFiles
5 | True
6 | False
7 | False
8 |
9 | False
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | CurrentPage
18 | True
19 | False
20 | False
21 | False
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | True
31 | True
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/Samples/HybridSPADemo/HybridSPADemo/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("HybridSPADemo")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("HybridSPADemo")]
13 | [assembly: AssemblyCopyright("Copyright © 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("b34ef850-90b2-41b6-8561-36227cf47428")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Revision and Build Numbers
33 | // by using the '*' as shown below:
34 | [assembly: AssemblyVersion("1.0.0.0")]
35 | [assembly: AssemblyFileVersion("1.0.0.0")]
36 |
--------------------------------------------------------------------------------
/Samples/HybridSPADemo/HybridSPADemo/Views/Shared/_Layout.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | My Merrill
5 |
6 |
7 | @RenderBody()
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Samples/HybridSPADemo/HybridSPADemo/Views/Shared/_ViewsLayout.cshtml:
--------------------------------------------------------------------------------
1 | @RenderBody()
--------------------------------------------------------------------------------
/Samples/HybridSPADemo/HybridSPADemo/Views/Views/Orders.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | Layout = "~/Views/Shared/_ViewsLayout.cshtml";
3 | }
4 | Orders
5 | CustomerID: {{ customerId }}
6 |
7 |
8 | @for (int i = 0; i < 10; i++)
9 | {
10 |
11 | @i
12 |
13 | }
14 |
15 |
16 | Customers
17 |
18 |
--------------------------------------------------------------------------------
/Samples/HybridSPADemo/HybridSPADemo/Views/_ViewStart.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | Layout = "~/Views/Shared/_Layout.cshtml";
3 | }
--------------------------------------------------------------------------------
/Samples/HybridSPADemo/HybridSPADemo/Views/web.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/Samples/HybridSPADemo/HybridSPADemo/Web.Debug.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
17 |
18 |
29 |
30 |
--------------------------------------------------------------------------------
/Samples/HybridSPADemo/HybridSPADemo/Web.Release.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
17 |
18 |
19 |
30 |
31 |
--------------------------------------------------------------------------------
/Samples/HybridSPADemo/HybridSPADemo/Web.config:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Samples/HybridSPADemo/HybridSPADemo/app/views/customers.html:
--------------------------------------------------------------------------------
1 |
2 | Search:
3 |
4 |
Customers:
5 |
11 |
--------------------------------------------------------------------------------
/Samples/HybridSPADemo/HybridSPADemo/app/views/orders.html:
--------------------------------------------------------------------------------
1 | Orders
2 |
3 | CustomerID: {{ customerId }}
4 |
5 |
6 |
7 | Baseball
8 | $9.99
9 |
10 |
11 | Bat
12 | $19.99
13 |
14 |
15 |
16 |
17 |
18 | Customers
--------------------------------------------------------------------------------
/Samples/HybridSPADemo/HybridSPADemo/customers.txt:
--------------------------------------------------------------------------------
1 | [
2 | {"id": 1, "name":"Ted", "total": 5.996},
3 | {"id": 2, "name":"Michelle", "total": 10.994},
4 | {"id": 3, "name":"Zed", "total": 10.99},
5 | {"id": 4, "name":"Tina", "total": 15.994}
6 | ]
--------------------------------------------------------------------------------
/Samples/HybridSPADemo/HybridSPADemo/index.html:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 | Angular App
18 |
19 |
20 |
21 | AngularJS Hybrid SPA (1 view loaded from server)
22 |
23 |
24 |
25 |
26 |
27 |
28 |
69 |
70 |
--------------------------------------------------------------------------------
/Samples/HybridSPADemo/HybridSPADemo/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Samples/Pagination/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Client-Side Pagination
5 |
6 |
7 |
8 |
9 |
10 |
11 | {{customer.name}}
12 |
13 |
14 |
Previous
15 |
Next
16 |
17 | Page {{currentPage+1}} of {{totalPages}}
18 |
19 |
20 |
21 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/Samples/Routing/RoutingExample/Web.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Samples/Routing/RoutingExample/app/app.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var app = angular.module('demoApp',['ngRoute', 'ngAnimate']);
4 |
5 | app.config(function($routeProvider) {
6 | $routeProvider.when('/',
7 | {
8 | controller: 'CustomersController',
9 | templateUrl: 'app/views/customers.html',
10 | resolve: {
11 | customers: function (customersService) {
12 | return customersService.getCustomers();
13 | }
14 | }
15 | })
16 | .when('/orders/:customerId',
17 | {
18 | controller: 'OrdersController',
19 | templateUrl: '/app/views/orders.html',
20 | //templateUrl: 'templates/orders.html' //Load a local template
21 | caseInsensitiveMatch: true //Case doesn't matter for this route
22 | })
23 | .otherwise({ redirectTo: '/' });
24 | });
25 |
26 | }());
27 |
28 |
--------------------------------------------------------------------------------
/Samples/Routing/RoutingExample/app/controllers/customersController.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var CustomersController = function($scope, customers /* passed in by $routeProvider */) {
4 | $scope.customers = customers;
5 | };
6 |
7 | CustomersController.$inject = ['$scope', 'customers'];
8 |
9 | angular.module('demoApp').controller('CustomersController', CustomersController);
10 |
11 | }());
12 |
13 |
--------------------------------------------------------------------------------
/Samples/Routing/RoutingExample/app/controllers/ordersController.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var OrdersController = function($scope, $routeParams, ordersService) {
4 | $scope.customerId = $routeParams.customerId;
5 |
6 | function init() {
7 | ordersService.getCustomerOrders($scope.customerId).then(function (orders) {
8 | $scope.orders = orders;
9 | });
10 | }
11 |
12 | init();
13 | };
14 |
15 | OrdersController.$inject = ['$scope', '$routeParams', 'ordersService'];
16 |
17 | angular.module('demoApp').controller('OrdersController', OrdersController);
18 |
19 | }());
--------------------------------------------------------------------------------
/Samples/Routing/RoutingExample/app/services/customersService.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var customersFactory = function($http) {
4 | var factory = {};
5 |
6 | factory.getCustomers = function() {
7 | return $http.get('/customers.json').then(function (custs) {
8 | return custs.data;
9 | });
10 | };
11 |
12 | return factory;
13 | };
14 |
15 | customersFactory.$inject = ['$http'];
16 |
17 | angular.module('demoApp').factory('customersService', customersFactory);
18 |
19 | }());
--------------------------------------------------------------------------------
/Samples/Routing/RoutingExample/app/services/ordersService.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | var ordersFactory = function ($http) {
4 | var factory = {};
5 |
6 | factory.getCustomerOrders = function (id) {
7 | return $http.get('/orders.json').then(function (orders) {
8 | return orders.data;
9 | });
10 | };
11 |
12 | return factory;
13 | };
14 |
15 | ordersFactory.$inject = ['$http'];
16 |
17 | angular.module('demoApp').factory('ordersService', ordersFactory);
18 |
19 | }());
--------------------------------------------------------------------------------
/Samples/Routing/RoutingExample/app/views/customers.html:
--------------------------------------------------------------------------------
1 |
2 | Search:
3 |
4 |
Customers:
5 |
11 |
--------------------------------------------------------------------------------
/Samples/Routing/RoutingExample/app/views/orders.html:
--------------------------------------------------------------------------------
1 | Orders
2 |
3 | CustomerID: {{ customerId }}
4 |
5 |
6 |
7 | {{order.product}}
8 | {{order.total | currency}}
9 |
10 |
11 |
12 |
13 |
14 | Customers
--------------------------------------------------------------------------------
/Samples/Routing/RoutingExample/customers.json:
--------------------------------------------------------------------------------
1 | [
2 | {"id": 1, "name":"Ted", "total": 5.996},
3 | {"id": 2, "name":"Michelle", "total": 10.994},
4 | {"id": 3, "name":"Zed", "total": 10.99},
5 | {"id": 4, "name":"Tina", "total": 15.994}
6 | ]
--------------------------------------------------------------------------------
/Samples/Routing/RoutingExample/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Angular App
5 |
6 |
7 |
8 | Customers and Orders
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/Samples/Routing/RoutingExample/orders.json:
--------------------------------------------------------------------------------
1 | [
2 | {"id": 1, "product":"Golf Clubs", "total": 499.99},
3 | {"id": 2, "product": "Shirt", "total": 39.99},
4 | {"id": 3, "product":"Bicycle", "total": 299.99},
5 | {"id": 4, "product":"Hat", "total": 29.99}
6 | ]
--------------------------------------------------------------------------------
/Samples/Routing/RoutingExample/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-routing",
3 | "version": "1.0.0",
4 | "description": "Sample App",
5 | "author": "Dan Wahlin",
6 | "dependencies": {
7 | "express": "^4.15.2"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Samples/Routing/RoutingExample/server.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var app = express();
3 |
4 | app.use(express.static(__dirname));
5 |
6 | app.listen(8000);
7 | console.log('Listening on port 8000');
--------------------------------------------------------------------------------
/Samples/Routing/RoutingExample/snippets.js:
--------------------------------------------------------------------------------
1 | $scope.customers = [
2 | {"id": 1, "name":"Ted", "total": 5.996},
3 | {"id": 2, "name":"Michelle", "total": 10.994},
4 | {"id": 3, "name":"Zed", "total": 10.99},
5 | {"id": 4, "name":"Tina", "total": 15.994}
6 | ];
7 |
8 |
9 | app.config(function($routeProvider) {
10 | $routeProvider.when('/',
11 | {
12 | controller: 'CustomersController',
13 | templateUrl: 'app/views/customers.html'
14 | })
15 | .when('/orders',
16 | {
17 | controller: 'OrdersController',
18 | templateUrl: 'app/views/orders.html'
19 | })
20 | });
21 |
22 |
23 | app.factory('customersFactory', function($http) {
24 | var factory = {};
25 | factory.getCustomers = function() {
26 | return $http.get('/customers.json');
27 | };
28 | return factory;
29 | });
--------------------------------------------------------------------------------
/Samples/Routing/ui-router/README.md:
--------------------------------------------------------------------------------
1 | # Demonstration of AngularUI Router
2 |
3 | Code and demo for the scotch.io tutorial
4 |
5 | [AngularJS Routing Using UI-Router](http://scotch.io/tutorials/javascript/angular-routing-using-ui-router)
--------------------------------------------------------------------------------
/Samples/Routing/ui-router/colors-list.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Samples/Routing/ui-router/customer-details.html:
--------------------------------------------------------------------------------
1 | Selected Customer
2 |
3 | {{ selectedCustomer.name }}
--------------------------------------------------------------------------------
/Samples/Routing/ui-router/customers.html:
--------------------------------------------------------------------------------
1 |
2 |
Customers
3 |
This page demonstrates multiple and named views.
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Name
13 | Total
14 |
15 |
16 |
17 |
18 |
19 | {{ cust.name }}
20 | ${{ cust.total }}
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/Samples/Routing/ui-router/home.html:
--------------------------------------------------------------------------------
1 |
2 |
Home Page
3 |
This page demonstrates nested views.
4 |
5 |
Colors List
6 |
Description
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Samples/Routing/ui-router/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
17 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/Samples/Routing/ui-router/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-routing",
3 | "version": "1.0.0",
4 | "description": "Sample App",
5 | "author": "Dan Wahlin",
6 | "dependencies": {
7 | "express": "^4.15.2"
8 | },
9 | "scripts":{
10 | "start": "node server.js"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Samples/Routing/ui-router/server.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var app = express();
3 |
4 | app.use(express.static(__dirname));
5 |
6 | app.listen(8000);
7 | console.log('Listening on port 8000');
--------------------------------------------------------------------------------
/Samples/Scopes/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Example - example-example106-production
6 |
13 |
14 |
15 |
16 |
29 |
30 |
31 |
32 |
33 |
34 | {{name}}!
35 |
36 |
37 |
38 | {{name}}
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/Samples/UnitTesting/app/app.js:
--------------------------------------------------------------------------------
1 | var reminderApp=angular.module('reminderApp',[]);
2 |
3 | reminderApp.controller('ReminderController', function($scope,reminderFactory) {
4 |
5 | $scope.reminders = reminderFactory.get();
6 |
7 | $scope.$on("newReminder", function(event) {
8 | $scope.reminders = reminderFactory.get();
9 | });
10 |
11 |
12 | $scope.createReminder=function() {
13 | reminderFactory.put($scope.reminder);
14 | $scope.reminder = "";
15 | }
16 | });
17 |
18 | reminderApp.directive('customColor', function () {
19 | return {
20 | restrict: 'A',
21 | link: function (scope, elem, attrs) {
22 | elem.css({"background-color":attrs.customColor});
23 | }
24 | }
25 | });
26 |
27 | reminderApp.filter('truncate',function(){
28 | return function(input,length){
29 | return (input.length>length?input.substring(0,length):input);
30 | };
31 | });
32 |
33 | reminderApp.factory('reminderFactory',function($rootScope){
34 | return {
35 |
36 | get:function(){
37 | var reminders=[];
38 | var keys=Object.keys(localStorage);
39 | for(var i=0;i li {
19 | display: inline;
20 | }
21 |
22 | .menu > li:before {
23 | content: "|";
24 | padding-right: 0.3em;
25 | }
26 |
27 | .menu > li:nth-child(1):before {
28 | content: "";
29 | padding: 0;
30 | }
31 |
--------------------------------------------------------------------------------
/Samples/UnitTesting/app/lib/jasmine/MIT.LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2008-2011 Pivotal Labs
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/Samples/UnitTesting/app/lib/jasmine/jasmine_favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanWahlin/AngularJSEndToEndCourseCode/12cf7f9f1213e481fa1c140f761e7e766a555845/Samples/UnitTesting/app/lib/jasmine/jasmine_favicon.png
--------------------------------------------------------------------------------
/Samples/UnitTesting/app/reminders.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
19 |
20 | Angular Reminder App
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | Add
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | {{reminder | truncate:20}}
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/Samples/UnitTesting/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "unit-testing",
3 | "description": "Unit Testing Demos",
4 | "devDependencies": {
5 | "phantomjs": "^2.1.7",
6 | "karma": "^1.5.0",
7 | "karma-jasmine": "^1.1.0",
8 | "karma-ng-scenario": "^1.0.0",
9 | "karma-chrome-launcher": "^2.0.0",
10 | "jasmine": "^2.5.3",
11 | "express": "^4.15.2"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Samples/UnitTesting/server.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var app = express();
3 |
4 | app.use(express.static(__dirname));
5 |
6 | app.listen(8000);
7 | console.log('Listening on port 8000');
--------------------------------------------------------------------------------
/Samples/UnitTesting/test/karma.conf.js:
--------------------------------------------------------------------------------
1 | module.exports = function(config) {
2 |
3 | config.set({
4 | basePath : '../',
5 | frameworks: ['jasmine'],
6 |
7 | files : [
8 | 'app/lib/angular.js',
9 | 'app/lib/angular-*.js',
10 | 'app/*.js',
11 | 'test/unit/*.js'
12 | ],
13 |
14 | autoWatch : true,
15 |
16 | browsers : ['Chrome']
17 |
18 | });
19 |
20 | };
21 |
--------------------------------------------------------------------------------
/Samples/UnitTesting/test/unit/controllersSpec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('ReminderController Test', function() {
4 | var scope, controller;
5 | var mockFactory = {
6 | reminders:['reminder1','reminder2'],
7 | get: function (){
8 | return this.reminders;
9 | },
10 | put:function(content){
11 | this.reminders.push(content);
12 | }
13 | };
14 |
15 | beforeEach(function() {
16 | module('reminderApp');
17 | inject(function($rootScope, $controller) {
18 | scope = $rootScope.$new();
19 | controller = $controller("ReminderController", {$scope: scope, reminderFactory:mockFactory });
20 | });
21 | });
22 |
23 | it('should return reminders array with 2 elements, add one, and return 3', function() {
24 | expect(scope.reminders.length).toBe(2);
25 | scope.reminder = "reminder3";
26 | scope.createReminder();
27 | expect(scope.reminders.length).toBe(3);
28 | });
29 | });
--------------------------------------------------------------------------------
/Samples/UnitTesting/test/unit/directivesSpec.js:
--------------------------------------------------------------------------------
1 | describe('directive tests', function() {
2 | var scope, compile;
3 |
4 | beforeEach(function() {
5 | module('reminderApp');
6 | inject(function($rootScope, $compile) {
7 | scope = $rootScope.$new();
8 | compile = $compile;
9 | });
10 | });
11 |
12 | it('should set background to rgb(128, 128, 128)', function() {
13 | elem = angular.element("sample ");
14 |
15 | compile(elem)(scope);
16 |
17 | expect(elem.css("background-color")).toEqual('rgb(128, 128, 128)');
18 | });
19 | });
--------------------------------------------------------------------------------
/Samples/UnitTesting/test/unit/filtersSpec.js:
--------------------------------------------------------------------------------
1 | describe('filter tests', function() {
2 |
3 | beforeEach(function() {
4 | module('reminderApp');
5 | });
6 |
7 | it('should truncate the input to 10 characters', function() {
8 | inject(function(truncateFilter) {
9 | expect(truncateFilter('abcdefghijk',10).length).toBe(10);
10 | });
11 | });
12 | });
--------------------------------------------------------------------------------
/Samples/UnitTesting/test/unit/servicesSpec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('reminderFactory tests', function (){
4 | var factory;
5 |
6 | //excuted before each "it" is run.
7 | beforeEach(function (){
8 |
9 | module('reminderApp');
10 |
11 | //inject factory for testing
12 | inject(function(reminderFactory) {
13 | factory = reminderFactory;
14 | });
15 |
16 | var store = {reminder1:'reminder1',reminder2:'reminder2',reminder3:'reminder3'};
17 |
18 | spyOn(localStorage, 'getItem').and.callFake(function (key) {
19 | return store[key];
20 | });
21 | spyOn(localStorage, 'setItem').and.callFake(function (key, value) {
22 | return store[key] = value + '';
23 | });
24 | spyOn(localStorage, 'clear').and.callFake(function () {
25 | store = {};
26 | });
27 | spyOn(Object, 'keys').and.callFake(function (key) {
28 | var keys=[];
29 | for(var key in store)
30 | keys.push(key);
31 | return keys;
32 | });
33 |
34 | });
35 |
36 | it('should have get and put functions', function () {
37 | expect(angular.isFunction(factory.get)).toBe(true);
38 | expect(angular.isFunction(factory.put)).toBe(true);
39 | });
40 |
41 | it('should return 3 reminders initially', function (){
42 | var result = factory.get();
43 | expect(result.length).toBe(3);
44 | });
45 |
46 | it('should return 4 reminders after adding one more', function (){
47 | factory.put('reminder4');
48 | var result = factory.get();
49 | expect(result.length).toBe(4);
50 | });
51 |
52 | });
53 |
--------------------------------------------------------------------------------
/Samples/Watches/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Reference, Equality, and Collection Watches
5 |
6 |
7 |
{{item}}
8 |
9 |
10 | Reference Watch:
11 |
{{referenceCount}}
12 |
13 | Equality Watch:
14 |
{{equalityCount}}
15 |
16 | Collection Watch:
17 |
{{collectionCount}}
18 |
19 |
Add
20 |
21 |
22 |
23 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/Src/.nuget/NuGet.Config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Src/.nuget/NuGet.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanWahlin/AngularJSEndToEndCourseCode/12cf7f9f1213e481fa1c140f761e7e766a555845/Src/.nuget/NuGet.exe
--------------------------------------------------------------------------------
/Src/CustomerManager.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.30110.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomerManager", "CustomerManager\CustomerManager.csproj", "{9070F180-9D2C-44CD-86C7-0EFB3918D2F0}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{AF7DC5C3-E97F-4405-B681-D13A4FF7DCF3}"
9 | ProjectSection(SolutionItems) = preProject
10 | .nuget\NuGet.Config = .nuget\NuGet.Config
11 | .nuget\NuGet.exe = .nuget\NuGet.exe
12 | .nuget\NuGet.targets = .nuget\NuGet.targets
13 | EndProjectSection
14 | EndProject
15 | Global
16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
17 | Debug|Any CPU = Debug|Any CPU
18 | Release|Any CPU = Release|Any CPU
19 | EndGlobalSection
20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
21 | {9070F180-9D2C-44CD-86C7-0EFB3918D2F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
22 | {9070F180-9D2C-44CD-86C7-0EFB3918D2F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
23 | {9070F180-9D2C-44CD-86C7-0EFB3918D2F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
24 | {9070F180-9D2C-44CD-86C7-0EFB3918D2F0}.Release|Any CPU.Build.0 = Release|Any CPU
25 | {CEE64AD2-A800-49D8-8A30-06CAFB902397}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26 | {CEE64AD2-A800-49D8-8A30-06CAFB902397}.Debug|Any CPU.Build.0 = Debug|Any CPU
27 | {CEE64AD2-A800-49D8-8A30-06CAFB902397}.Release|Any CPU.ActiveCfg = Release|Any CPU
28 | {CEE64AD2-A800-49D8-8A30-06CAFB902397}.Release|Any CPU.Build.0 = Release|Any CPU
29 | EndGlobalSection
30 | GlobalSection(SolutionProperties) = preSolution
31 | HideSolutionNode = FALSE
32 | EndGlobalSection
33 | EndGlobal
34 |
--------------------------------------------------------------------------------
/Src/CustomerManager/App_Start/BreezeWebApiConfig.cs:
--------------------------------------------------------------------------------
1 | using System.Web.Http;
2 |
3 | [assembly: WebActivator.PreApplicationStartMethod(
4 | typeof(CustomerManager.App_Start.BreezeWebApiConfig), "RegisterBreezePreStart")]
5 | namespace CustomerManager.App_Start {
6 | ///
7 | /// Inserts the Breeze Web API controller route at the front of all Web API routes
8 | ///
9 | ///
10 | /// This class is discovered and run during startup; see
11 | /// http://blogs.msdn.com/b/davidebb/archive/2010/10/11/light-up-your-nupacks-with-startup-code-and-webactivator.aspx
12 | ///
13 | public static class BreezeWebApiConfig {
14 |
15 | public static void RegisterBreezePreStart() {
16 | GlobalConfiguration.Configuration.Routes.MapHttpRoute(
17 | name: "BreezeApi",
18 | routeTemplate: "breeze/{controller}/{action}"
19 | );
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/Src/CustomerManager/App_Start/WebApiConfig.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Serialization;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Web;
7 | using System.Web.Http;
8 | using System.Web.Http.Controllers;
9 |
10 | namespace CustomerManager.App_Start
11 | {
12 | public static class WebApiConfig
13 | {
14 | public static void Register(HttpConfiguration config)
15 | {
16 | config.Routes.MapHttpRoute(
17 | name: "DefaultApi",
18 | routeTemplate: "api/{controller}/{action}/{id}",
19 | defaults: new { id = RouteParameter.Optional }
20 | );
21 |
22 | config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
23 | config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
24 |
25 | // Remove default XML handler
26 | var matches = config.Formatters
27 | .Where(f => f.SupportedMediaTypes
28 | .Where(m => m.MediaType.ToString() == "application/xml" ||
29 | m.MediaType.ToString() == "text/xml")
30 | .Count() > 0)
31 | .ToList();
32 | foreach (var match in matches)
33 | config.Formatters.Remove(match);
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/Src/CustomerManager/Content/animations.css:
--------------------------------------------------------------------------------
1 | /* Animations */
2 | .slide-animation-container {
3 | position:relative;
4 | }
5 |
6 | .slide-animation.ng-enter, .slide-animation.ng-leave {
7 | -moz-transition: 0.5s linear all;
8 | -o-transition: 0.5s linear all;
9 | -webkit-transition: 0.5s linear all;
10 | transition: 0.5s linear all;
11 | position: relative;
12 | /*top: 0;
13 | left: 0;
14 | right: 0;*/
15 | height: 1000px;
16 | }
17 |
18 | .slide-animation.ng-enter {
19 | z-index:100;
20 | left:100px;
21 | opacity:0;
22 | }
23 |
24 | .slide-animation.ng-enter.ng-enter-active {
25 | left:0;
26 | opacity:1;
27 | }
28 |
29 | .slide-animation.ng-leave {
30 | z-index:101;
31 | opacity:1;
32 | left:0;
33 | }
34 |
35 | .slide-animation.ng-leave.ng-leave-active {
36 | left:-100px;
37 | opacity:0;
38 | }
39 |
40 | body.skip-animations * {
41 | -webkit-transition:none!important;
42 | -moz-transition:none!important;
43 | -o-transition:none!important;
44 | transition:none!important;
45 | }
46 |
47 | .show-hide-animation.ng-hide-add,
48 | .show-hide-animation.ng-hide-remove {
49 | -webkit-transition:all linear 0.3s;
50 | -moz-transition:all linear 0.3s;
51 | -o-transition:all linear 0.3s;
52 | transition:all linear 0.3s;
53 | display:block!important;
54 | height: 1000px;
55 | }
56 |
57 | .show-hide-animation.ng-hide-remove {
58 | opacity:0;
59 | }
60 | .show-hide-animation.ng-hide-remove.ng-hide-remove-active {
61 | opacity:1;
62 | }
63 | .show-hide-animation.ng-hide-add {
64 | opacity:1;
65 | }
66 | .show-hide-animation.ng-hide-add.ng-hide-add-active {
67 | opacity:0;
68 | }
69 |
70 | .repeat-animation.ng-enter,
71 | .repeat-animation.ng-leave,
72 | .repeat-animation.ng-move {
73 | -webkit-transition: 0.5s linear all;
74 | -moz-transition: 0.5s linear all;
75 | -o-transition: 0.5s linear all;
76 | transition: 0.5s linear all;
77 | position:relative;
78 | }
79 |
80 | .repeat-animation.ng-enter {
81 | left:10px;
82 | opacity:0;
83 | }
84 | .repeat-animation.ng-enter.ng-enter-active {
85 | left:0;
86 | opacity:1;
87 | }
88 |
89 | .repeat-animation.ng-leave {
90 | left:10px;
91 | opacity:1;
92 | }
93 | .repeat-animation.ng-leave.ng-leave-active {
94 | left:-10px;
95 | opacity:0;
96 | }
97 |
98 | .repeat-animation.ng-move {
99 | opacity:0.5;
100 | }
101 | .repeat-animation.ng-move.ng-move-active {
102 | opacity:1;
103 | }
--------------------------------------------------------------------------------
/Src/CustomerManager/Content/images/ColorPalette.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanWahlin/AngularJSEndToEndCourseCode/12cf7f9f1213e481fa1c140f761e7e766a555845/Src/CustomerManager/Content/images/ColorPalette.png
--------------------------------------------------------------------------------
/Src/CustomerManager/Content/images/CourseLogoYellow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanWahlin/AngularJSEndToEndCourseCode/12cf7f9f1213e481fa1c140f761e7e766a555845/Src/CustomerManager/Content/images/CourseLogoYellow.png
--------------------------------------------------------------------------------
/Src/CustomerManager/Content/images/angularShield.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanWahlin/AngularJSEndToEndCourseCode/12cf7f9f1213e481fa1c140f761e7e766a555845/Src/CustomerManager/Content/images/angularShield.png
--------------------------------------------------------------------------------
/Src/CustomerManager/Content/images/appFolders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanWahlin/AngularJSEndToEndCourseCode/12cf7f9f1213e481fa1c140f761e7e766a555845/Src/CustomerManager/Content/images/appFolders.png
--------------------------------------------------------------------------------
/Src/CustomerManager/Content/images/customerApp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanWahlin/AngularJSEndToEndCourseCode/12cf7f9f1213e481fa1c140f761e7e766a555845/Src/CustomerManager/Content/images/customerApp.png
--------------------------------------------------------------------------------
/Src/CustomerManager/Content/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanWahlin/AngularJSEndToEndCourseCode/12cf7f9f1213e481fa1c140f761e7e766a555845/Src/CustomerManager/Content/images/favicon.ico
--------------------------------------------------------------------------------
/Src/CustomerManager/Content/images/female.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanWahlin/AngularJSEndToEndCourseCode/12cf7f9f1213e481fa1c140f761e7e766a555845/Src/CustomerManager/Content/images/female.png
--------------------------------------------------------------------------------
/Src/CustomerManager/Content/images/male.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanWahlin/AngularJSEndToEndCourseCode/12cf7f9f1213e481fa1c140f761e7e766a555845/Src/CustomerManager/Content/images/male.png
--------------------------------------------------------------------------------
/Src/CustomerManager/Content/images/people.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanWahlin/AngularJSEndToEndCourseCode/12cf7f9f1213e481fa1c140f761e7e766a555845/Src/CustomerManager/Content/images/people.png
--------------------------------------------------------------------------------
/Src/CustomerManager/Content/images/report.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanWahlin/AngularJSEndToEndCourseCode/12cf7f9f1213e481fa1c140f761e7e766a555845/Src/CustomerManager/Content/images/report.png
--------------------------------------------------------------------------------
/Src/CustomerManager/Content/images/spinner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanWahlin/AngularJSEndToEndCourseCode/12cf7f9f1213e481fa1c140f761e7e766a555845/Src/CustomerManager/Content/images/spinner.gif
--------------------------------------------------------------------------------
/Src/CustomerManager/CustomerManager.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ProjectFiles
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | SpecificPage
13 | True
14 | False
15 | False
16 | False
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | False
26 | True
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/Src/CustomerManager/Global.asax:
--------------------------------------------------------------------------------
1 | <%@ Application Codebehind="Global.asax.cs" Inherits="CustomerManager.Global" Language="C#" %>
2 |
--------------------------------------------------------------------------------
/Src/CustomerManager/Global.asax.cs:
--------------------------------------------------------------------------------
1 | using CustomerManager.App_Start;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Web;
6 | using System.Web.Http;
7 | using System.Web.Security;
8 | using System.Web.SessionState;
9 |
10 | namespace CustomerManager
11 | {
12 | public class Global : System.Web.HttpApplication
13 | {
14 |
15 | protected void Application_Start(object sender, EventArgs e)
16 | {
17 | WebApiConfig.Register(GlobalConfiguration.Configuration);
18 | }
19 |
20 | protected void Session_Start(object sender, EventArgs e)
21 | {
22 |
23 | }
24 |
25 | protected void Application_BeginRequest(object sender, EventArgs e)
26 | {
27 |
28 | }
29 |
30 | protected void Application_AuthenticateRequest(object sender, EventArgs e)
31 | {
32 |
33 | }
34 |
35 | protected void Application_Error(object sender, EventArgs e)
36 | {
37 |
38 | }
39 |
40 | protected void Session_End(object sender, EventArgs e)
41 | {
42 |
43 | }
44 |
45 | protected void Application_End(object sender, EventArgs e)
46 | {
47 |
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/Src/CustomerManager/Model/Customer.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Converters;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.ComponentModel.DataAnnotations;
6 | using System.Linq;
7 | using System.Web;
8 |
9 | namespace CustomerManager.Model
10 | {
11 | public class Customer
12 | {
13 | public int Id { get; set; }
14 | [StringLength(50)]
15 | public string FirstName { get; set; }
16 | [StringLength(50)]
17 | public string LastName { get; set; }
18 | [StringLength(100)]
19 | public string Email { get; set; }
20 | [StringLength(1000)]
21 | public string Address { get; set; }
22 | [StringLength(50)]
23 | public string City { get; set; }
24 | public State State { get; set; }
25 | public int StateId { get; set; }
26 | public int Zip { get; set; }
27 | [JsonConverter(typeof(StringEnumConverter))]
28 | public Gender Gender { get; set; }
29 | public ICollection Orders { get; set; }
30 | }
31 |
32 | public enum Gender
33 | {
34 | Female,
35 | Male
36 | }
37 | }
--------------------------------------------------------------------------------
/Src/CustomerManager/Model/CustomerSummary.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Converters;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Web;
7 |
8 | namespace CustomerManager.Model
9 | {
10 | public class CustomerSummary
11 | {
12 | public int Id { get; set; }
13 | public string FirstName { get; set; }
14 | public string LastName { get; set; }
15 | public string City { get; set; }
16 | public State State { get; set; }
17 | public int OrderCount { get; set; }
18 | [JsonConverter(typeof(StringEnumConverter))]
19 | public Gender Gender { get; set; }
20 | }
21 | }
--------------------------------------------------------------------------------
/Src/CustomerManager/Model/OperationStatus.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 |
4 | namespace CustomerManager.Model
5 | {
6 | [DebuggerDisplay("Status: {Status}")]
7 | public class OperationStatus
8 | {
9 | public bool Status { get; set; }
10 | public int RecordsAffected { get; set; }
11 | public string Message { get; set; }
12 | public Object OperationId { get; set; }
13 | public string ExceptionMessage { get; set; }
14 | public string ExceptionStackTrace { get; set; }
15 | public string ExceptionInnerMessage { get; set; }
16 | public string ExceptionInnerStackTrace { get; set; }
17 |
18 | public static OperationStatus CreateFromException(string message, Exception ex)
19 | {
20 | OperationStatus opStatus = new OperationStatus
21 | {
22 | Status = false,
23 | Message = message,
24 | OperationId = null
25 | };
26 |
27 | if (ex != null)
28 | {
29 | opStatus.ExceptionMessage = ex.Message;
30 | opStatus.ExceptionStackTrace = ex.StackTrace;
31 | opStatus.ExceptionInnerMessage = (ex.InnerException == null) ? null : ex.InnerException.Message;
32 | opStatus.ExceptionInnerStackTrace = (ex.InnerException == null) ? null : ex.InnerException.StackTrace;
33 | }
34 | return opStatus;
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Src/CustomerManager/Model/Order.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Web;
6 |
7 | namespace CustomerManager.Model
8 | {
9 | public class Order
10 | {
11 | public int Id { get; set; }
12 | [StringLength(50)]
13 | public string Product { get; set; }
14 | public decimal Price { get; set; }
15 | public int Quantity { get; set; }
16 | public DateTime Date { get; set; }
17 | public int CustomerId { get; set; }
18 | public Customer Customer { get; set; }
19 |
20 | public Order Clone()
21 | {
22 | return (Order)this.MemberwiseClone();
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/Src/CustomerManager/Model/State.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Web;
6 |
7 | namespace CustomerManager.Model
8 | {
9 | public class State
10 | {
11 | public int Id { get; set; }
12 | [StringLength(2)]
13 | public string Abbreviation { get; set; }
14 | [StringLength(25)]
15 | public string Name { get; set; }
16 | }
17 | }
--------------------------------------------------------------------------------
/Src/CustomerManager/Model/UserLogin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Web;
5 |
6 | namespace CustomerManager.Model
7 | {
8 | public class UserLogin
9 | {
10 | public string UserName { get; set; }
11 | public string Password { get; set; }
12 | }
13 | }
--------------------------------------------------------------------------------
/Src/CustomerManager/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("CustomerManager")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("CustomerManager")]
13 | [assembly: AssemblyCopyright("Copyright © 2013 Dan Wahlin")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("eebd9beb-e961-491f-a5e0-faa188f37e32")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Revision and Build Numbers
33 | // by using the '*' as shown below:
34 | [assembly: AssemblyVersion("1.0.0.0")]
35 | [assembly: AssemblyFileVersion("1.0.0.0")]
36 |
--------------------------------------------------------------------------------
/Src/CustomerManager/Repository/CustomerManagerContext.cs:
--------------------------------------------------------------------------------
1 | using CustomerManager.Model;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Configuration;
5 | using System.Data.Entity;
6 | using System.Linq;
7 | using System.Web;
8 |
9 | namespace CustomerManager.Repository
10 | {
11 | public class CustomerManagerContext : DbContext
12 | {
13 | public CustomerManagerContext()
14 | {
15 | Configuration.ProxyCreationEnabled = false;
16 | Configuration.LazyLoadingEnabled = false;
17 | }
18 |
19 | // DEVELOPMENT ONLY: initialize the database
20 | static CustomerManagerContext()
21 | {
22 | Database.SetInitializer(new CustomerManagerDatabaseInitializer());
23 | }
24 |
25 | public DbSet Customers { get; set; }
26 | public DbSet Orders { get; set; }
27 | public DbSet States { get; set; }
28 | }
29 | }
--------------------------------------------------------------------------------
/Src/CustomerManager/Repository/CustomerManagerDatabaseInitializer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Data.Entity;
4 | using System.Linq;
5 | using System.Text;
6 |
7 | namespace CustomerManager.Repository
8 | {
9 | ////DropCreateDatabaseIfModelChanges
10 | public class CustomerManagerDatabaseInitializer : DropCreateDatabaseAlways // re-creates every time the server starts
11 | {
12 | protected override void Seed(CustomerManagerContext context)
13 | {
14 | DataInitializer.Initialize(context);
15 | base.Seed(context);
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Src/CustomerManager/Web.Debug.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
17 |
18 |
29 |
30 |
--------------------------------------------------------------------------------
/Src/CustomerManager/Web.Release.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
17 |
18 |
19 |
30 |
31 |
--------------------------------------------------------------------------------
/Src/CustomerManager/app/customersApp/animations/listAnimations.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var wcAnimations = function () {
4 | var duration = 0.5;
5 | return {
6 | enter: function (element, done) {
7 | var random = Math.random() * 100;
8 | TweenMax.set(element, { opacity: 0, left: random + 'px' });
9 |
10 | var random2 = Math.random();
11 | TweenMax.to(element, duration, { opacity: 1, left: '0px', ease: Back.easeInOut, delay: random2, onComplete: done });
12 | },
13 | leave: function (element, done) {
14 | TweenMax.to(element, duration, { opacity: 0, left: '-50px', onComplete: done });
15 | }
16 | };
17 | };
18 |
19 | angular.module('customersApp').animation('.card-animation', wcAnimations);
20 |
21 | }());
22 |
--------------------------------------------------------------------------------
/Src/CustomerManager/app/customersApp/controllers/aboutController.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | var injectParams = [];
4 |
5 | var AboutController = function () {
6 |
7 | };
8 |
9 | AboutController.$inject = injectParams;
10 |
11 | angular.module('customersApp').controller('AboutController', AboutController);
12 |
13 | }());
--------------------------------------------------------------------------------
/Src/CustomerManager/app/customersApp/controllers/customers/customerOrdersController.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | var injectParams = ['$scope','$routeParams', '$window', 'dataService'];
4 |
5 | var CustomerOrdersController = function ($scope, $routeParams, $window, dataService) {
6 | var vm = this,
7 | customerId = ($routeParams.customerId) ? parseInt($routeParams.customerId) : 0;
8 |
9 | vm.customer = {};
10 | vm.ordersTotal = 0.00;
11 |
12 | init();
13 |
14 | function init() {
15 | if (customerId > 0) {
16 | dataService.getCustomer(customerId)
17 | .then(function (customer) {
18 | vm.customer = customer;
19 | $scope.$broadcast('customer', customer);
20 | }, function (error) {
21 | $window.alert("Sorry, an error occurred: " + error.message);
22 | });
23 | }
24 | }
25 | };
26 |
27 | CustomerOrdersController.$inject = injectParams;
28 |
29 | angular.module('customersApp').controller('CustomerOrdersController', CustomerOrdersController);
30 |
31 | }());
--------------------------------------------------------------------------------
/Src/CustomerManager/app/customersApp/controllers/loginController.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | var injectParams = ['$location', '$routeParams', 'authService'];
4 |
5 | var LoginController = function ($location, $routeParams, authService) {
6 | var vm = this,
7 | path = '/';
8 |
9 | vm.email = null;
10 | vm.password = null;
11 | vm.errorMessage = null;
12 |
13 | vm.login = function () {
14 | authService.login(vm.email, vm.password).then(function (status) {
15 | //$routeParams.redirect will have the route
16 | //they were trying to go to initially
17 | if (!status) {
18 | vm.errorMessage = 'Unable to login';
19 | return;
20 | }
21 |
22 | if (status && $routeParams && $routeParams.redirect) {
23 | path = path + $routeParams.redirect;
24 | }
25 |
26 | $location.path(path);
27 | });
28 | };
29 | };
30 |
31 | LoginController.$inject = injectParams;
32 |
33 | angular.module('customersApp')
34 | .controller('LoginController', LoginController);
35 |
36 | }());
--------------------------------------------------------------------------------
/Src/CustomerManager/app/customersApp/controllers/navbarController.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | var injectParams = ['$scope', '$location', 'config', 'authService'];
4 |
5 | var NavbarController = function ($scope, $location, config, authService) {
6 | var vm = this,
7 | appTitle = 'Customer Management';
8 |
9 | vm.isCollapsed = false;
10 | vm.appTitle = (config.useBreeze) ? appTitle + ' Breeze' : appTitle;
11 |
12 | vm.highlight = function (path) {
13 | return $location.path().substr(0, path.length) === path;
14 | };
15 |
16 | vm.loginOrOut = function () {
17 | setLoginLogoutText();
18 | var isAuthenticated = authService.user.isAuthenticated;
19 | if (isAuthenticated) { //logout
20 | authService.logout().then(function () {
21 | $location.path('/');
22 | return;
23 | });
24 | }
25 | redirectToLogin();
26 | };
27 |
28 | function redirectToLogin() {
29 | var path = '/login' + $location.$$path;
30 | $location.replace();
31 | $location.path(path);
32 | }
33 |
34 | $scope.$on('loginStatusChanged', function (loggedIn) {
35 | setLoginLogoutText(loggedIn);
36 | });
37 |
38 | $scope.$on('redirectToLogin', function () {
39 | redirectToLogin();
40 | });
41 |
42 | function setLoginLogoutText() {
43 | vm.loginLogoutText = (authService.user.isAuthenticated) ? 'Logout' : 'Login';
44 | }
45 |
46 | setLoginLogoutText();
47 |
48 | };
49 |
50 | NavbarController.$inject = injectParams;
51 |
52 | angular.module('customersApp').controller('NavbarController', NavbarController);
53 |
54 | }());
55 |
--------------------------------------------------------------------------------
/Src/CustomerManager/app/customersApp/controllers/orders/orderChildController.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var injectParams = ['$scope'];
4 |
5 | var OrderChildController = function ($scope) {
6 | var vm = this;
7 |
8 | vm.orderby = 'product';
9 | vm.reverse = false;
10 | vm.ordersTotal = 0.00;
11 | vm.customer;
12 |
13 | init();
14 |
15 | vm.setOrder = function (orderby) {
16 | if (orderby === vm.orderby) {
17 | vm.reverse = !vm.reverse;
18 | }
19 | vm.orderby = orderby;
20 | };
21 |
22 | function init() {
23 | if ($scope.customer) {
24 | vm.customer = $scope.customer;
25 | updateTotal($scope.customer);
26 | }
27 | else {
28 | $scope.$on('customer', function (event, customer) {
29 | vm.customer = customer;
30 | updateTotal(customer);
31 | });
32 | }
33 | }
34 |
35 | function updateTotal(customer) {
36 | var total = 0.00;
37 | for (var i = 0; i < customer.orders.length; i++) {
38 | var order = customer.orders[i];
39 | total += order.orderTotal;
40 | }
41 | vm.ordersTotal = total;
42 | }
43 | };
44 |
45 | OrderChildController.$inject = injectParams;
46 |
47 | angular.module('customersApp').controller('OrderChildController', OrderChildController);
48 |
49 | }());
--------------------------------------------------------------------------------
/Src/CustomerManager/app/customersApp/controllers/orders/ordersController.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | var injectParams = ['$filter', '$window', 'dataService'];
4 |
5 | var OrdersController = function ($filter, $window, dataService) {
6 | var vm = this;
7 |
8 | vm.customers = [];
9 | vm.filteredCustomers;
10 | vm.filteredCount;
11 |
12 | //paging
13 | vm.totalRecords = 0;
14 | vm.pageSize = 10;
15 | vm.currentPage = 1;
16 |
17 | init();
18 |
19 | vm.pageChanged = function () {
20 | getCustomers();
21 | };
22 |
23 | vm.searchTextChanged = function () {
24 | filterCustomersProducts(vm.searchText);
25 | };
26 |
27 | function init() {
28 | //createWatches();
29 | getCustomers();
30 | }
31 |
32 | //function createWatches() {
33 | // //Watch searchText value and pass it and the customers to nameCityStateFilter
34 | // //Doing this instead of adding the filter to ng-repeat allows it to only be run once (rather than twice)
35 | // //while also accessing the filtered count via vm.filteredCount above
36 |
37 | // //Better to handle this using ng-change on . See searchTextChanged() function.
38 | // $scope.$watch("searchText", function (filterText) {
39 | // filterCustomersProducts(filterText);
40 | // });
41 | //}
42 |
43 | function filterCustomersProducts(filterText) {
44 | vm.filteredCustomers = $filter("nameProductFilter")(vm.customers, filterText);
45 | vm.filteredCount = vm.filteredCustomers.length;
46 | }
47 |
48 | function getCustomers() {
49 | dataService.getCustomers(vm.currentPage - 1, vm.pageSize)
50 | .then(function (data) {
51 | vm.totalRecords = data.totalRecords;
52 | vm.customers = data.results;
53 | filterCustomersProducts('');
54 | }, function (error) {
55 | $window.alert(error.message);
56 | });
57 | }
58 | };
59 |
60 | OrdersController.$inject = injectParams;
61 |
62 | angular.module('customersApp').controller('OrdersController', OrdersController);
63 |
64 | }());
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/Src/CustomerManager/app/customersApp/directives/lazyLoader.js:
--------------------------------------------------------------------------------
1 | //
2 | (function () {
3 | // use this directive to delay assigning user input to the underlying
4 | // view model field until focus leaves the dom element. Useful for
5 | // delaying breeze validation until user enters all data (like when
6 | // entering dates)
7 | var lazyLoad = function () {
8 | return {
9 | restrict: 'A', //E = element, A = attribute, C = class, M = comment
10 | transclude: true,
11 | scope: {
12 | name: '@'
13 | },
14 | link: function (scope, element, attrs) {
15 | element.bind('blur', function (e) {
16 | scope.$parent.$apply(function () {
17 | scope.$parent[scope.name] = element.val();
18 | });
19 | });
20 | }
21 | };
22 | };
23 |
24 | angular.module('customersApp').directive('lazyLoad', lazyLoad);
25 |
26 | }());
--------------------------------------------------------------------------------
/Src/CustomerManager/app/customersApp/directives/wcUnique.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | var injectParams = ['$q', 'dataService'];
4 |
5 | var wcUniqueDirective = function ($q, dataService) {
6 |
7 | var link = function (scope, element, attrs, ngModel) {
8 | ngModel.$asyncValidators.unique = function (modelValue, viewValue) {
9 | var deferred = $q.defer(),
10 | currentValue = modelValue || viewValue,
11 | key = attrs.wcUniqueKey,
12 | property = attrs.wcUniqueProperty;
13 |
14 | //First time the asyncValidators function is loaded the
15 | //key won't be set so ensure that we have
16 | //key and propertyName before checking with the server
17 | if (key && property) {
18 | dataService.checkUniqueValue(key, property, currentValue)
19 | .then(function (unique) {
20 | if (unique) {
21 | deferred.resolve(); //It's unique
22 | }
23 | else {
24 | deferred.reject(); //Add unique to $errors
25 | }
26 | });
27 | return deferred.promise;
28 | }
29 | else {
30 | return $q.when(true);
31 | }
32 | };
33 | };
34 |
35 | return {
36 | restrict: 'A',
37 | require: 'ngModel',
38 | link: link
39 | };
40 | };
41 |
42 | wcUniqueDirective.$inject = injectParams;
43 |
44 | angular.module('customersApp').directive('wcUnique', wcUniqueDirective);
45 |
46 | }());
--------------------------------------------------------------------------------
/Src/CustomerManager/app/customersApp/filters/nameCityStateFilter.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | var nameCityStateFilter = function () {
4 |
5 | return function (customers, filterValue) {
6 | if (!filterValue) return customers;
7 |
8 | var matches = [];
9 | filterValue = filterValue.toLowerCase();
10 | for (var i = 0; i < customers.length; i++) {
11 | var cust = customers[i];
12 | if (cust.firstName.toLowerCase().indexOf(filterValue) > -1 ||
13 | cust.lastName.toLowerCase().indexOf(filterValue) > -1 ||
14 | cust.city.toLowerCase().indexOf(filterValue) > -1 ||
15 | cust.state.name.toLowerCase().indexOf(filterValue) > -1) {
16 |
17 | matches.push(cust);
18 | }
19 | }
20 | return matches;
21 | };
22 | };
23 |
24 | angular.module('customersApp').filter('nameCityStateFilter', nameCityStateFilter);
25 |
26 | }());
--------------------------------------------------------------------------------
/Src/CustomerManager/app/customersApp/filters/nameProductFilter.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | var nameProductFilter = function () {
4 |
5 | function matchesProduct(customer, filterValue) {
6 | if (customer.orders) {
7 | for (var i = 0; i < customer.orders.length; i++) {
8 | if (customer.orders[i].product.toLowerCase().indexOf(filterValue) > -1) {
9 | return true;
10 | }
11 | }
12 | }
13 | return false;
14 | }
15 |
16 | return function (customers, filterValue) {
17 | if (!filterValue || !customers) return customers;
18 |
19 | var matches = [];
20 | filterValue = filterValue.toLowerCase();
21 | for (var i = 0; i < customers.length; i++) {
22 | var cust = customers[i];
23 | if (cust.firstName.toLowerCase().indexOf(filterValue) > -1 ||
24 | cust.lastName.toLowerCase().indexOf(filterValue) > -1 ||
25 | matchesProduct(cust, filterValue)) {
26 |
27 | matches.push(cust);
28 | }
29 | }
30 | return matches;
31 | };
32 | };
33 |
34 | angular.module('customersApp').filter('nameProductFilter', nameProductFilter);
35 |
36 | }());
--------------------------------------------------------------------------------
/Src/CustomerManager/app/customersApp/partials/modal.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
{{modalOptions.bodyText}}
7 |
8 |
12 |
13 |
--------------------------------------------------------------------------------
/Src/CustomerManager/app/customersApp/services/authService.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | var injectParams = ['$http', '$rootScope'];
4 |
5 | var authFactory = function ($http, $rootScope) {
6 | var serviceBase = '/api/dataservice/',
7 | factory = {
8 | loginPath: '/login',
9 | user: {
10 | isAuthenticated: false,
11 | roles: null
12 | }
13 | };
14 |
15 | factory.login = function (email, password) {
16 | return $http.post(serviceBase + 'login', { userLogin: { userName: email, password: password } }).then(
17 | function (results) {
18 | var loggedIn = results.data.status;;
19 | changeAuth(loggedIn);
20 | return loggedIn;
21 | });
22 | };
23 |
24 | factory.logout = function () {
25 | return $http.post(serviceBase + 'logout').then(
26 | function (results) {
27 | var loggedIn = !results.data.status;
28 | changeAuth(loggedIn);
29 | return loggedIn;
30 | });
31 | };
32 |
33 | factory.redirectToLogin = function () {
34 | $rootScope.$broadcast('redirectToLogin', null);
35 | };
36 |
37 | function changeAuth(loggedIn) {
38 | factory.user.isAuthenticated = loggedIn;
39 | $rootScope.$broadcast('loginStatusChanged', loggedIn);
40 | }
41 |
42 | return factory;
43 | };
44 |
45 | authFactory.$inject = injectParams;
46 |
47 | angular.module('customersApp').factory('authService', authFactory);
48 |
49 | }());
50 |
51 |
--------------------------------------------------------------------------------
/Src/CustomerManager/app/customersApp/services/config.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | var value = {
4 | useBreeze: false
5 | };
6 |
7 | angular.module('customersApp').value('config', value);
8 |
9 | }());
--------------------------------------------------------------------------------
/Src/CustomerManager/app/customersApp/services/dataService.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | var injectParams = ['config', 'customersService', 'customersBreezeService'];
4 |
5 | var dataService = function (config, customersService, customersBreezeService) {
6 | return (config.useBreeze) ? customersBreezeService : customersService;
7 | };
8 |
9 | dataService.$inject = injectParams;
10 |
11 | angular.module('customersApp').factory('dataService', dataService);
12 |
13 | }());
14 |
15 |
--------------------------------------------------------------------------------
/Src/CustomerManager/app/customersApp/services/httpInterceptors.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | angular.module('customersApp')
4 | .config(['$httpProvider', function ($httpProvider) {
5 |
6 | var injectParams = ['$q', '$rootScope'];
7 |
8 | var httpInterceptor401 = function ($q, $rootScope) {
9 |
10 | var success = function (response) {
11 | return response;
12 | };
13 |
14 | var error = function (res) {
15 | if (res.status === 401) {
16 | //Raise event so listener (navbarController) can act on it
17 | $rootScope.$broadcast('redirectToLogin', null);
18 | return $q.reject(res);
19 | }
20 | return $q.reject(res);
21 | };
22 |
23 | return function (promise) {
24 | return promise.then(success, error);
25 | };
26 |
27 | };
28 |
29 | httpInterceptor401.$inject = injectParams;
30 |
31 | $httpProvider.interceptors.push(httpInterceptor401);
32 |
33 | }]);
34 |
35 | }());
--------------------------------------------------------------------------------
/Src/CustomerManager/app/customersApp/services/modalService.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | var injectParams = ['$uibModal'];
4 |
5 | var modalService = function ($uibModal) {
6 |
7 | var modalDefaults = {
8 | backdrop: true,
9 | keyboard: true,
10 | modalFade: true,
11 | templateUrl: '/app/customersApp/partials/modal.html'
12 | };
13 |
14 | var modalOptions = {
15 | closeButtonText: 'Close',
16 | actionButtonText: 'OK',
17 | headerText: 'Proceed?',
18 | bodyText: 'Perform this action?'
19 | };
20 |
21 | this.showModal = function (customModalDefaults, customModalOptions) {
22 | if (!customModalDefaults) customModalDefaults = {};
23 | customModalDefaults.backdrop = 'static';
24 | return this.show(customModalDefaults, customModalOptions);
25 | };
26 |
27 | this.show = function (customModalDefaults, customModalOptions) {
28 | //Create temp objects to work with since we're in a singleton service
29 | var tempModalDefaults = {};
30 | var tempModalOptions = {};
31 |
32 | //Map angular-ui modal custom defaults to modal defaults defined in this service
33 | angular.extend(tempModalDefaults, modalDefaults, customModalDefaults);
34 |
35 | //Map modal.html $scope custom properties to defaults defined in this service
36 | angular.extend(tempModalOptions, modalOptions, customModalOptions);
37 |
38 | if (!tempModalDefaults.controller) {
39 | tempModalDefaults.controller = function ($scope, $uibModalInstance) {
40 | $scope.modalOptions = tempModalOptions;
41 | $scope.modalOptions.ok = function (result) {
42 | $uibModalInstance.close('ok');
43 | };
44 | $scope.modalOptions.close = function (result) {
45 | $uibModalInstance.close('cancel');
46 | };
47 | };
48 |
49 | tempModalDefaults.controller.$inject = ['$scope', '$uibModalInstance'];
50 | }
51 |
52 | return $uibModal.open(tempModalDefaults).result;
53 | };
54 | };
55 |
56 | modalService.$inject = injectParams;
57 |
58 | angular.module('customersApp').service('modalService', modalService);
59 |
60 | }());
--------------------------------------------------------------------------------
/Src/CustomerManager/app/customersApp/views/about.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
Created by:
10 |
11 |
12 |
13 |
17 |
18 |
22 |
23 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Src/CustomerManager/app/customersApp/views/customers/customerOrders.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 | {{vm.customer.address}}
12 |
13 | {{vm.customer.city}}, {{vm.customer.state.name}}
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Src/CustomerManager/app/customersApp/views/login.html:
--------------------------------------------------------------------------------
1 |
55 |
56 |
--------------------------------------------------------------------------------
/Src/CustomerManager/app/customersApp/views/orders/orders.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | All Customer Orders
5 |
6 |
7 |
19 |
20 |
28 |
29 |
30 |
No customers found
31 |
32 |
33 |
34 |
35 |
42 |
43 |
Showing {{ vm.filteredCount }} of {{ vm.totalRecords}} total customers
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/Src/CustomerManager/app/customersApp/views/orders/ordersTable.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Product
5 | Date
6 | Quantity
7 | Unit Price
8 | Total
9 |
10 |
11 |
12 |
13 |
14 | No orders found
15 |
16 |
17 |
18 |
19 | {{ order.product }}
20 |
21 |
22 | {{ order.date | date:'MM/dd/yyyy' }}
23 |
24 |
25 | {{ order.quantity }}
26 |
27 |
28 | {{ order.price | currency }}
29 |
30 |
31 | {{ order.orderTotal | currency }}
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | {{ vm.customer.ordersTotal | currency }}
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/Src/CustomerManager/app/wc.directives/directives/lazyLoader.js:
--------------------------------------------------------------------------------
1 | //
2 | (function () {
3 | // use this directive to delay assigning user input to the underlying
4 | // view model field until focus leaves the dom element. Useful for
5 | // delaying breeze validation until user enters all data (like when
6 | // entering dates)
7 | var lazyLoad = function () {
8 | return {
9 | restrict: 'A', //E = element, A = attribute, C = class, M = comment
10 | transclude: true,
11 | scope: {
12 | name: '@'
13 | },
14 | link: function (scope, element, attrs) {
15 | element.bind('blur', function (e) {
16 | scope.$parent.$apply(function () {
17 | scope.$parent[scope.name] = element.val();
18 | });
19 | });
20 | }
21 | };
22 | };
23 |
24 | angular.module('customersApp').directive('lazyLoad', lazyLoad);
25 |
26 | }());
--------------------------------------------------------------------------------
/Src/CustomerManager/app/wc.directives/directives/menuHighlighter.js:
--------------------------------------------------------------------------------
1 | /*
2 | Thanks to Karl-Gustav for creating the autoActive directive
3 | to simplify highlighting elements in a menu based on the path
4 | View the original version of the autoActive directive at
5 | https://github.com/Karl-Gustav/autoActive
6 |
7 | This version renames the directive and does some minor code restructuring and changes.
8 | */
9 |
10 | (function () {
11 |
12 | var injectParams = ['$location'];
13 |
14 | var menuHighlighter = function ($location) {
15 |
16 | var link = function (scope, element) {
17 | function setActive() {
18 | var path = $location.path();
19 | var className = scope.highlightClassName || 'active';
20 |
21 | if (path) {
22 | angular.forEach(element.find('li'), function (li) {
23 | var anchor = li.querySelector('a');
24 | //Get href from href attribute or data-href in cases where href isn't used (such as login)
25 | var href = (anchor && anchor.href) ? anchor.href :
26 | anchor.getAttribute('data-href').replace('#!', '');
27 | //Get value after hash
28 | var trimmedHref = href.substr(href.indexOf('#!/') + 2, href.length);
29 | //Convert path to same length as trimmedHref
30 | var basePath = path.substr(0, trimmedHref.length);
31 |
32 | //See if trimmedHref and basePath match. If so, then highlight that item
33 | if (trimmedHref === basePath) {
34 | angular.element(li).addClass(className);
35 | } else {
36 | angular.element(li).removeClass(className);
37 | }
38 | });
39 | }
40 | }
41 |
42 | setActive();
43 |
44 | //Monitor location changes
45 | scope.$on('$locationChangeSuccess', setActive);
46 | };
47 |
48 | return {
49 | restrict: 'A',
50 | scope: {
51 | highlightClassName: '@'
52 | },
53 | link: link
54 | }
55 | }
56 |
57 | menuHighlighter.$inject = injectParams;
58 |
59 | angular.module('wc.directives').directive('menuHighlighter', menuHighlighter);
60 |
61 | }());
--------------------------------------------------------------------------------
/Src/CustomerManager/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanWahlin/AngularJSEndToEndCourseCode/12cf7f9f1213e481fa1c140f761e7e766a555845/Src/CustomerManager/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/Src/CustomerManager/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanWahlin/AngularJSEndToEndCourseCode/12cf7f9f1213e481fa1c140f761e7e766a555845/Src/CustomerManager/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/Src/CustomerManager/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanWahlin/AngularJSEndToEndCourseCode/12cf7f9f1213e481fa1c140f761e7e766a555845/Src/CustomerManager/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/Src/CustomerManager/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp'),
2 | uglify = require('gulp-uglify'),
3 | concat = require('gulp-concat'),
4 | plumber = require('gulp-plumber'),
5 | templateCache = require('gulp-angular-templatecache'),
6 | //sass = require('gulp-sass'),
7 | //csso = require('gulp-csso'),
8 | dist = 'Scripts/dist';
9 |
10 | //gulp.task('sass', function () {
11 | // gulp.src('Content/styles.scss')
12 | // .pipe(plumber())
13 | // .pipe(sass({ errLogToConsole: true }))
14 | // .pipe(csso())
15 | // .pipe(gulp.dest('Content'));
16 | //});
17 |
18 | gulp.task('compressScripts', function () {
19 | gulp.src([
20 | 'app/**/*.js'
21 | ])
22 | .pipe(plumber())
23 | .pipe(concat('scripts.min.js'))
24 | .pipe(uglify())
25 | .pipe(gulp.dest(dist));
26 | });
27 |
28 | gulp.task('templates', function () {
29 | gulp.src('app/customersApp/views/**/*.html')
30 | .pipe(plumber())
31 | .pipe(templateCache({ root: 'app/customersApp/views', module: 'customersApp' }))
32 | .pipe(gulp.dest(dist));
33 | });
34 |
35 | gulp.task('watch', function () {
36 |
37 | //gulp.watch('Content/*.scss', ['sass']);
38 |
39 | gulp.watch(['app/**/*.js'],
40 | ['compressScripts']);
41 |
42 | });
43 |
44 | gulp.task('default', ['compressScripts', 'templates', 'watch']);
45 |
--------------------------------------------------------------------------------
/Src/CustomerManager/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "customer-manager-standard",
3 | "author": "Dan Wahlin",
4 | "version": "1.0.0",
5 | "scripts": {
6 | "start": "node server/server.js"
7 | },
8 | "dependencies": {
9 | "express": "^4.15.2",
10 | "pug": "^2.0.0-beta11",
11 | "mongoose": "^4.9.1",
12 | "cookie-parser": "^1.4.3",
13 | "body-parser": "^1.17.1",
14 | "express-session": "^1.15.1",
15 | "errorhandler": "^1.5.0",
16 | "csurf": "^1.9.0"
17 | },
18 | "devDependencies": {
19 | "gulp": "^3.9.1",
20 | "gulp-angular-templatecache": "^2.0.0",
21 | "gulp-concat": "^2.6.1",
22 | "gulp-sass": "^3.1.0",
23 | "gulp-csso": "^3.0.0",
24 | "gulp-plumber": "^1.1.0",
25 | "gulp-uglify": "^2.1.1",
26 | "phantomjs-prebuilt": "2.1.14",
27 | "karma": "^1.5.0",
28 | "karma-jasmine": "^1.1.0",
29 | "karma-ng-scenario": "^1.0.0",
30 | "karma-chrome-launcher": "^2.0.0",
31 | "jasmine": "^2.5.3"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Src/CustomerManager/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Src/CustomerManager/server/initMongoDB.bat:
--------------------------------------------------------------------------------
1 | @ECHO off
2 | c:\mongodb\bin\mongo.exe %CD%\initMongoData.js
3 |
4 | ECHO -
5 | ECHO Your data is loaded
6 | pause
--------------------------------------------------------------------------------
/Src/CustomerManager/server/initMongoDB.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | scriptDir=$(dirname $0)
4 |
5 | mongo ${scriptDir}/initMongoData.js
6 |
7 | echo -
8 | echo Your data is loaded
9 | read -p "Press [Enter] to exit..."
--------------------------------------------------------------------------------
/Src/CustomerManager/server/lib/protectJSON.js:
--------------------------------------------------------------------------------
1 | // JSON vulnerability protection
2 | // we prepend the data with ")]},\n", which will be stripped by $http in AngularJS
3 | // From angular-app (https://github.com/angular-app/angular-app), by Pawel Kozlowski & Peter Bacon Darwin
4 | module.exports = function(req, res, next) {
5 | var _send = res.send;
6 | res.send = function(body) {
7 | var contentType = res.getHeader('Content-Type');
8 | if ( contentType && contentType.indexOf('application/json') !== -1 ) {
9 | if (2 == arguments.length) {
10 | // res.send(body, status) backwards compat
11 | if ('number' != typeof body && 'number' == typeof arguments[1]) {
12 | this.statusCode = arguments[1];
13 | } else {
14 | this.statusCode = body;
15 | body = arguments[1];
16 | }
17 | }
18 | body = ")]}',\n" + body;
19 | return _send.call(res, body);
20 | }
21 | _send.apply(res, arguments);
22 | };
23 | next();
24 | };
--------------------------------------------------------------------------------
/Src/CustomerManager/server/models/customer.js:
--------------------------------------------------------------------------------
1 | var mongoose = require('mongoose')
2 | , Schema = mongoose.Schema
3 | , ObjectId = Schema.ObjectId;
4 |
5 |
6 | var SettingsSchema = new Schema({
7 | collectionName : {
8 | type : String, required: true, trim: true, default: 'customers'
9 | },
10 | nextSeqNumber: {
11 | type: Number, default: 1
12 | }
13 | });
14 |
15 | var OrderSchema = new Schema({
16 | product : {
17 | type : String, required: true, trim: true
18 | },
19 | price : {
20 | type : Number,
21 | },
22 | quantity : {
23 | type : Number,
24 | }
25 | });
26 |
27 | var CustomerSchema = new Schema({
28 | firstName : {
29 | type : String, required: true, trim: true
30 | },
31 | lastName : {
32 | type : String, required: true, trim: true
33 | },
34 | email : {
35 | type : String, required: true, trim: true
36 | },
37 | address : {
38 | type : String, required: true, trim: true
39 | },
40 | city : {
41 | type : String, required: true, trim: true
42 | },
43 | stateId : {
44 | type : Number, required: true
45 | },
46 | state : {
47 | id : {
48 | type : Number
49 | },
50 | abbreviation : {
51 | type : String, required: true, trim: true
52 | },
53 | name : {
54 | type : String, required: true, trim: true
55 | }
56 | },
57 | zip : {
58 | type : Number, required: true
59 | },
60 | gender : {
61 | type : String,
62 | },
63 | id : {
64 | type : Number, required: true, unique: true
65 | },
66 | orderCount : {
67 | type : Number,
68 | },
69 | orders: [OrderSchema],
70 | });
71 |
72 | CustomerSchema.index({ id: 1, type: 1 }); // schema level
73 |
74 | // I make sure this is the last pre-save middleware (just in case)
75 | var Settings = mongoose.model('settings', SettingsSchema);
76 |
77 | CustomerSchema.pre('save', function(next) {
78 | var doc = this;
79 | // Calculate the next id on new Customers only.
80 | if (this.isNew) {
81 | Settings.findOneAndUpdate( {"collectionName": "customers"}, { $inc: { nextSeqNumber: 1 } }, function (err, settings) {
82 | if (err) next(err);
83 | doc.id = settings.nextSeqNumber - 1; // substract 1 because I need the 'current' sequence number, not the next
84 | next();
85 | });
86 | } else {
87 | next();
88 | }
89 | });
90 |
91 | exports.CustomerSchema = CustomerSchema;
92 | module.exports = mongoose.model('Customer', CustomerSchema);
93 |
--------------------------------------------------------------------------------
/Src/CustomerManager/server/models/state.js:
--------------------------------------------------------------------------------
1 | var mongoose = require('mongoose')
2 | , Schema = mongoose.Schema
3 | , ObjectId = Schema.ObjectId;
4 |
5 | var StateSchema = new Schema({
6 | id : {
7 | type : Number, required: true
8 | },
9 | abbreviation : {
10 | type : String, required: true, trim: true
11 | },
12 | name : {
13 | type : String, required: true, trim: true
14 | }
15 | });
16 |
17 | exports.StateSchema = StateSchema;
18 | module.exports = mongoose.model('State', StateSchema);
19 |
20 |
--------------------------------------------------------------------------------
/Src/CustomerManager/server/routes/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * GET home page.
3 | */
4 |
5 | exports.index = function(req, res){
6 | res.render('index');
7 | };
8 |
--------------------------------------------------------------------------------
/Src/CustomerManager/server/server.js:
--------------------------------------------------------------------------------
1 | var express = require('express'),
2 | cookieParser = require('cookie-parser'),
3 | bodyParser = require('body-parser'),
4 | session = require('express-session'),
5 | errorhandler = require('errorhandler'),
6 | csrf = require('csurf'),
7 | routes = require('./routes'),
8 | api = require('./routes/api'),
9 | DB = require('./accessDB'),
10 | protectJSON = require('./lib/protectJSON'),
11 | app = express();
12 |
13 | app.set('views', __dirname + '/views');
14 | app.set('view engine', 'pug');
15 | app.use(session({
16 | secret: 'customermanagerstandard',
17 | saveUninitialized: true,
18 | resave: true }));
19 | app.use(cookieParser());
20 | app.use(bodyParser.urlencoded({ extended: true }));
21 | app.use(bodyParser.json());
22 | app.use(express.static(__dirname + '/../'));
23 | app.use(errorhandler());
24 | app.use(protectJSON);
25 | app.use(csrf());
26 |
27 | app.use(function (req, res, next) {
28 | var csrf = req.csrfToken();
29 | res.cookie('XSRF-TOKEN', csrf);
30 | res.locals._csrf = csrf;
31 | next();
32 | })
33 |
34 | process.on('uncaughtException', function (err) {
35 | if (err) console.log(err, err.stack);
36 | });
37 |
38 | //Local Connection
39 | var conn = 'mongodb://localhost/customermanager';
40 | var db = new DB.startup(conn);
41 |
42 | // Routes
43 | app.get('/', routes.index);
44 |
45 | // JSON API
46 | var baseUrl = '/api/dataservice/';
47 |
48 | app.get(baseUrl + 'Customers', api.customers);
49 | app.get(baseUrl + 'Customer/:id', api.customer);
50 | app.get(baseUrl + 'CustomersSummary', api.customersSummary);
51 | app.get(baseUrl + 'CustomerById/:id', api.customer);
52 |
53 | app.post(baseUrl + 'PostCustomer', api.addCustomer);
54 | app.put(baseUrl + 'PutCustomer/:id', api.editCustomer);
55 | app.delete(baseUrl + 'DeleteCustomer/:id', api.deleteCustomer);
56 |
57 | app.get(baseUrl + 'States', api.states);
58 |
59 | app.get(baseUrl + 'CheckUnique/:id', api.checkUnique);
60 |
61 | app.post(baseUrl + 'Login', api.login);
62 | app.post(baseUrl + 'Logout', api.logout);
63 |
64 |
65 | // redirect all others to the index (HTML5 history)
66 | app.get('*', routes.index);
67 |
68 | // Start server
69 |
70 | app.listen(3000, function () {
71 | console.log("CustMgr Express server listening on port %d in %s mode", this.address().port, app.settings.env);
72 | });
73 |
--------------------------------------------------------------------------------
/Src/CustomerManager/server/views/index.jade:
--------------------------------------------------------------------------------
1 | include ../../index.html
2 |
--------------------------------------------------------------------------------
/Src/CustomerManager/test/karma.conf.js:
--------------------------------------------------------------------------------
1 | module.exports = function (config) {
2 | config.set({
3 | basePath: '../',
4 | port: 9876,
5 | frameworks: ['jasmine'],
6 | files: [
7 | //Library scripts
8 | 'test/lib/angular.js', //Ensure Angular is loaded first,
9 | 'test/lib/breeze.min.js', //Ensure Angular is loaded first
10 | 'test/lib/*.js',
11 | 'Scripts/**/*.js',
12 |
13 | //App and test scripts (order matters!)
14 | 'test/helpers/*.js',
15 | 'app/wc.directives/directives/wcOverlay.js',
16 | 'app/wc.directives/directives/menuHighlighter.js',
17 | 'app/customersApp/app.js',
18 | 'app/customersApp/**/*.js',
19 | 'test/unit/*.js'
20 | ],
21 | autoWatch: true,
22 | browsers: ['Chrome'],
23 | reporters: ['progress']
24 | });
25 | };
26 |
27 |
--------------------------------------------------------------------------------
/Src/CustomerManager/test/unit/customersServiceSpec.js:
--------------------------------------------------------------------------------
1 | describe('customersService Tests', function () {
2 | var httpBackend,
3 | serviceUrl = '/api/dataservice/customersSummary?$top=10&$skip=0',
4 | custs = [{
5 | "id": 1,
6 | "firstName": "Marcus",
7 | "lastName": "HighTower",
8 | "city": "Phoenix",
9 | "state": {
10 | "id": 1,
11 | "abbreviation": "AZ",
12 | "name": " Arizona"
13 | },
14 | "orderCount": 6,
15 | "gender": "Male"
16 | }];
17 |
18 | beforeEach(function () {
19 | module('customersApp');
20 |
21 | inject(function ($httpBackend) {
22 | httpBackend = $httpBackend;
23 | });
24 | });
25 |
26 | //Ensure no expectations were missed (expectGET or expectPOST)
27 | afterEach(function () {
28 | httpBackend.verifyNoOutstandingExpectation();
29 | httpBackend.verifyNoOutstandingRequest();
30 | });
31 |
32 | it('customersService should return custom object', function () {
33 | inject(function (customersService) {
34 | var response = {
35 | totalRecords: 1,
36 | results: custs
37 | };
38 | //Header normally sent from server and contains the totalRecords
39 | httpBackend.when('GET', serviceUrl).respond(custs, { 'X-InlineCount': '1' });
40 |
41 | var test = {
42 | handler: function () { }
43 | };
44 |
45 | //Monitor the handler function
46 | spyOn(test, 'handler');
47 |
48 | customersService.getCustomersSummary(0, 10).then(test.handler);
49 | httpBackend.flush();
50 |
51 | //Ensure handler function received proper response data
52 | expect(test.handler).toHaveBeenCalledWith(response);
53 | });
54 | });
55 |
56 | it('customersService should return custom object with totalRecords equal to 1', function () {
57 | inject(function (customersService) {
58 | //Header normally sent from server and contains the totalRecords
59 | httpBackend.when('GET', serviceUrl).respond(custs, { 'X-InlineCount': '1' });
60 | customersService.getCustomersSummary(0, 10).then(function (result) {
61 | expect(result.totalRecords).toEqual(1);
62 | });
63 | httpBackend.flush();
64 | });
65 | });
66 |
67 | });
--------------------------------------------------------------------------------
/Src/CustomerManager/test/unit/wcOverlaySpec.js:
--------------------------------------------------------------------------------
1 | describe('wcOverlay directive specs', function () {
2 | var scope, compile, element, compiledOverlay;
3 |
4 | beforeEach(module('wc.directives'));
5 |
6 | beforeEach(inject(function ($rootScope, $compile) {
7 | scope = $rootScope;
8 | compile = $compile;
9 |
10 | element = angular.element(" Loading...
");
11 |
12 | scope.delayTime = 100;
13 |
14 | compiledOverlay = compile(element)(scope);
15 | }));
16 |
17 | it('Should have appended the directive template', function () {
18 | expect(compiledOverlay.find('div').hasClass('overlayContainer')).toBe(true);
19 | });
20 |
21 | });
--------------------------------------------------------------------------------
/Src/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Dan Wahlin and Wahlin Consulting (http://github.com/DanWahlin)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/copyFolders.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var fse = require('fs-extra'),
4 | ignoreDirs = ['Creating a Module Factory Controller and View',
5 | 'Unit Testing AngularJS Components',
6 | 'Working with Controllers and Watches'];
7 |
8 | function copyDirectory(srcDir, startDir, copyToSubFolderName) {
9 |
10 | //Iterate through directories
11 | fse.readdirSync(startDir).forEach(function (dir) {
12 | var directory = startDir + '/' + dir,
13 | stat = fse.lstatSync(directory);
14 |
15 | if (stat.isDirectory()) {
16 | if (ignoreDirs.indexOf(dir) === -1) { //Make sure the ignoreDirs aren't involved in the copy operations
17 | var targetDir = directory + '/' + copyToSubFolderName, //Target directory src should be copied to
18 | filesOverlaySrc = directory + '/Files', //If no srcDir is provided then we're overlaying lab files into the targetDir
19 | finalSrc = (srcDir) ? srcDir : filesOverlaySrc;
20 |
21 | fse.copySync(finalSrc, targetDir);
22 | console.log('Copied ' + finalSrc + ' to ' + targetDir);
23 | }
24 | }
25 | });
26 | }
27 |
28 | //Copy src into Begin folder of each lab
29 | copyDirectory('./Src', './Labs', 'Begin');
30 |
31 | //Copy Files into Begin folder of each lab
32 | copyDirectory(null, './Labs', 'Begin');
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "foldercopier",
3 | "version": "1.0.0",
4 | "description": "Copies source code from destination folder into lab folders and overlays specific lab files.",
5 | "author": "Dan Wahlin",
6 | "main": "copyFolders.js",
7 | "dependencies": {
8 | "fs-extra": "^2.1.2"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | To build the labs do the following:
2 |
3 |
4 | 1. Download the code and extract it to your machine (or use git).
5 | 2. Run "npm install" from a command prompt at the root of the folder.
6 | 3. Run "node copyFolders.js" to generate the lab code output.
7 |
--------------------------------------------------------------------------------