From 13484a93af571819ed992395116c46aa98c342eb Mon Sep 17 00:00:00 2001 From: amfranco Date: Wed, 11 Nov 2015 22:59:32 -0300 Subject: [PATCH 01/15] Added expenses calc demo --- client/demo/expenses/index.html | 65 +++++++++++++++++++++++++++++++++ client/demo/expenses/script.js | 58 +++++++++++++++++++++++++++++ client/demo/expenses/styles.css | 14 +++++++ 3 files changed, 137 insertions(+) create mode 100644 client/demo/expenses/index.html create mode 100644 client/demo/expenses/script.js create mode 100644 client/demo/expenses/styles.css diff --git a/client/demo/expenses/index.html b/client/demo/expenses/index.html new file mode 100644 index 0000000..927b714 --- /dev/null +++ b/client/demo/expenses/index.html @@ -0,0 +1,65 @@ + + + + + + + + + + + +
+
+

Expenses calc

+
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+

{{ typesList.name }}

+
+
Date
+
Description
+
Amount
+
Operations
+
+
+
+
{{expense.date | date: 'dd/MM/yyyy'}}
+
{{expense.description}}
+
{{expense.amount}}
+
+
+
+
+
Total
+
{{ expensesVm.total(typesList.name) }}
+
+
+
+
+
+
+
Total
+
{{ expensesVm.total('') }}
+
+
+
+ + diff --git a/client/demo/expenses/script.js b/client/demo/expenses/script.js new file mode 100644 index 0000000..6d01ad9 --- /dev/null +++ b/client/demo/expenses/script.js @@ -0,0 +1,58 @@ +(function() { + 'use strict'; + + // Create module and controller + angular + .module('expensesDemo', []) + .controller('ExpensesController', ['$scope', '$filter', ExpensesController]); + + ExpensesController.$inject = [ + ]; + + function ExpensesController($scope, $filter) { + // Controller as viewModel + var vm = this; + // Initialization + vm.list = []; + // Expenses types + vm.expensesTypes = [ + {name: "food", value: "food"}, + {name: "transportation", value: "transportation"}, + {name: "lodging", value: "lodging"}, + {name: "financial", value: "financial"}, + {name: "sales", value: "sales"}, + {name: "other", value: "other"} + ]; + + // Controller methods + vm.add = add; + vm.remove = remove; + + // Total amount + vm.total = total; + + /* Adds an item to the todo list */ + function add(date, type, description, amount) { + vm.list.push({date: date, type: type, description: description, amount: amount}); + } + + /* Removes the item in the list with index: $index*/ + function remove(index) { + vm.list.splice(index,1); + } + + // Calculate expense total. + function total(type) { + var sum = 0; + var list = vm.list; + if (type !== '') { + // filter by expense type + list = $filter('filter')(vm.list, { type: type }); + } + angular.forEach(list, function(expense, key) { + sum += expense.amount; + }); + return sum; + } + } +})(); diff --git a/client/demo/expenses/styles.css b/client/demo/expenses/styles.css new file mode 100644 index 0000000..5ef6a4d --- /dev/null +++ b/client/demo/expenses/styles.css @@ -0,0 +1,14 @@ +body { +} +.form {margin-bottom: 15px; padding-bottom: 10px; border-bottom: 1px solid #000;} +.form input {margin-bottom: 10px;} +.food div {background-color: #FBDDDD;} +.transportation div {background-color: #C0DAC0;} +.lodging div {background-color: #EAEAFF;} +.financial div {background-color: #EEEEEE;} +.sales div {background-color: #F9F99D;} +.other div {background-color: #C5F5F5;} +.row.total {font-weight: bold; margin-top: 15px; padding: 5px; border: 1px solid #CCC;} +.type h3 {margin-top: 10px} +.type .header {font-weight: bold; border-bottom: 1px solid #000;} +.type .type-total {border-top: 1px solid #000;} From afe62c0d53d808e6591ae57efc5736a922dde0be Mon Sep 17 00:00:00 2001 From: aotaduy Date: Mon, 9 Nov 2015 09:28:03 -0300 Subject: [PATCH 02/15] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5e4b558..e0df072 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ I haven't tested with newer versions but it should work anyway. ## For both envs ```` -npm install grunt bower -g +npm install grunt-cli bower -g git clone https://github.com/aotaduy/angular-course.git npm install bower install From b442a15bb4a068e4291fd9f93a989d2e0c8464ab Mon Sep 17 00:00:00 2001 From: aotaduy Date: Mon, 9 Nov 2015 11:09:14 -0300 Subject: [PATCH 03/15] Random example --- client/demo/random/index.html | 25 +++++++++++--------- client/demo/random/random-service.factory.js | 5 +++- client/demo/random/random.controller.js | 6 ++++- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/client/demo/random/index.html b/client/demo/random/index.html index e969633..e4fa312 100644 --- a/client/demo/random/index.html +++ b/client/demo/random/index.html @@ -9,25 +9,28 @@
+
-
+
+

+ Get a random number from the service online. Faulty service returns random error with a 0.5 probability +

-

{{randomVm.message}}

-

Random: {{randomVm.randomNumber}}

+

{{randomVm.message}}

+

Random: {{randomVm.randomNumber}}

-
-

- - {{item.text}} - -

+
+
diff --git a/client/demo/random/random-service.factory.js b/client/demo/random/random-service.factory.js index 2eb7848..8d7834b 100644 --- a/client/demo/random/random-service.factory.js +++ b/client/demo/random/random-service.factory.js @@ -27,7 +27,10 @@ return $http.get('/api/random/faulty') .then(function (response) { service.values.push(response.data.value); - return response.data.value; + return response.data.value.toFixed(3); + }, function (response) { + response.data.value = response.data.value.toFixed(3); + return $q.reject(response); }); } diff --git a/client/demo/random/random.controller.js b/client/demo/random/random.controller.js index a59fe4d..c138c24 100644 --- a/client/demo/random/random.controller.js +++ b/client/demo/random/random.controller.js @@ -17,6 +17,7 @@ // Initialization vm.randomNumber = 0; vm.message = null; + vm.messageHistory = ''; vm.numbers = randomService.values; // Controller methods @@ -25,15 +26,18 @@ /* Get next random number */ function updateNextRandom() { vm.message = 'Updating...'; + vm.randomNumber = 0; randomService.getRandom() .then(function(aValue) { vm.status = 200; vm.message = null; vm.randomNumber = aValue; + vm.messageHistory = vm.messageHistory + aValue + '\n'; }) .catch(function(aResponse) { vm.message = 'Failed with: ' + aResponse.status + ' ' + aResponse.data.value; - vm.randomNumber = NaN; + vm.randomNumber = null; + vm.messageHistory = vm.messageHistory + vm.message + '\n'; }); } From 4dbaaca58f7dc9531e715e8f0dfe8013fde7537e Mon Sep 17 00:00:00 2001 From: aotaduy Date: Mon, 9 Nov 2015 16:36:09 -0300 Subject: [PATCH 04/15] Add some tests --- client/.jshintrc | 4 +- client/demo/random/index.html | 18 +++- client/demo/random/random-service.factory.js | 38 ++++++++- .../random/random-service.factory.spec.js | 85 +++++++++++++++++++ client/demo/random/random.controller.js | 23 +++-- client/demo/random/random.controller.spec.js | 52 ++++++++++++ client/demo/todo-list-controller/index.html | 3 +- .../todo-list.controller.js | 2 +- .../todo-list.controller.spec.js | 29 +++++++ karma.conf.js | 6 +- package.json | 2 + server/api/random/random.controller.js | 4 +- 12 files changed, 247 insertions(+), 19 deletions(-) create mode 100644 client/demo/random/random-service.factory.spec.js diff --git a/client/.jshintrc b/client/.jshintrc index 2d3b8c3..c2f1e99 100644 --- a/client/.jshintrc +++ b/client/.jshintrc @@ -25,12 +25,14 @@ "moment": true, "describe": true, "beforeEach": true, + "afterEach": false, "module": true, "inject": true, "it": true, "expect": true, "browser": true, "element": true, - "by": true + "by": true, + "sinon": false } } diff --git a/client/demo/random/index.html b/client/demo/random/index.html index e4fa312..610963e 100644 --- a/client/demo/random/index.html +++ b/client/demo/random/index.html @@ -17,17 +17,31 @@
+
+
+
/api/random/faulty -> returns a number or an error if the number is < 0.5
+/api/random/slow -> returns a number with a random delay of between 0 and 2 secs
+/api/random/fast -> returns a number as fast as it can.
+
+

- Get a random number from the service online. Faulty service returns random error with a 0.5 probability + Get a random number from the service online.

{{randomVm.message}}

Random: {{randomVm.randomNumber}}

+

+ Get an array of the size specified in the input +

+ + +

Randoms: {{randomVm.randomArray}}

diff --git a/client/demo/random/random-service.factory.js b/client/demo/random/random-service.factory.js index 8d7834b..73e5b1b 100644 --- a/client/demo/random/random-service.factory.js +++ b/client/demo/random/random-service.factory.js @@ -9,15 +9,18 @@ randomFactory.$inject = [ '$http', - '$q' + '$q', + '$timeout' ]; - function randomFactory($http, $q) { + function randomFactory($http, $q, $timeout) { var service = { values: [], + mean: mean, getRandom: getRandom, - getLocal: getLocal, - mean: mean + getRandomDeferred: getRandomDeferred, + getRandomArray: getRandomArray, + getLocal: getLocal }; @@ -34,10 +37,37 @@ }); } + /* Answer an array with number of random numbers */ + function getRandomArray(size){ + var calls = []; + for (var i = 0; i < size; i++){ + calls.push($http.get('/api/random/slow').then(function (response) { + return response.data.value.toFixed(3); + })); + } + return $q.all(calls); + } + function getLocal(){ return $q.when({value: Math.random()}); } + function getRandomDeferred(){ + var deferred = $q.defer(); + $timeout(function () { + var number = Math.random().toFixed(3); + if (number < 0.5){ + deferred.reject({ + status: 404, + data: {value: number } + }); + } else { + deferred.resolve(number); + } + }, Math.random() * 2000); + return deferred.promise; + } + function mean(){ var sum = 0; service.values.forEach( function(each) { diff --git a/client/demo/random/random-service.factory.spec.js b/client/demo/random/random-service.factory.spec.js new file mode 100644 index 0000000..4894d55 --- /dev/null +++ b/client/demo/random/random-service.factory.spec.js @@ -0,0 +1,85 @@ +describe('Service: randomService', function() { + 'use strict'; + var + $rootScope, + $httpBackend, + service, + $q, + $timeout; + + beforeEach(module('randomDemo')); + beforeEach(inject(function( + _$rootScope_, + randomService, + _$q_, + _$httpBackend_, + _$timeout_) { + service = randomService; + $q = _$q_; + $httpBackend = _$httpBackend_; + $rootScope = _$rootScope_; + $timeout = _$timeout_; + })); + + describe('Happy path', function () { + beforeEach(function () { + $httpBackend.whenGET('/api/random/faulty').respond({value: 0.7}); + $httpBackend.whenGET('/api/random/fast').respond({value: 0.7}); + $httpBackend.whenGET('/api/random/slow').respond({value: 0.7}); + sinon.stub(Math, 'random'); + Math.random.returns(0.7); + }); + afterEach(function () { + Math.random.restore(); + }); + + it('should getRandomNumber', function() { + service.getRandom().then(function (response) { + expect(response).to.equal((0.7).toFixed(3)); + }); + $httpBackend.flush(); + }); + it('should getRandomNumber', function() { + service.getRandomDeferred().then(function (response) { + expect(response).to.be.a.number; + }); + $timeout.flush(); + $rootScope.$digest(); + }); + + it('should calculate mean', function() { + service.getRandom(); + service.getRandom(); + $httpBackend.flush(); + expect(service.mean()).to.equal(0.7); + }); + }); + describe('Errors path', function () { + beforeEach(function () { + $httpBackend.whenGET('/api/random/faulty').respond(503, {value: 0.3}); + $httpBackend.whenGET('/api/random/fast').respond(404, {value: 0.3}); + $httpBackend.whenGET('/api/random/slow').respond(500, {value: 0.3}); + sinon.stub(Math, 'random'); + Math.random.returns(0.3); + }); + + afterEach(function () { + Math.random.restore(); + }); + + it('should getRandomNumber', function() { + service.getRandom().catch(function (response) { + expect(response.status).to.equal(503); + }); + $httpBackend.flush(); + }); + it('should getRandomNumber', function() { + service.getRandomDeferred().catch(function (response) { + expect(response.status).to.equal(404); + }); + $timeout.flush(); + $rootScope.$digest(); + }); + }); + +}); diff --git a/client/demo/random/random.controller.js b/client/demo/random/random.controller.js index c138c24..4ff7629 100644 --- a/client/demo/random/random.controller.js +++ b/client/demo/random/random.controller.js @@ -16,12 +16,15 @@ var vm = this; // Initialization vm.randomNumber = 0; + vm.arraySize = 5; vm.message = null; vm.messageHistory = ''; vm.numbers = randomService.values; // Controller methods vm.updateNextRandom = updateNextRandom; + vm.getRandomArray = getRandomArray; + vm.getMean = randomService.mean; /* Get next random number */ function updateNextRandom() { @@ -34,11 +37,21 @@ vm.randomNumber = aValue; vm.messageHistory = vm.messageHistory + aValue + '\n'; }) - .catch(function(aResponse) { - vm.message = 'Failed with: ' + aResponse.status + ' ' + aResponse.data.value; - vm.randomNumber = null; - vm.messageHistory = vm.messageHistory + vm.message + '\n'; - }); + .catch(handleError); + } + + function handleError(aResponse) { + vm.message = 'Failed with: ' + aResponse.status + ' ' + aResponse.data.value; + vm.randomNumber = null; + vm.messageHistory = vm.messageHistory + vm.message + '\n'; + } + + function getRandomArray(size) { + vm.message = 'Updating...'; + randomService.getRandomArray(size).then(function (response) { + vm.messageHistory = vm.messageHistory + 'Array: ' + response + '\n'; + vm.message = null; + }, handleError); } } diff --git a/client/demo/random/random.controller.spec.js b/client/demo/random/random.controller.spec.js index e69de29..5399f1c 100644 --- a/client/demo/random/random.controller.spec.js +++ b/client/demo/random/random.controller.spec.js @@ -0,0 +1,52 @@ +describe('Controller: RandomDemo', function() { + 'use strict'; + var controller, + scope, + value, + $rootScope, + service, + $q; + // Refresh the $filter every time. + beforeEach(module('randomDemo')); + beforeEach(inject(function(_$rootScope_, $controller, randomService, _$q_) { + scope = _$rootScope_.$new(); + $rootScope = _$rootScope_; + controller = $controller('RandomController', + {$scope: scope}); + service = randomService; + $q = _$q_ + })); + + it('should getRandom', function() { + sinon.stub(service, 'getRandom', function() { + return $q.when(0.2); + }); + controller.updateNextRandom(); + $rootScope.$digest(); + expect(controller.messageHistory).to.equal('0.2\n'); + service.getRandom.restore(); + }); + + it('should getRandomArray', function() { + sinon.stub(service, 'getRandomArray', function() { + return $q.when([0.2, 0.3]); + }); + controller.getRandomArray(); + $rootScope.$digest(); + expect(controller.messageHistory).to.equal('Array: 0.2,0.3\n'); + service.getRandomArray.restore(); + }); + + it('should handleError', function() { + sinon.stub(service, 'getRandom', function() { + return $q.reject( + { status: 404, + data: {value: 0.2} + }); + }); + controller.updateNextRandom(); + $rootScope.$digest(); + expect(controller.messageHistory).to.equal('Failed with: 404 0.2\n'); + service.getRandom.restore(); + }); +}); diff --git a/client/demo/todo-list-controller/index.html b/client/demo/todo-list-controller/index.html index b87bdf1..f9cd870 100644 --- a/client/demo/todo-list-controller/index.html +++ b/client/demo/todo-list-controller/index.html @@ -13,12 +13,11 @@ } - +

Todo List #{{todoVm.list.length}}

-
diff --git a/client/demo/todo-list-controller/todo-list.controller.js b/client/demo/todo-list-controller/todo-list.controller.js index cb4b63b..99518b9 100644 --- a/client/demo/todo-list-controller/todo-list.controller.js +++ b/client/demo/todo-list-controller/todo-list.controller.js @@ -3,7 +3,7 @@ // Create module and controller angular - .module('todoListDemo', []) + .module('todoListControllerDemo', []) .controller('TodoListController', TodoListController); diff --git a/client/demo/todo-list-controller/todo-list.controller.spec.js b/client/demo/todo-list-controller/todo-list.controller.spec.js index e69de29..7d21948 100644 --- a/client/demo/todo-list-controller/todo-list.controller.spec.js +++ b/client/demo/todo-list-controller/todo-list.controller.spec.js @@ -0,0 +1,29 @@ +describe('Controller: todo-list', function() { + 'use strict'; + var controller, + scope; + // Refresh the $filter every time. + beforeEach(module('todoListControllerDemo')); + beforeEach(inject(function(_$rootScope_, $controller) { + scope = _$rootScope_.$new(); + controller = $controller('TodoListController', + {$scope: scope}); + }) + ); + + it('should start empty', function() { + expect(controller.list.length).to.equal(0); + }); + + it('should add items', function() { + controller.itemText = 'First item'; + controller.add(controller.itemText); + expect(controller.list.length).to.equal(1); + controller.itemText = 'Second item'; + controller.add(controller.itemText); + expect(controller.list.length).to.equal(2); + controller.remove(1); + expect(controller.list.length).to.equal(1); + }); + +}); diff --git a/karma.conf.js b/karma.conf.js index 4bdbd2b..ee1d0f5 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -7,7 +7,7 @@ module.exports = function(config) { basePath: '', // testing framework to use (jasmine/mocha/qunit/...) - frameworks: ['mocha', 'sinon-chai'], + frameworks: ['mocha', 'sinon-chai', 'chai-as-promised', 'chai'], // list of files / patterns to load in the browser files: [ @@ -23,6 +23,7 @@ module.exports = function(config) { 'client/app/app.js', 'client/app/**/*.js', 'client/components/**/*.js', + 'client/demo/**/*.js', //'client/app/**/*.jade', //'client/components/**/*.jade', 'client/app/**/*.html', @@ -35,7 +36,8 @@ module.exports = function(config) { '**/*.jade': 'ng-jade2js', '**/*.html': 'html2js', '**/*.coffee': 'coffee', - 'client/app/**/*.js' : ['coverage'] + 'client/app/**/*.js' : ['coverage'], + 'client/demo/**/*.js' : ['coverage'] }, ngHtml2JsPreprocessor: { diff --git a/package.json b/package.json index 27a310f..f73cebc 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,8 @@ "jit-grunt": "^0.5.0", "jshint-stylish": "~0.1.5", "karma": "~0.12.9", + "karma-chai": "^0.1.0", + "karma-chai-as-promised": "^0.1.2", "karma-chrome-launcher": "~0.1.3", "karma-coverage": "^0.5.3", "karma-firefox-launcher": "~0.1.3", diff --git a/server/api/random/random.controller.js b/server/api/random/random.controller.js index 0150d2e..f792fb4 100644 --- a/server/api/random/random.controller.js +++ b/server/api/random/random.controller.js @@ -24,7 +24,7 @@ function fast(req, res) { function slow(req, res) { setTimeout(function() { res.json({value: Math.random()}); - }, 1000); + }, Math.floor(2000 * Math.random())); } function faulty(req, res) { @@ -36,5 +36,5 @@ function faulty(req, res) { res.status(status); } res.json({value: value}); - }, 1000); + }, Math.floor(1000 * Math.random())); } From 1956c6fd9f612c16246842689055e3c19e812452 Mon Sep 17 00:00:00 2001 From: aotaduy Date: Tue, 10 Nov 2015 15:40:00 -0300 Subject: [PATCH 05/15] Fix tests --- karma.conf.js | 2 +- server/api/random/random.controller.js | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/karma.conf.js b/karma.conf.js index ee1d0f5..0d22131 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -7,7 +7,7 @@ module.exports = function(config) { basePath: '', // testing framework to use (jasmine/mocha/qunit/...) - frameworks: ['mocha', 'sinon-chai', 'chai-as-promised', 'chai'], + frameworks: ['mocha', 'sinon-chai'], // list of files / patterns to load in the browser files: [ diff --git a/server/api/random/random.controller.js b/server/api/random/random.controller.js index f792fb4..2781440 100644 --- a/server/api/random/random.controller.js +++ b/server/api/random/random.controller.js @@ -9,8 +9,6 @@ 'use strict'; -var _ = require('lodash'), - MovieDB = require('moviedb')(process.env.MOVIEDB_API); // Get list of things exports.fast = fast; From 50de528a53c334b73393a8056847cc8233d9ede5 Mon Sep 17 00:00:00 2001 From: aotaduy Date: Wed, 11 Nov 2015 17:21:40 -0300 Subject: [PATCH 06/15] added show movie --- client/app/app.less | 1 + .../movie-listing/movie-listing.html | 2 +- .../movie-poster/movie-poster.directive.js | 17 +++++++++ .../components/movie-poster/movie-poster.html | 2 + .../components/movie-poster/movie-poster.less | 7 ++++ client/app/components/movie/movie.html | 4 +- .../moviesConnector.factory.js | 7 +++- .../app/pages/movie/movie-page.controller.js | 20 ++++++++++ .../pages/movie/movie-page.controller.spec.js | 38 +++++++++++++++++++ client/app/pages/movie/movie-page.html | 23 +++++++++++ client/app/pages/movie/movie-page.route.js | 36 ++++++++++++++++++ client/index.html | 3 ++ server/api/movies/index.js | 2 +- server/api/movies/movies.controller.js | 8 +++- 14 files changed, 161 insertions(+), 9 deletions(-) create mode 100644 client/app/components/movie-poster/movie-poster.directive.js create mode 100644 client/app/components/movie-poster/movie-poster.html create mode 100644 client/app/components/movie-poster/movie-poster.less create mode 100644 client/app/pages/movie/movie-page.controller.js create mode 100644 client/app/pages/movie/movie-page.controller.spec.js create mode 100644 client/app/pages/movie/movie-page.html create mode 100644 client/app/pages/movie/movie-page.route.js diff --git a/client/app/app.less b/client/app/app.less index 16a4591..e33c13e 100644 --- a/client/app/app.less +++ b/client/app/app.less @@ -17,6 +17,7 @@ // injector @import 'components/movie-listing/movie-listing.less'; +@import 'components/movie-poster/movie-poster.less'; @import 'components/movie/movie.less'; @import 'components/search-box/search-box.less'; @import 'pages/example/main.less'; diff --git a/client/app/components/movie-listing/movie-listing.html b/client/app/components/movie-listing/movie-listing.html index 15fb7b6..2c02d26 100644 --- a/client/app/components/movie-listing/movie-listing.html +++ b/client/app/components/movie-listing/movie-listing.html @@ -1,3 +1,3 @@
- + movie="movie">
diff --git a/client/app/components/movie-poster/movie-poster.directive.js b/client/app/components/movie-poster/movie-poster.directive.js new file mode 100644 index 0000000..d53be17 --- /dev/null +++ b/client/app/components/movie-poster/movie-poster.directive.js @@ -0,0 +1,17 @@ +(function() { + 'use strict'; + + angular + .module('moviesApp') + .directive('moviePoster', moviePosterDirective); + function moviePosterDirective() { + return { + restrict: 'E', + templateUrl: 'app/components/movie-poster/movie-poster.html', + scope: { + movie: '=', + type: '=' + } + }; + } +})(); diff --git a/client/app/components/movie-poster/movie-poster.html b/client/app/components/movie-poster/movie-poster.html new file mode 100644 index 0000000..41959c0 --- /dev/null +++ b/client/app/components/movie-poster/movie-poster.html @@ -0,0 +1,2 @@ +{{movie.title}} \ No newline at end of file diff --git a/client/app/components/movie-poster/movie-poster.less b/client/app/components/movie-poster/movie-poster.less new file mode 100644 index 0000000..6249601 --- /dev/null +++ b/client/app/components/movie-poster/movie-poster.less @@ -0,0 +1,7 @@ +movie-poster { + display: block; + .poster { + width: 154px; + height: 231px; + } +} diff --git a/client/app/components/movie/movie.html b/client/app/components/movie/movie.html index 077d32a..0da6bc0 100644 --- a/client/app/components/movie/movie.html +++ b/client/app/components/movie/movie.html @@ -1,4 +1,2 @@ -

{{movie.title}}

-{{movie.title}} + Read more diff --git a/client/app/components/movies-connector/moviesConnector.factory.js b/client/app/components/movies-connector/moviesConnector.factory.js index 0d2186b..5cd3886 100644 --- a/client/app/components/movies-connector/moviesConnector.factory.js +++ b/client/app/components/movies-connector/moviesConnector.factory.js @@ -20,13 +20,16 @@ cachedConfiguration: null, topRatedMovies: topRatedMovies, configuration: configuration, - search: search + search: search, + movieInfo: movieInfo }; function topRatedMovies() { return $http.get('/api/movies/'); } - + function movieInfo(movieId) { + return $http.get('/api/movies/info/' + movieId); + } function search(query) { return $http.get('/api/movies/search/' + query); } diff --git a/client/app/pages/movie/movie-page.controller.js b/client/app/pages/movie/movie-page.controller.js new file mode 100644 index 0000000..d37511e --- /dev/null +++ b/client/app/pages/movie/movie-page.controller.js @@ -0,0 +1,20 @@ +(function() { + 'use strict'; + + angular + .module('moviesApp') + .controller('MoviePageController', MoviePageController); + + MoviePageController.$inject = [ + 'movie', + 'moviesConnector' + ]; + + /* @ngInject */ + function MoviePageController(movie, topMovies, moviesConnector){ + var vm = this; + vm.movie = movie; + + + } +})(); diff --git a/client/app/pages/movie/movie-page.controller.spec.js b/client/app/pages/movie/movie-page.controller.spec.js new file mode 100644 index 0000000..3d5d47b --- /dev/null +++ b/client/app/pages/movie/movie-page.controller.spec.js @@ -0,0 +1,38 @@ +'use strict'; + +describe('Controller: MainCtrl', function () { + + // load the controller's module + beforeEach(module('moviesApp', function ($provide) { + $provide.value('movies', {data: {results: []}}); + $provide.value('topMovies', {data: {results: []}}); + + })); + + var controller, + scope, + $httpBackend; + + // Initialize the controller and a mock scope + beforeEach(inject(function (_$httpBackend_, $controller, $rootScope) { + $httpBackend = _$httpBackend_; + $httpBackend.expectGET('/api/movies/search/star') + .respond({ + results:[ + {title: 'Star Wars'}, + {title: 'Star Trek'} + ] + }); + + scope = $rootScope.$new(); + controller = $controller('SearchPageController', { + $scope: scope + }); + })); + + it('should updateNames properly', function () { + controller.updatedSearch('star'); + $httpBackend.flush(); + expect(controller.topMovieNames.length).to.equal(2); + }); +}); diff --git a/client/app/pages/movie/movie-page.html b/client/app/pages/movie/movie-page.html new file mode 100644 index 0000000..aefa66a --- /dev/null +++ b/client/app/pages/movie/movie-page.html @@ -0,0 +1,23 @@ +

{{movieVm.movie.title}}

+
+
+ + +
+
+

{{movieVm.movie.overview}}

+

Genres: {{genre.name}}

+ Check in IMDB +
+
+

Similar Movies

+
+
+ +
+
+
+
+
Movie Format: {{movieVm.movie | json}}
+
+ diff --git a/client/app/pages/movie/movie-page.route.js b/client/app/pages/movie/movie-page.route.js new file mode 100644 index 0000000..2dcdea9 --- /dev/null +++ b/client/app/pages/movie/movie-page.route.js @@ -0,0 +1,36 @@ +(function() { + 'use strict'; + + angular + .module('moviesApp') + .config(configRouteListing); + + configRouteListing.$inject = [ + '$stateProvider' + ]; + + function configRouteListing ($stateProvider) { + + $stateProvider + .state('movie-page', { + url: '/movie/:movieId', + title: 'Movie', + templateUrl: 'app/pages/movie/movie-page.html', + controller: 'MoviePageController', + controllerAs: 'movieVm', + resolve: { + movie: ['$stateParams', 'moviesConnector', + function($stateParams, moviesConnector) { + if($stateParams.movieId) { + return moviesConnector.movieInfo($stateParams.movieId) + .then(function (response) { + return response.data; + }); + } else { + + } + }] + } + }); + } +})(); diff --git a/client/index.html b/client/index.html index 687cba4..a3458b5 100644 --- a/client/index.html +++ b/client/index.html @@ -70,6 +70,7 @@ + @@ -82,6 +83,8 @@ + + diff --git a/server/api/movies/index.js b/server/api/movies/index.js index 8300a18..ffd7eda 100644 --- a/server/api/movies/index.js +++ b/server/api/movies/index.js @@ -11,7 +11,7 @@ if (!process.env.MOVIEDB_API) { } else { var controller = require('./movies.controller'); router.get('/', controller.index); - router.get('/:movieId', controller.get); + router.get('/info/:movieId', controller.get); router.get('/configuration', controller.configuration); router.get('/playing', controller.nowPlaying); router.get('/search/:query', controller.search); diff --git a/server/api/movies/movies.controller.js b/server/api/movies/movies.controller.js index 662489a..7c9f126 100644 --- a/server/api/movies/movies.controller.js +++ b/server/api/movies/movies.controller.js @@ -104,8 +104,12 @@ function configuration(req, res){ } function get(req, res) { - MovieDB.movieInfo({id: req.params.id}, function(err, response){ - res.json(response); + MovieDB.movieInfo({id: req.params.movieId}, function(err, response){ + MovieDB.movieSimilar({id: req.params.movieId}, function (errSimilar, responseSimilar) { + response.similar = responseSimilar; + res.json(response); + }) + }); } From 8a852b4cdcf9626005998eab2ef6ca9634ae9767 Mon Sep 17 00:00:00 2001 From: aotaduy Date: Thu, 12 Nov 2015 10:24:13 -0300 Subject: [PATCH 07/15] Removed test --- .../pages/movie/movie-page.controller.spec.js | 38 ------------------- client/app/pages/movie/movie-page.html | 3 +- 2 files changed, 1 insertion(+), 40 deletions(-) delete mode 100644 client/app/pages/movie/movie-page.controller.spec.js diff --git a/client/app/pages/movie/movie-page.controller.spec.js b/client/app/pages/movie/movie-page.controller.spec.js deleted file mode 100644 index 3d5d47b..0000000 --- a/client/app/pages/movie/movie-page.controller.spec.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -describe('Controller: MainCtrl', function () { - - // load the controller's module - beforeEach(module('moviesApp', function ($provide) { - $provide.value('movies', {data: {results: []}}); - $provide.value('topMovies', {data: {results: []}}); - - })); - - var controller, - scope, - $httpBackend; - - // Initialize the controller and a mock scope - beforeEach(inject(function (_$httpBackend_, $controller, $rootScope) { - $httpBackend = _$httpBackend_; - $httpBackend.expectGET('/api/movies/search/star') - .respond({ - results:[ - {title: 'Star Wars'}, - {title: 'Star Trek'} - ] - }); - - scope = $rootScope.$new(); - controller = $controller('SearchPageController', { - $scope: scope - }); - })); - - it('should updateNames properly', function () { - controller.updatedSearch('star'); - $httpBackend.flush(); - expect(controller.topMovieNames.length).to.equal(2); - }); -}); diff --git a/client/app/pages/movie/movie-page.html b/client/app/pages/movie/movie-page.html index aefa66a..d98c8ac 100644 --- a/client/app/pages/movie/movie-page.html +++ b/client/app/pages/movie/movie-page.html @@ -2,11 +2,10 @@

{{movieVm.movie.title}}

-

{{movieVm.movie.overview}}

-

Genres: {{genre.name}}

+

Genres: {{genre.name}}

Check in IMDB
From 96430f9a22971e430720e14bb0cfb9f71def8d61 Mon Sep 17 00:00:00 2001 From: aotaduy Date: Thu, 12 Nov 2015 16:17:06 -0300 Subject: [PATCH 08/15] Added custom directives examples --- .../movie-poster/movie-poster.directive.js | 3 +- client/demo/custom-directives/index.html | 52 +++++++++++++++++++ .../modal-button.controller.js | 28 ++++++++++ .../modal-button.directive.js | 24 +++++++++ .../demo/custom-directives/modal-button.html | 20 +++++++ .../validate-password.directive.js | 38 ++++++++++++++ 6 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 client/demo/custom-directives/index.html create mode 100644 client/demo/custom-directives/modal-button.controller.js create mode 100644 client/demo/custom-directives/modal-button.directive.js create mode 100644 client/demo/custom-directives/modal-button.html create mode 100644 client/demo/custom-directives/validate-password.directive.js diff --git a/client/app/components/movie-poster/movie-poster.directive.js b/client/app/components/movie-poster/movie-poster.directive.js index d53be17..460fefa 100644 --- a/client/app/components/movie-poster/movie-poster.directive.js +++ b/client/app/components/movie-poster/movie-poster.directive.js @@ -9,8 +9,7 @@ restrict: 'E', templateUrl: 'app/components/movie-poster/movie-poster.html', scope: { - movie: '=', - type: '=' + movie: '=' } }; } diff --git a/client/demo/custom-directives/index.html b/client/demo/custom-directives/index.html new file mode 100644 index 0000000..3dafdc3 --- /dev/null +++ b/client/demo/custom-directives/index.html @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + +
+ +
+
+ + + +

{{modalTitle}}

+ + +

{{text}}

+ + + + +

This is a test

+

This is a test to reproduce a modal with a transclusion directive

+

{{modalTitle}} this is a test: {{text}}

+
{{number}}
+
+
+
+
+ + diff --git a/client/demo/custom-directives/modal-button.controller.js b/client/demo/custom-directives/modal-button.controller.js new file mode 100644 index 0000000..f1979a8 --- /dev/null +++ b/client/demo/custom-directives/modal-button.controller.js @@ -0,0 +1,28 @@ +(function() { + 'use strict'; + + // Create module and controller + angular + .module('custom-directives') + .controller('ModalButtonController', ModalButtonController); + + + ModalButtonController.$inject = [ + '$rootScope' + ]; + + function ModalButtonController($rootScope) { + // Controller as viewModel + var vm = this; + // Initialization + + + // Controller methods + vm.modalClosed = modalClosed + + function modalClosed () { + $rootScope.$emit('modalClosed'); + vm.onCancel(); + } + } +})(); diff --git a/client/demo/custom-directives/modal-button.directive.js b/client/demo/custom-directives/modal-button.directive.js new file mode 100644 index 0000000..75d4602 --- /dev/null +++ b/client/demo/custom-directives/modal-button.directive.js @@ -0,0 +1,24 @@ +(function() { + 'use strict'; + + angular + .module('custom-directives') + .directive('modalButton', modalButtonDirective); + + + function modalButtonDirective() { + return { + restrict: 'E', + templateUrl: '/demo/custom-directives/modal-button.html', + controller: 'ModalButtonController', + controllerAs: 'modalVm', + bindToController: true, + transclude: true, + scope: { + title: '=', + buttonText: '@', + onCancel: '&' + } + }; + } +})(); diff --git a/client/demo/custom-directives/modal-button.html b/client/demo/custom-directives/modal-button.html new file mode 100644 index 0000000..8d335df --- /dev/null +++ b/client/demo/custom-directives/modal-button.html @@ -0,0 +1,20 @@ +
+ +
+ \ No newline at end of file diff --git a/client/demo/custom-directives/validate-password.directive.js b/client/demo/custom-directives/validate-password.directive.js new file mode 100644 index 0000000..774e33d --- /dev/null +++ b/client/demo/custom-directives/validate-password.directive.js @@ -0,0 +1,38 @@ +(function() { + 'use strict'; + + angular + .module('custom-directives', []) + .directive('validatePassword', validatePasswordDirective); + + validatePasswordDirective.$inject = ['$parse']; + + function validatePasswordDirective($parse) { + return { + restrict: 'A', + link: linkValidatePassword + }; + + function linkValidatePassword(scope, element, attributes) { + var message, + showMessage = $parse(attributes.showMessage)(scope) || false ; + scope.$watch(function () { + return element.val(); + }, doValidation); + message = angular.element('Min Size Failed'); + if (showMessage){ + element.after(message); + } + message.hide(); + function doValidation(newValue) { + if (newValue.length > attributes.minLength && newValue.length < attributes.maxLength ) { + element.addClass('min-size'); + message.show(); + } else { + element.removeClass('min-size'); + message.hide(); + } + } + } + } +})(); From a6e62d0f31671159ab8b1b4ada14ee0ae87fc22b Mon Sep 17 00:00:00 2001 From: aotaduy Date: Fri, 13 Nov 2015 14:05:28 -0300 Subject: [PATCH 09/15] Added nedb cache for api calls --- .gitignore | 1 + .../movie-listing/movie-listing.html | 2 +- .../modal-button.controller.js | 2 +- package.json | 1 + server/api/movies/index.js | 30 ++-- server/api/movies/movies.controller.js | 168 ++++++------------ server/app.js | 5 + server/routes.js | 2 +- 8 files changed, 83 insertions(+), 128 deletions(-) diff --git a/.gitignore b/.gitignore index b475440..f8ce4ef 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ dist /server/config/local.env.js npm-debug.log coverage +cache.nedb \ No newline at end of file diff --git a/client/app/components/movie-listing/movie-listing.html b/client/app/components/movie-listing/movie-listing.html index 2c02d26..15fb7b6 100644 --- a/client/app/components/movie-listing/movie-listing.html +++ b/client/app/components/movie-listing/movie-listing.html @@ -1,3 +1,3 @@
- movie="movie"> +
diff --git a/client/demo/custom-directives/modal-button.controller.js b/client/demo/custom-directives/modal-button.controller.js index f1979a8..208ed28 100644 --- a/client/demo/custom-directives/modal-button.controller.js +++ b/client/demo/custom-directives/modal-button.controller.js @@ -3,7 +3,7 @@ // Create module and controller angular - .module('custom-directives') + .module('custom-directives', []) .controller('ModalButtonController', ModalButtonController); diff --git a/package.json b/package.json index f73cebc..fdb2256 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "method-override": "~1.0.0", "morgan": "~1.0.0", "moviedb": "^0.2.2", + "nedb": "^1.4.0", "omdb-client": "^1.0.6", "serve-favicon": "~2.0.1", "serve-index": "^1.7.2" diff --git a/server/api/movies/index.js b/server/api/movies/index.js index ffd7eda..7fd0291 100644 --- a/server/api/movies/index.js +++ b/server/api/movies/index.js @@ -3,18 +3,20 @@ var express = require('express'); var router = express.Router(); -if (!process.env.MOVIEDB_API) { - router.get('/', function(req, res){ - res.status({status: 404}); - res.json({error: 404}) - }); -} else { - var controller = require('./movies.controller'); - router.get('/', controller.index); - router.get('/info/:movieId', controller.get); - router.get('/configuration', controller.configuration); - router.get('/playing', controller.nowPlaying); - router.get('/search/:query', controller.search); +function createRouter(app) { + if (!process.env.MOVIEDB_API) { + router.get('/', function(req, res){ + res.status({status: 404}); + res.json({error: 404}) + }); + } else { + var controller = require('./movies.controller')(app) ; + router.get('/', controller.index); + router.get('/info/:movieId', controller.get); + router.get('/configuration', controller.configuration); + router.get('/playing', controller.nowPlaying); + router.get('/search/:query', controller.search); + } + return router; } - -module.exports = router; +module.exports = createRouter; diff --git a/server/api/movies/movies.controller.js b/server/api/movies/movies.controller.js index 7c9f126..66be312 100644 --- a/server/api/movies/movies.controller.js +++ b/server/api/movies/movies.controller.js @@ -9,125 +9,71 @@ 'use strict'; + var _ = require('lodash'), MovieDB = require('moviedb')(process.env.MOVIEDB_API); // Get list of things -exports.get = get; -exports.index = index; -exports.search = search; -exports.configuration = configuration; -exports.nowPlaying = nowPlaying; +function createRouteConfigs(app) { +var routeConfigs = {}; +routeConfigs.get = get; +routeConfigs.index = index; +routeConfigs.search = search; +routeConfigs.configuration = configuration; +routeConfigs.nowPlaying = nowPlaying; -function configuration(req, res){ - MovieDB.configuration(function(err, movies){ - console.log(err); - console.log(movies); - if (movies === null) { - res.json({ - "images": { - "base_url": "http://image.tmdb.org/t/p/", - "secure_base_url": "https://image.tmdb.org/t/p/", - "backdrop_sizes": [ - "w300", - "w780", - "w1280", - "original" - ], - "logo_sizes": [ - "w45", - "w92", - "w154", - "w185", - "w300", - "w500", - "original" - ], - "poster_sizes": [ - "w92", - "w154", - "w185", - "w342", - "w500", - "w780", - "original" - ], - "profile_sizes": [ - "w45", - "w185", - "h632", - "original" - ], - "still_sizes": [ - "w92", - "w185", - "w300", - "original" - ] - }, - "change_keys": [ - "adult", - "also_known_as", - "alternative_titles", - "biography", - "birthday", - "budget", - "cast", - "character_names", - "crew", - "deathday", - "general", - "genres", - "homepage", - "images", - "imdb_id", - "name", - "original_title", - "overview", - "plot_keywords", - "production_companies", - "production_countries", - "releases", - "revenue", - "runtime", - "spoken_languages", - "status", - "tagline", - "title", - "trailers", - "translations" - ] -}) - } - res.json(movies); - }); -} + function configuration(req, res){ + MovieDB.configuration(function(err, movies){ + console.log(err); + console.log(movies); + res.json(movies); + }); + } -function get(req, res) { - MovieDB.movieInfo({id: req.params.movieId}, function(err, response){ - MovieDB.movieSimilar({id: req.params.movieId}, function (errSimilar, responseSimilar) { - response.similar = responseSimilar; - res.json(response); - }) - - }); -} + function get(req, res) { + app.db.findOne({movieId: req.params.movieId}, function (err, result) { + if (result) { + res.json(result.movie) + } else{ + MovieDB.movieInfo({id: req.params.movieId}, function(err, response){ + MovieDB.movieSimilar({id: req.params.movieId}, function (errSimilar, responseSimilar) { + response.similar = responseSimilar; + app.db.insert({movieId: req.params.movieId, movie: response}); + res.json(response); + }) + + }); + } + }); + } -function search(req, res) { - MovieDB.searchMovie({query: req.params.query}, function(err, response){ - res.json(response); - }); -} -function nowPlaying(req, res) { - MovieDB.miscPopularMovies(function(err, movies){ - res.json(movies); - }); + function search(req, res) { + app.db.findOne({searchQuery: req.params.query}, function (err, result) { + if (result) { + res.json(result.searchResults) + } else{ + MovieDB.searchMovie({query: req.params.query}, function(err, response){ + app.db.insert({searchQuery: req.params.query, searchResults: response}); + res.json(response); + }); + } + }) + + } + function nowPlaying(req, res) { + MovieDB.miscPopularMovies(function(err, movies){ + res.json(movies); + }); -} -function index(req, res) { + } + function index(req, res) { - MovieDB.miscTopRatedMovies(function(err, movies){ - res.json(movies); - }); + MovieDB.miscTopRatedMovies(function(err, movies){ + res.json(movies); + }); + } + return routeConfigs; } + +module.exports = createRouteConfigs; \ No newline at end of file diff --git a/server/app.js b/server/app.js index 1dcd147..b1719aa 100644 --- a/server/app.js +++ b/server/app.js @@ -12,9 +12,14 @@ var config = require('./config/environment'); // Setup server var app = express(); var server = require('http').createServer(app); +var Datastore = require('nedb'); +app.db = new Datastore({ filename: './cache.nedb', autoload: true }); + require('./config/express')(app); require('./routes')(app); +//Open database + // Start server server.listen(config.port, config.ip, function () { console.log('Express server listening on %d, in %s mode', config.port, app.get('env')); diff --git a/server/routes.js b/server/routes.js index f7db227..37675a9 100644 --- a/server/routes.js +++ b/server/routes.js @@ -14,7 +14,7 @@ module.exports = function(app) { // Insert routes below app.use('/api/things', require('./api/thing')); - app.use('/api/movies', require('./api/movies')); + app.use('/api/movies', require('./api/movies')(app)); app.use('/api/random', require('./api/random')); // Serve demo directory app.use('/demo/', serveIndex(demoDir, {'icons': true})); From dc08726fcc4091df7f90ba69cfbee9bbece188ec Mon Sep 17 00:00:00 2001 From: aotaduy Date: Fri, 13 Nov 2015 17:49:26 -0300 Subject: [PATCH 10/15] Added routes --- client/app/pages/listing/listing-page.html | 1 - client/app/pages/movie/movie-page.debug.html | 3 + .../app/pages/movie/movie-page.debug.route.js | 20 +++ client/app/pages/movie/movie-page.edit.html | 21 ++++ .../app/pages/movie/movie-page.edit.route.js | 20 +++ client/app/pages/movie/movie-page.html | 17 ++- client/app/pages/movie/movie-page.route.js | 3 +- .../app/pages/movie/movie-page.similar.html | 8 ++ .../pages/movie/movie-page.similar.route.js | 20 +++ client/index.html | 3 + server/api/movies/movies.controller.js | 116 ++++++++++-------- 11 files changed, 169 insertions(+), 63 deletions(-) create mode 100644 client/app/pages/movie/movie-page.debug.html create mode 100644 client/app/pages/movie/movie-page.debug.route.js create mode 100644 client/app/pages/movie/movie-page.edit.html create mode 100644 client/app/pages/movie/movie-page.edit.route.js create mode 100644 client/app/pages/movie/movie-page.similar.html create mode 100644 client/app/pages/movie/movie-page.similar.route.js diff --git a/client/app/pages/listing/listing-page.html b/client/app/pages/listing/listing-page.html index 6276e10..ab433b0 100644 --- a/client/app/pages/listing/listing-page.html +++ b/client/app/pages/listing/listing-page.html @@ -1,7 +1,6 @@

Popular Movies {{listingVm.movies.length}}

-
diff --git a/client/app/pages/movie/movie-page.debug.html b/client/app/pages/movie/movie-page.debug.html new file mode 100644 index 0000000..cc0a946 --- /dev/null +++ b/client/app/pages/movie/movie-page.debug.html @@ -0,0 +1,3 @@ +
+{{movieVm.movie | json}}
+
\ No newline at end of file diff --git a/client/app/pages/movie/movie-page.debug.route.js b/client/app/pages/movie/movie-page.debug.route.js new file mode 100644 index 0000000..4765824 --- /dev/null +++ b/client/app/pages/movie/movie-page.debug.route.js @@ -0,0 +1,20 @@ +(function() { + 'use strict'; + + angular + .module('moviesApp') + .config(configRouteMovieDebug); + + configRouteMovieDebug.$inject = [ + '$stateProvider' + ]; + + function configRouteMovieDebug($stateProvider) { + + $stateProvider + .state('movie-page.debug', { + url: '/debug', + templateUrl: 'app/pages/movie/movie-page.debug.html', + }); + } +})(); diff --git a/client/app/pages/movie/movie-page.edit.html b/client/app/pages/movie/movie-page.edit.html new file mode 100644 index 0000000..44350ad --- /dev/null +++ b/client/app/pages/movie/movie-page.edit.html @@ -0,0 +1,21 @@ +

Editing

+
+
+

Title:

+ +

Overview:

+ +
+
+
+
+

Similar Movies

+ + {{similarMovie.title}} + +
+
diff --git a/client/app/pages/movie/movie-page.edit.route.js b/client/app/pages/movie/movie-page.edit.route.js new file mode 100644 index 0000000..aec914e --- /dev/null +++ b/client/app/pages/movie/movie-page.edit.route.js @@ -0,0 +1,20 @@ +(function() { + 'use strict'; + + angular + .module('moviesApp') + .config(configRouteMovieEdit); + + configRouteMovieEdit.$inject = [ + '$stateProvider' + ]; + + function configRouteMovieEdit($stateProvider) { + + $stateProvider + .state('movie-page.edit', { + url: '/edit', + templateUrl: 'app/pages/movie/movie-page.edit.html', + }); + } +})(); diff --git a/client/app/pages/movie/movie-page.html b/client/app/pages/movie/movie-page.html index d98c8ac..c8642da 100644 --- a/client/app/pages/movie/movie-page.html +++ b/client/app/pages/movie/movie-page.html @@ -9,14 +9,13 @@

{{movieVm.movie.title}}

Check in IMDB
-

Similar Movies

-
-
- -
-
-
-
-
Movie Format: {{movieVm.movie | json}}
+
+
+ + + +
+ +
diff --git a/client/app/pages/movie/movie-page.route.js b/client/app/pages/movie/movie-page.route.js index 2dcdea9..c585876 100644 --- a/client/app/pages/movie/movie-page.route.js +++ b/client/app/pages/movie/movie-page.route.js @@ -13,8 +13,9 @@ $stateProvider .state('movie-page', { - url: '/movie/:movieId', title: 'Movie', + url: '/movie/:movieId', + abstract: true, templateUrl: 'app/pages/movie/movie-page.html', controller: 'MoviePageController', controllerAs: 'movieVm', diff --git a/client/app/pages/movie/movie-page.similar.html b/client/app/pages/movie/movie-page.similar.html new file mode 100644 index 0000000..adde207 --- /dev/null +++ b/client/app/pages/movie/movie-page.similar.html @@ -0,0 +1,8 @@ +

Similar Movies

+
+
+ +
+
+
+
\ No newline at end of file diff --git a/client/app/pages/movie/movie-page.similar.route.js b/client/app/pages/movie/movie-page.similar.route.js new file mode 100644 index 0000000..c327fac --- /dev/null +++ b/client/app/pages/movie/movie-page.similar.route.js @@ -0,0 +1,20 @@ +(function() { + 'use strict'; + + angular + .module('moviesApp') + .config(configRouteMovieSimilar); + + configRouteListing.$inject = [ + '$stateProvider' + ]; + + function configRouteMovieSimilar($stateProvider) { + + $stateProvider + .state('movie-page.similar', { + url:'', + templateUrl: 'app/pages/movie/movie-page.similar.html', + }); + } +})(); diff --git a/client/index.html b/client/index.html index a3458b5..e845a3d 100644 --- a/client/index.html +++ b/client/index.html @@ -84,7 +84,10 @@ + + + diff --git a/server/api/movies/movies.controller.js b/server/api/movies/movies.controller.js index 66be312..3da7f5a 100644 --- a/server/api/movies/movies.controller.js +++ b/server/api/movies/movies.controller.js @@ -15,65 +15,77 @@ var _ = require('lodash'), // Get list of things function createRouteConfigs(app) { -var routeConfigs = {}; -routeConfigs.get = get; -routeConfigs.index = index; -routeConfigs.search = search; -routeConfigs.configuration = configuration; -routeConfigs.nowPlaying = nowPlaying; + var routeConfigs = {}; + routeConfigs.get = get; + routeConfigs.index = index; + routeConfigs.search = search; + routeConfigs.configuration = configuration; + routeConfigs.nowPlaying = nowPlaying; - function configuration(req, res){ - MovieDB.configuration(function(err, movies){ - console.log(err); - console.log(movies); - res.json(movies); - }); - } - - function get(req, res) { - app.db.findOne({movieId: req.params.movieId}, function (err, result) { - if (result) { - res.json(result.movie) - } else{ - MovieDB.movieInfo({id: req.params.movieId}, function(err, response){ - MovieDB.movieSimilar({id: req.params.movieId}, function (errSimilar, responseSimilar) { - response.similar = responseSimilar; - app.db.insert({movieId: req.params.movieId, movie: response}); - res.json(response); - }) - - }); + function configuration(req, res){ + app.db.findOne({configuration: 1}, function (err, result) { + if (result) { + res.json(result.configurationData); + } else{ + MovieDB.configuration(function(err, config){ + app.db.insert({configuration: 1, configurationData: config}); + res.json(config); + }); + } + }); } - }); - } - function search(req, res) { - app.db.findOne({searchQuery: req.params.query}, function (err, result) { - if (result) { - res.json(result.searchResults) - } else{ - MovieDB.searchMovie({query: req.params.query}, function(err, response){ - app.db.insert({searchQuery: req.params.query, searchResults: response}); + function get(req, res) { + app.db.findOne({movieId: req.params.movieId}, function (err, result) { + if (result) { + res.json(result.movie) + } else{ + MovieDB.movieInfo({id: req.params.movieId}, function(err, response){ + MovieDB.movieSimilar({id: req.params.movieId}, function (errSimilar, responseSimilar) { + response.similar = responseSimilar; + app.db.insert({movieId: req.params.movieId, movie: response}); res.json(response); - }); - } - }) - - } - function nowPlaying(req, res) { - MovieDB.miscPopularMovies(function(err, movies){ - res.json(movies); - }); + }) + + }); + } + }); + } - } - function index(req, res) { + function search(req, res) { + app.db.findOne({searchQuery: req.params.query}, function (err, result) { + if (result) { + res.json(result.searchResults) + } else{ + MovieDB.searchMovie({query: req.params.query}, function(err, response){ + app.db.insert({searchQuery: req.params.query, searchResults: response}); + res.json(response); + }); + } + }) + + } - MovieDB.miscTopRatedMovies(function(err, movies){ - res.json(movies); - }); + function nowPlaying(req, res) { + MovieDB.miscPopularMovies(function(err, movies){ + res.json(movies); + }); + + } - } - return routeConfigs; + function index(req, res) { + app.db.findOne({topRated: 1}, function (err, result) { + if (result) { + res.json(result.movies); + } else{ + MovieDB.miscTopRatedMovies(function(err, movies){ + app.db.insert({topRated: 1, movies: movies}); + res.json(movies); + }); + } + }); + } + return routeConfigs; } module.exports = createRouteConfigs; \ No newline at end of file From 7eed398082d8d134a8be03f68a4b82eb7b07e1c1 Mon Sep 17 00:00:00 2001 From: aotaduy Date: Mon, 16 Nov 2015 15:25:43 -0300 Subject: [PATCH 11/15] Animations --- bower.json | 16 ++++---- client/demo/todo-list-animations/index.html | 38 +++++++++++++++++++ .../todo-list.animations.css | 32 ++++++++++++++++ .../todo-list.animations2.css | 28 ++++++++++++++ .../todo-list.controller.js | 34 +++++++++++++++++ client/index.html | 8 ++-- 6 files changed, 146 insertions(+), 10 deletions(-) create mode 100644 client/demo/todo-list-animations/index.html create mode 100644 client/demo/todo-list-animations/todo-list.animations.css create mode 100644 client/demo/todo-list-animations/todo-list.animations2.css create mode 100644 client/demo/todo-list-animations/todo-list.controller.js diff --git a/bower.json b/bower.json index 9ebfc71..bd5a54b 100644 --- a/bower.json +++ b/bower.json @@ -3,16 +3,18 @@ "version": "0.0.0", "dependencies": { "angular": "~1.4.*", - "json3": "~3.3.1", - "es5-shim": "~3.0.1", - "bootstrap": "~3.1.1", - "angular-resource": ">=1.2.*", + "angular-animate": "~1.4.7", + "angular-bootstrap": "~0.14.0", "angular-cookies": ">=1.2.*", + "angular-resource": ">=1.2.*", "angular-sanitize": ">=1.2.*", - "angular-bootstrap": "~0.14.0", + "angular-ui-router": "~0.2.15", + "animate.css": "~3.4.0", + "bootstrap": "~3.1.1", + "es5-shim": "~3.0.1", "font-awesome": ">=4.1.0", - "lodash": "~2.4.1", - "angular-ui-router": "~0.2.15" + "json3": "~3.3.1", + "lodash": "~2.4.1" }, "devDependencies": { "angular-mocks": ">=1.2.*", diff --git a/client/demo/todo-list-animations/index.html b/client/demo/todo-list-animations/index.html new file mode 100644 index 0000000..830fa83 --- /dev/null +++ b/client/demo/todo-list-animations/index.html @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + +
+
+

Todo List #{{todoVm.list.length}}

+
+
+
+ + +
+
+

+ + {{item.text}} + +

+
+
+
+ + + diff --git a/client/demo/todo-list-animations/todo-list.animations.css b/client/demo/todo-list-animations/todo-list.animations.css new file mode 100644 index 0000000..454190a --- /dev/null +++ b/client/demo/todo-list-animations/todo-list.animations.css @@ -0,0 +1,32 @@ +.todo-item { + opacity:1; +} + +.todo-item.ng-leave { + transition:0.2s linear all; + opacity:1; +} + +.todo-item.ng-leave.ng-leave-active { + opacity:0; +} + +.todo-item.ng-enter { + transition:0.2s linear all; + opacity:0; + margin-left: -100px; +} + +.todo-item.ng-enter.ng-enter-active { + opacity:1; + margin-left: 0; +} + +.done-add, .done-remove { + transition: all ease-in 0.5s; +} + +.done { + opacity: 0.5; + background-color: gray; +} \ No newline at end of file diff --git a/client/demo/todo-list-animations/todo-list.animations2.css b/client/demo/todo-list-animations/todo-list.animations2.css new file mode 100644 index 0000000..157ae3c --- /dev/null +++ b/client/demo/todo-list-animations/todo-list.animations2.css @@ -0,0 +1,28 @@ +.todo-item { + opacity:1; +} + +.todo-item.ng-leave { + animation: bounceOutRight 1s; +} + + +.todo-item.ng-enter { + animation: bounceInLeft 1s; +} + +.todo-item.ng-enter.ng-enter-active { + opacity:1; + margin-left: 0; +} + +.done-add, .done-remove { + transition: all ease-in 0.5s; + animation: shake 0.5s; +} + +.done { + opacity: 0.5; + background-color: gray; +} + diff --git a/client/demo/todo-list-animations/todo-list.controller.js b/client/demo/todo-list-animations/todo-list.controller.js new file mode 100644 index 0000000..74dbee6 --- /dev/null +++ b/client/demo/todo-list-animations/todo-list.controller.js @@ -0,0 +1,34 @@ +(function() { + 'use strict'; + + // Create module and controller + angular + .module('todoListAnimationsDemo', ['ngAnimate']) + .controller('TodoListController', TodoListController); + + + TodoListController.$inject = [ + ]; + + function TodoListController() { + // Controller as viewModel + var vm = this; + // Initialization + vm.list = []; + vm.itemText = ''; + + // Controller methods + vm.add = add; + vm.remove = remove; + + /* Adds an item to the todo list */ + function add(text) { + vm.list.push({done: false, text: text}); + } + + /* Removes the item in the list with index: $index*/ + function remove(index) { + vm.list.splice(index,1); + } + } +})(); diff --git a/client/index.html b/client/index.html index e845a3d..2f82e12 100644 --- a/client/index.html +++ b/client/index.html @@ -13,6 +13,7 @@ + @@ -53,12 +54,13 @@ - + + + - - + From da195c245104edfb70c697e8a559812f2c4b5a77 Mon Sep 17 00:00:00 2001 From: aotaduy Date: Thu, 19 Nov 2015 16:42:48 -0300 Subject: [PATCH 12/15] Validation --- client/demo/validation/emailCom.directive.js | 31 ++++++++ client/demo/validation/index.html | 79 +++++++++++++++++++ .../demo/validation/same-letters.directive.js | 29 +++++++ 3 files changed, 139 insertions(+) create mode 100644 client/demo/validation/emailCom.directive.js create mode 100644 client/demo/validation/index.html create mode 100644 client/demo/validation/same-letters.directive.js diff --git a/client/demo/validation/emailCom.directive.js b/client/demo/validation/emailCom.directive.js new file mode 100644 index 0000000..a6f21da --- /dev/null +++ b/client/demo/validation/emailCom.directive.js @@ -0,0 +1,31 @@ +(function() { + 'use strict'; + + angular + .module('customValidation') + .directive('emailCom', emailComDirective); + + emailComDirective.$inject = []; + + function emailComDirective() { + return { + restrict: 'A', + require: 'ngModel', + link: emailComLink + }; + + function emailComLink(scope, element, attributes, ngModelController) { + var oldEmail; + oldEmail = ngModelController.$validators.email; + + ngModelController.$validators.email = validateEmail; + + scope.modelController = ngModelController; + + function validateEmail(viewValue, modelValue) { + + return modelValue === undefined || oldEmail(viewValue, modelValue) && modelValue.endsWith('.com'); + } + } + } +})(); diff --git a/client/demo/validation/index.html b/client/demo/validation/index.html new file mode 100644 index 0000000..c358656 --- /dev/null +++ b/client/demo/validation/index.html @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + +
+
+
+
+

User Registration

+
+ + +
+
+ + + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ +
+
+
+
+ Form invalid + Form Touched + + +
{{theForm | json}}
+
+
+
+ +
+ + + diff --git a/client/demo/validation/same-letters.directive.js b/client/demo/validation/same-letters.directive.js new file mode 100644 index 0000000..3fe53e7 --- /dev/null +++ b/client/demo/validation/same-letters.directive.js @@ -0,0 +1,29 @@ +(function() { + 'use strict'; + + angular + .module('customValidation', []) + .directive('sameLettersNumbers', sameLettersNumbersDirective); + + sameLettersNumbersDirective.$inject = []; + + function sameLettersNumbersDirective() { + return { + restrict: 'A', + require: 'ngModel', + link: sameLettersNumbersLink + }; + + function sameLettersNumbersLink(scope, element, attributes, ngModelController) { + + ngModelController.$validators.sameLettersNumbers = validateSameNumbers; + + function validateSameNumbers(viewValue, modelValue) { + var letters = (viewValue || ' ').match(/[A-Za-z]/g) || [], + numbers = (viewValue || ' ').match(/[0-9]/g) || []; + + return letters.length === numbers.length; + } + } + } +})(); From a5cf0ed998cee0fe0ddbb45fee49228e958f3327 Mon Sep 17 00:00:00 2001 From: aotaduy Date: Thu, 19 Nov 2015 19:06:45 -0300 Subject: [PATCH 13/15] updated readme --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e0df072..55035cf 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,8 @@ I haven't tested with newer versions but it should work anyway. ## For both envs ```` npm install grunt-cli bower -g -git clone https://github.com/aotaduy/angular-course.git +git clone https://github.com/aotaduy/angular-example.git +cd angular-example npm install bower install npm run update-webdriver @@ -50,9 +51,13 @@ The movie db example application uses the REST API at https://www.themoviedb.org Before running ``grunt serve`` you should set the environment variable (this is a fake key you shuld add your own): ```` +In Windows set MOVIEDB_API=72fa50138ba3dcfd588fd59a1375a810 ```` - +```` +In Linux +export MOVIEDB_API=72fa50138ba3dcfd588fd59a1375a810 +```` ## To run the app ```` grunt serve From 5d34ee7caff2ce3d5834874f1ded5b6a7ad6229e Mon Sep 17 00:00:00 2001 From: aotaduy Date: Tue, 24 Nov 2015 11:01:10 -0300 Subject: [PATCH 14/15] Fixed tests --- client/app/pages/movie/movie-page.similar.route.js | 2 +- client/demo/validation/customValidation.module.js | 4 ++++ client/demo/validation/index.html | 1 + client/demo/validation/same-letters.directive.js | 2 +- 4 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 client/demo/validation/customValidation.module.js diff --git a/client/app/pages/movie/movie-page.similar.route.js b/client/app/pages/movie/movie-page.similar.route.js index c327fac..29a503e 100644 --- a/client/app/pages/movie/movie-page.similar.route.js +++ b/client/app/pages/movie/movie-page.similar.route.js @@ -5,7 +5,7 @@ .module('moviesApp') .config(configRouteMovieSimilar); - configRouteListing.$inject = [ + configRouteMovieSimilar.$inject = [ '$stateProvider' ]; diff --git a/client/demo/validation/customValidation.module.js b/client/demo/validation/customValidation.module.js new file mode 100644 index 0000000..9510880 --- /dev/null +++ b/client/demo/validation/customValidation.module.js @@ -0,0 +1,4 @@ +(function() { + 'use strict'; + angular.module('customValidation', []); +})(); \ No newline at end of file diff --git a/client/demo/validation/index.html b/client/demo/validation/index.html index c358656..eeb4dd8 100644 --- a/client/demo/validation/index.html +++ b/client/demo/validation/index.html @@ -6,6 +6,7 @@ + diff --git a/client/demo/validation/same-letters.directive.js b/client/demo/validation/same-letters.directive.js index 3fe53e7..2091599 100644 --- a/client/demo/validation/same-letters.directive.js +++ b/client/demo/validation/same-letters.directive.js @@ -2,7 +2,7 @@ 'use strict'; angular - .module('customValidation', []) + .module('customValidation') .directive('sameLettersNumbers', sameLettersNumbersDirective); sameLettersNumbersDirective.$inject = []; From 3583249062d22fe0736bf49c2cc1e51b5e61d5ee Mon Sep 17 00:00:00 2001 From: amfranco Date: Sun, 29 Nov 2015 16:58:40 -0300 Subject: [PATCH 15/15] Added a test to the controller --- client/demo/expenses/index.html | 1 + client/demo/expenses/script.js | 3 ++ client/demo/expenses/script.spec.js | 56 +++++++++++++++++++++++++++++ e2e/expenses/main.spec.js | 30 ++++++++++++++++ 4 files changed, 90 insertions(+) create mode 100644 client/demo/expenses/script.spec.js create mode 100644 e2e/expenses/main.spec.js diff --git a/client/demo/expenses/index.html b/client/demo/expenses/index.html index 927b714..4781438 100644 --- a/client/demo/expenses/index.html +++ b/client/demo/expenses/index.html @@ -4,6 +4,7 @@ + diff --git a/client/demo/expenses/script.js b/client/demo/expenses/script.js index 6d01ad9..bef93f1 100644 --- a/client/demo/expenses/script.js +++ b/client/demo/expenses/script.js @@ -44,14 +44,17 @@ // Calculate expense total. function total(type) { var sum = 0; + var list = vm.list; if (type !== '') { // filter by expense type list = $filter('filter')(vm.list, { type: type }); } + angular.forEach(list, function(expense, key) { sum += expense.amount; }); + return sum; } } diff --git a/client/demo/expenses/script.spec.js b/client/demo/expenses/script.spec.js new file mode 100644 index 0000000..1f1d8c6 --- /dev/null +++ b/client/demo/expenses/script.spec.js @@ -0,0 +1,56 @@ + +describe('Controller: todo-list', function() { + 'use strict'; + var controller, + scope; + // Refresh the $filter every time. + beforeEach(module('expensesDemo')); + beforeEach(inject(function(_$rootScope_, $controller) { + scope = _$rootScope_.$new(); + filter = scope.get('$filter'); + controller = $controller('ExpensesController', + {$scope: scope, $filter: filter}); + }) + ); + + it('should start empty', function() { + expect(controller.list.length).to.equal(0); + }); + + it('add item to the list', function() { + var item1 = {date: '2015/11/16', type:'food', description:'hot dog', amount: 1.25}; + controller.add(item1); + expect(controller.list.length).to.equal(1); + var item2 = {date: '2015/11/24', type:'financial', description:'credit', amount: 50000}; + controller.add(item2); + expect(controller.list.length).to.equal(2); + }); + + it('remove item', function() { + var item = {date: '2015/11/16', type:'food', description:'hot dog', amount: 1.25}; + controller.add(item); + expect(controller.list.length).to.equal(1); + + controller.remove(0); + expect(controller.list.length).to.equal(0); + }); + + it('calculate total', function() { + var item1 = {date: '2015/11/16', type:'food', description:'hot dog', amount: 1.25}; + controller.add(item1); + expect(controller.list.length).to.equal(1); + var item2 = {date: '2015/11/18', type:'food', description:'dinner', amount: 12.50}; + controller.add(item2); + expect(controller.list.length).to.equal(2); + var item3 = {date: '2015/11/24', type:'financial', description:'credit', amount: 50000}; + controller.add(item3); + expect(controller.list.length).to.equal(3); + + var total1 = controller.total('food'); + expect(total1).to.equal(13.75); + expect(controller.total('financial')).to.equal(50000); + expect(controller.total()).to.equal(150013.75); + }); + + +}); diff --git a/e2e/expenses/main.spec.js b/e2e/expenses/main.spec.js new file mode 100644 index 0000000..7763a18 --- /dev/null +++ b/e2e/expenses/main.spec.js @@ -0,0 +1,30 @@ +'use strict'; + +describe('Expenses', function() { + var page; + + beforeEach(function() { + browser.get('/demo/expenses/'); + page = {}; + }); + + it('should add an expense', function() { + page.date = element(by.id('date')); + page.type = element(by.id('type')); + page.description = element(by.id('description')); + page.amount = element(by.id('amount')); + page.button = element(by.id('add-button')); + + page.date.sendKeys('11/25/2015'); + page.type.sendKeys('financial'); + page.description.sendKeys('credit'); + page.amount.sendKeys('21000'); + page.button.click(); + + var todoList = element.all(by.repeater('expense in expensesVm.list')); + expect(todoList.count()).to.eventually.equal(1); + var total = $('.row.total .ng-binding').getText(); + expect(total).to.eventually.equal('21000'); + + }); +});