diff options
34 files changed, 477 insertions, 516 deletions
diff --git a/docs/content/api/angular.inputType.ngdoc b/docs/content/api/angular.inputType.ngdoc index 76a907d1..bfd5fe6f 100644 --- a/docs/content/api/angular.inputType.ngdoc +++ b/docs/content/api/angular.inputType.ngdoc @@ -40,8 +40,8 @@ All `inputType` widgets support: <doc:example> <doc:source> <script> - angular.inputType('json', function() { - this.$parseView = function() { + angular.inputType('json', function(element, scope) { + scope.$parseView = function() { try { this.$modelValue = angular.fromJson(this.$viewValue); if (this.$error.JSON) { @@ -52,19 +52,19 @@ All `inputType` widgets support: } } - this.$parseModel = function() { + scope.$parseModel = function() { this.$viewValue = angular.toJson(this.$modelValue); } }); - function Ctrl() { - this.data = { + function Ctrl($scope) { + $scope.data = { framework:'angular', codenames:'supper-powers' } - this.required = false; - this.disabled = false; - this.readonly = false; + $scope.required = false; + $scope.disabled = false; + $scope.readonly = false; } </script> <div ng:controller="Ctrl"> diff --git a/docs/content/cookbook/advancedform.ngdoc b/docs/content/cookbook/advancedform.ngdoc index e973e30f..58a8dfd5 100644 --- a/docs/content/cookbook/advancedform.ngdoc +++ b/docs/content/cookbook/advancedform.ngdoc @@ -8,10 +8,8 @@ detection, and preventing invalid form submission. <doc:example> <doc:source> <script> - function UserForm() { - this.state = /^\w\w$/; - this.zip = /^\d\d\d\d\d$/; - this.master = { + function UserForm($scope) { + var master = { name: 'John Smith', address:{ line1: '123 Main St.', @@ -23,40 +21,42 @@ detection, and preventing invalid form submission. {type:'phone', value:'1(234) 555-1212'} ] }; - this.cancel(); - } - UserForm.prototype = { - cancel: function() { - this.form = angular.copy(this.master); - }, + $scope.state = /^\w\w$/; + $scope.zip = /^\d\d\d\d\d$/; - save: function() { - this.master = this.form; - this.cancel(); - }, + $scope.cancel = function() { + $scope.form = angular.copy(master); + }; - addContact: function() { - this.form.contacts.push({type:'', value:''}); - }, + $scope.save = function() { + master = $scope.form; + $scope.cancel(); + }; + + $scope.addContact = function() { + $scope.form.contacts.push({type:'', value:''}); + }; - removeContact: function(contact) { - for ( var i = 0, ii = this.form.contacts.length; i < ii; i++) { - if (contact === this.form.contacts[i]) { - this.form.contacts.splice(i, 1); + $scope.removeContact = function(contact) { + var contacts = $scope.form.contacts; + for (var i = 0, ii = contacts.length; i < ii; i++) { + if (contact === contacts[i]) { + contacts.splice(i, 1); } } - }, + }; - isCancelDisabled: function() { - return angular.equals(this.master, this.form); - }, + $scope.isCancelDisabled = function() { + return angular.equals(master, $scope.form); + }; - isSaveDisabled: function() { - return this.myForm.$invalid || angular.equals(this.master, this.form); - } + $scope.isSaveDisabled = function() { + return $scope.myForm.$invalid || angular.equals(master, $scope.form); + }; - }; + $scope.cancel(); + } </script> <div ng:controller="UserForm"> @@ -91,8 +91,7 @@ detection, and preventing invalid form submission. <hr/> Debug View: - <pre>form={{form}} - master={{master}}</pre> + <pre>form={{form}}</pre> </div> </doc:source> <doc:scenario> diff --git a/docs/content/cookbook/deeplinking.ngdoc b/docs/content/cookbook/deeplinking.ngdoc index 2ef3da4a..a4dc3a9b 100644 --- a/docs/content/cookbook/deeplinking.ngdoc +++ b/docs/content/cookbook/deeplinking.ngdoc @@ -39,42 +39,38 @@ The two partials are defined in the following URLs: <doc:example> <doc:source jsfiddle="false"> <script> - AppCntl.$inject = ['$route'] - function AppCntl($route) { + AppCntl.$inject = ['$scope', '$route'] + function AppCntl($scope, $route) { // define routes $route.when("/welcome", {template:'./examples/welcome.html', controller:WelcomeCntl}); $route.when("/settings", {template:'./examples/settings.html', controller:SettingsCntl}); - $route.parent(this); + $route.parent($scope); // initialize the model to something useful - this.person = { + $scope.person = { name:'anonymous', contacts:[{type:'email', url:'anonymous@example.com'}] }; } - function WelcomeCntl($route){} - WelcomeCntl.prototype = { - greet: function() { - alert("Hello " + this.person.name); - } - }; - - SettingsCntl.$inject = ['$location']; - function SettingsCntl($location){ - this.$location = $location; - this.cancel(); + function WelcomeCntl($scope) { + $scope.greet = function() { + alert("Hello " + $scope.person.name); + }; + } + + function SettingsCntl($scope, $location) { + $scope.cancel = function() { + $scope.form = angular.copy($scope.person); + }; + + $scope.save = function() { + angular.copy($scope.form, $scope.person); + $location.path('/welcome'); + }; + + $scope.cancel(); } - SettingsCntl.prototype = { - cancel: function() { - this.form = angular.copy(this.person); - }, - - save: function() { - angular.copy(this.form, this.person); - this.$location.path('/welcome'); - } - }; </script> <div ng:controller="AppCntl"> <h1>Your App Chrome</h1> diff --git a/docs/content/cookbook/form.ngdoc b/docs/content/cookbook/form.ngdoc index 80c23e94..9371da7a 100644 --- a/docs/content/cookbook/form.ngdoc +++ b/docs/content/cookbook/form.ngdoc @@ -10,23 +10,23 @@ allow a user to enter data. <doc:example> <doc:source> <script> - function FormController() { - this.user = { + function FormController($scope) { + $scope.user = { name: 'John Smith', address:{line1: '123 Main St.', city:'Anytown', state:'AA', zip:'12345'}, contacts:[{type:'phone', value:'1(234) 555-1212'}] }; - this.state = /^\w\w$/; - this.zip = /^\d\d\d\d\d$/; + $scope.state = /^\w\w$/; + $scope.zip = /^\d\d\d\d\d$/; - this.addContact = function() { - this.user.contacts.push({type:'', value:''}); + $scope.addContact = function() { + $scope.user.contacts.push({type:'', value:''}); }; - this.removeContact = function(contact) { - for ( var i = 0, ii = this.user.contacts.length; i < ii; i++) { + $scope.removeContact = function(contact) { + for (var i = 0, ii = this.user.contacts.length; i < ii; i++) { if (contact === this.user.contacts[i]) { - this.user.contacts.splice(i, 1); + $scope.user.contacts.splice(i, 1); } } }; diff --git a/docs/content/cookbook/helloworld.ngdoc b/docs/content/cookbook/helloworld.ngdoc index e3d76d83..b6b5bcf7 100644 --- a/docs/content/cookbook/helloworld.ngdoc +++ b/docs/content/cookbook/helloworld.ngdoc @@ -5,8 +5,8 @@ <doc:example> <doc:source> <script> - function HelloCntl() { - this.name = 'World'; + function HelloCntl($scope) { + $scope.name = 'World'; } </script> <div ng:controller="HelloCntl"> diff --git a/docs/content/cookbook/mvc.ngdoc b/docs/content/cookbook/mvc.ngdoc index f566a541..71e771bd 100644 --- a/docs/content/cookbook/mvc.ngdoc +++ b/docs/content/cookbook/mvc.ngdoc @@ -14,9 +14,8 @@ no connection between the controller and the view. <doc:example> <doc:source> <script> - function TicTacToeCntl($location){ - this.$location = $location; - this.cellStyle= { + function TicTacToeCntl($scope, $location) { + $scope.cellStyle= { 'height': '20px', 'width': '20px', 'border': '1px solid black', @@ -24,30 +23,40 @@ no connection between the controller and the view. 'vertical-align': 'middle', 'cursor': 'pointer' }; - this.reset(); - this.$watch('$location.search().board', this.readUrl); - } - TicTacToeCntl.prototype = { - dropPiece: function(row, col) { - if (!this.winner && !this.board[row][col]) { - this.board[row][col] = this.nextMove; - this.nextMove = this.nextMove == 'X' ? 'O' : 'X'; - this.setUrl(); - } - }, - reset: function() { - this.board = [ + + $scope.reset = function() { + $scope.board = [ ['', '', ''], ['', '', ''], ['', '', ''] ]; - this.nextMove = 'X'; - this.winner = ''; - this.setUrl(); - }, - grade: function() { - var b = this.board; - this.winner = + $scope.nextMove = 'X'; + $scope.winner = ''; + setUrl(); + }; + + $scope.dropPiece = function(row, col) { + if (!$scope.winner && !$scope.board[row][col]) { + $scope.board[row][col] = $scope.nextMove; + $scope.nextMove = $scope.nextMove == 'X' ? 'O' : 'X'; + setUrl(); + } + }; + + $scope.reset(); + $scope.$watch(function() { return $location.search().board;}, readUrl); + + function setUrl() { + var rows = []; + angular.forEach($scope.board, function(row) { + rows.push(row.join(',')); + }); + $location.search({board: rows.join(';') + '/' + $scope.nextMove}); + } + + function grade() { + var b = $scope.board; + $scope.winner = row(0) || row(1) || row(2) || col(0) || col(1) || col(2) || diagonal(-1) || diagonal(1); @@ -55,25 +64,19 @@ no connection between the controller and the view. function col(col) { return same(b[0][col], b[1][col], b[2][col]);} function diagonal(i) { return same(b[0][1-i], b[1][1], b[2][1+i]);} function same(a, b, c) { return (a==b && b==c) ? a : '';}; - }, - setUrl: function() { - var rows = []; - angular.forEach(this.board, function(row){ - rows.push(row.join(',')); - }); - this.$location.search({board: rows.join(';') + '/' + this.nextMove}); - }, - readUrl: function(scope, value) { + } + + function readUrl(scope, value) { if (value) { value = value.split('/'); - this.nextMove = value[1]; + $scope.nextMove = value[1]; angular.forEach(value[0].split(';'), function(row, col){ - this.board[col] = row.split(','); - }, this); - this.grade(); + $scope.board[col] = row.split(','); + }); + grade(); } } - }; + } </script> <h3>Tic-Tac-Toe</h3> diff --git a/docs/content/guide/dev_guide.expressions.ngdoc b/docs/content/guide/dev_guide.expressions.ngdoc index 4df69d28..b7ecc521 100644 --- a/docs/content/guide/dev_guide.expressions.ngdoc +++ b/docs/content/guide/dev_guide.expressions.ngdoc @@ -51,14 +51,14 @@ You can try evaluating different expressions here: <doc:example> <doc:source> <script> - function Cntl2() { - this.exprs = []; - this.expr = '3*10|currency'; - this.addExp = function(expr) { + function Cntl2($scope) { + $scope.exprs = []; + $scope.expr = '3*10|currency'; + $scope.addExp = function(expr) { this.exprs.push(expr); }; - this.removeExp = function(contact) { + $scope.removeExp = function(contact) { for ( var i = 0, ii = this.exprs.length; i < ii; i++) { if (contact === this.exprs[i]) { this.exprs.splice(i, 1); @@ -101,10 +101,10 @@ the global state (a common source of subtle bugs). <doc:example> <doc:source> <script> - function Cntl1($window){ - this.name = 'World'; + function Cntl1($window, $scope){ + $scope.name = 'World'; - this.greet = function() { + $scope.greet = function() { ($window.mockWindow || $window).alert('Hello ' + this.name); } } diff --git a/docs/content/guide/dev_guide.forms.ngdoc b/docs/content/guide/dev_guide.forms.ngdoc index b4e37abd..03d0e6f9 100644 --- a/docs/content/guide/dev_guide.forms.ngdoc +++ b/docs/content/guide/dev_guide.forms.ngdoc @@ -111,10 +111,10 @@ The following example demonstrates: .ng-form {display: block;} </style> <script> - function UserFormCntl() { - this.state = /^\w\w$/; - this.zip = /^\d\d\d\d\d$/; - this.master = { + function UserFormCntl($scope) { + $scope.state = /^\w\w$/; + $scope.zip = /^\d\d\d\d\d$/; + $scope.master = { customer: 'John Smith', address:{ line1: '123 Main St.', @@ -123,28 +123,26 @@ The following example demonstrates: zip:'12345' } }; - this.cancel(); - } - UserFormCntl.prototype = { - cancel: function() { - this.form = angular.copy(this.master); - }, + $scope.cancel = function() { + $scope.form = angular.copy($scope.master); + }; - save: function() { - this.master = this.form; - this.cancel(); - }, + $scope.save = function() { + $scope.master = $scope.form; + $scope.cancel(); + }; - isCancelDisabled: function() { - return angular.equals(this.master, this.form); - }, + $scope.isCancelDisabled = function() { + return angular.equals($scope.master, $scope.form); + }; - isSaveDisabled: function() { - return this.userForm.$invalid || angular.equals(this.master, this.form); - } + $scope.isSaveDisabled = function() { + return $scope.userForm.$invalid || angular.equals($scope.master, $scope.form); + }; - }; + $scope.cancel(); + } </script> <div ng:controller="UserFormCntl"> @@ -282,15 +280,13 @@ This example shows how to implement a custom HTML editor widget in Angular. <doc:example> <doc:source> <script> - function EditorCntl() { - this.htmlContent = '<b>Hello</b> <i>World</i>!'; + function EditorCntl($scope) { + $scope.htmlContent = '<b>Hello</b> <i>World</i>!'; } - HTMLEditorWidget.$inject = ['$element', 'htmlFilter']; - function HTMLEditorWidget(element, htmlFilter) { - var self = this; - - this.$parseModel = function() { + HTMLEditorWidget.$inject = ['$element', '$scope', 'htmlFilter']; + function HTMLEditorWidget(element, scope, htmlFilter) { + scope.$parseModel = function() { // need to protect for script injection try { this.$viewValue = htmlFilter( @@ -305,13 +301,13 @@ This example shows how to implement a custom HTML editor widget in Angular. } } - this.$render = function() { + scope.$render = function() { element.html(this.$viewValue); } element.bind('keyup', function() { - self.$apply(function() { - self.$emit('$viewChange', element.html()); + scope.$apply(function() { + scope.$emit('$viewChange', element.html()); }); }); } @@ -364,13 +360,13 @@ validation. <doc:example> <doc:source> <script> - function Ctrl() { - this.input1 = ''; - this.input2 = ''; - this.input3 = 'A'; - this.input4 = false; - this.input5 = 'c'; - this.input6 = []; + function Ctrl($scope) { + $scope.input1 = ''; + $scope.input2 = ''; + $scope.input3 = 'A'; + $scope.input4 = false; + $scope.input5 = 'c'; + $scope.input6 = []; } </script> <table style="font-size:.9em;" ng:controller="Ctrl"> diff --git a/docs/content/guide/dev_guide.overview.ngdoc b/docs/content/guide/dev_guide.overview.ngdoc index 5d308167..faf40af5 100644 --- a/docs/content/guide/dev_guide.overview.ngdoc +++ b/docs/content/guide/dev_guide.overview.ngdoc @@ -43,9 +43,9 @@ easier a web developer's life can if they're using angular: <doc:example> <doc:source> <script> - function InvoiceCntl() { - this.qty = 1; - this.cost = 19.95; + function InvoiceCntl($scope) { + $scope.qty = 1; + $scope.cost = 19.95; } </script> <div ng:controller="InvoiceCntl"> diff --git a/docs/content/guide/dev_guide.templates.filters.creating_filters.ngdoc b/docs/content/guide/dev_guide.templates.filters.creating_filters.ngdoc index 98b41411..87894227 100644 --- a/docs/content/guide/dev_guide.templates.filters.creating_filters.ngdoc +++ b/docs/content/guide/dev_guide.templates.filters.creating_filters.ngdoc @@ -34,8 +34,8 @@ text upper-case and assigns color. } }); - function Ctrl() { - this.greeting = 'hello'; + function Ctrl($scope) { + $scope.greeting = 'hello'; } </script> diff --git a/docs/src/templates/docs.js b/docs/src/templates/docs.js index 38a75236..bf279df5 100644 --- a/docs/src/templates/docs.js +++ b/docs/src/templates/docs.js @@ -1,9 +1,8 @@ -DocsController.$inject = ['$location', '$window', '$cookies', '$filter']; -function DocsController($location, $window, $cookies, $filter) { - window.$root = this.$root; +DocsController.$inject = ['$scope', '$location', '$window', '$cookies', '$filter']; +function DocsController(scope, $location, $window, $cookies, $filter) { + window.$root = scope.$root; - var scope = this, - OFFLINE_COOKIE_NAME = 'ng-offline', + var OFFLINE_COOKIE_NAME = 'ng-offline', DOCS_PATH = /^\/(api)|(guide)|(cookbook)|(misc)|(tutorial)/, INDEX_PATH = /^(\/|\/index[^\.]*.html)$/, filter = $filter('filter'); @@ -160,6 +159,6 @@ angular.module('ngdocs', [], function($locationProvider, $filterProvider) { return text && text.replace(/^angular\.module\.([^\.]+)(\.(.*))?$/, function(_, module, _0, name){ return 'Module ' + module + (name ? ' - ' + name : ''); }); - } + }; }); }); diff --git a/example/personalLog/personalLog.js b/example/personalLog/personalLog.js index 7be233cb..4d182227 100644 --- a/example/personalLog/personalLog.js +++ b/example/personalLog/personalLog.js @@ -26,26 +26,26 @@ var LOGS = 'logs'; /** * The controller for the personal log app. */ -function LogCtrl($cookieStore) { - var self = this, - logs = self.logs = $cookieStore.get(LOGS) || []; //main model +function LogCtrl($cookieStore, $scope) { + + var logs = $scope.logs = $cookieStore.get(LOGS) || []; //main model /** * Adds newMsg to the logs array as a log, persists it and clears newMsg. * @param {string} msg Message to add (message is passed as parameter to make testing easier). */ - this.addLog = function(msg) { - var newMsg = msg || self.newMsg; + $scope.addLog = function(msg) { + var newMsg = msg || $scope.newMsg; if (!newMsg) return; var log = { at: new Date().getTime(), msg: newMsg - } + }; logs.push(log); $cookieStore.put(LOGS, logs); - self.newMsg = ''; + $scope.newMsg = ''; }; @@ -53,7 +53,7 @@ function LogCtrl($cookieStore) { * Persistently removes a log from logs. * @param {object} log The log to remove. */ - this.rmLog = function(log) { + $scope.rmLog = function(log) { for ( var i = 0; i < logs.length; i++) { if (log === logs[i]) { logs.splice(i, 1); @@ -68,14 +68,14 @@ function LogCtrl($cookieStore) { /** * Persistently removes all logs. */ - this.rmLogs = function() { + $scope.rmLogs = function() { logs.splice(0, logs.length); $cookieStore.remove(LOGS); }; } //inject -LogCtrl.$inject = ['$cookieStore']; +LogCtrl.$inject = ['$cookieStore', '$scope']; //export example.personalLog.LogCtrl = LogCtrl; diff --git a/example/personalLog/test/personalLogSpec.js b/example/personalLog/test/personalLogSpec.js index 9393e047..ab2d98c9 100644 --- a/example/personalLog/test/personalLogSpec.js +++ b/example/personalLog/test/personalLogSpec.js @@ -1,63 +1,58 @@ describe('example.personalLog.LogCtrl', function() { - var logCtrl; - - function createNotesCtrl() { - var injector = angular.injector(['ng', 'ngMock']); - var scope = injector.get('$rootScope'); - scope.$cookies = injector.get('$cookies'); - return scope.$new(example.personalLog.LogCtrl); - } - + var logScope; beforeEach(function() { - logCtrl = createNotesCtrl(); + var injector = angular.injector(['ng', 'ngMock']); + logScope = injector.get('$rootScope'); + logScope.$cookies = injector.get('$cookies'); + injector.instantiate(example.personalLog.LogCtrl, {$scope: logScope}); }); it('should initialize notes with an empty array', function() { - expect(logCtrl.logs).toEqual([]); + expect(logScope.logs).toEqual([]); }); describe('addLog', function() { beforeEach(function() { - expect(logCtrl.logs).toEqual([]); + expect(logScope.logs).toEqual([]); }); it('should add newMsg to logs as a log entry', function() { - logCtrl.newMsg = 'first log message'; - logCtrl.addLog(); + logScope.newMsg = 'first log message'; + logScope.addLog(); - expect(logCtrl.logs.length).toBe(1); - expect(logCtrl.logs[0].msg).toBe('first log message'); + expect(logScope.logs.length).toBe(1); + expect(logScope.logs[0].msg).toBe('first log message'); //one more msg, this time passed in as param - logCtrl.addLog('second log message'); + logScope.addLog('second log message'); - expect(logCtrl.logs.length).toBe(2); - expect(logCtrl.logs[0].msg).toBe('first log message'); - expect(logCtrl.logs[1].msg).toBe('second log message'); + expect(logScope.logs.length).toBe(2); + expect(logScope.logs[0].msg).toBe('first log message'); + expect(logScope.logs[1].msg).toBe('second log message'); }); it('should clear newMsg when log entry is persisted', function() { - logCtrl.addLog('first log message'); - expect(logCtrl.newMsg).toBe(''); + logScope.addLog('first log message'); + expect(logScope.newMsg).toBe(''); }); it('should store logs in the logs cookie', function() { - expect(logCtrl.$cookies.logs).not.toBeDefined(); - logCtrl.addLog('first log message'); - expect(logCtrl.$cookies.logs).toBeTruthy(); + expect(logScope.$cookies.logs).not.toBeDefined(); + logScope.addLog('first log message'); + expect(logScope.$cookies.logs).toBeTruthy(); }); it('should do nothing if newMsg is empty', function() { - logCtrl.addLog(''); - expect(logCtrl.logs.length).toBe(0); + logScope.addLog(''); + expect(logScope.logs.length).toBe(0); }); }); @@ -65,35 +60,35 @@ describe('example.personalLog.LogCtrl', function() { describe('rmLog', function() { beforeEach(function() { - logCtrl.addLog('message1'); - logCtrl.addLog('message2'); - logCtrl.addLog('message3'); - logCtrl.addLog('message4'); - expect(logCtrl.logs.length).toBe(4); + logScope.addLog('message1'); + logScope.addLog('message2'); + logScope.addLog('message3'); + logScope.addLog('message4'); + expect(logScope.logs.length).toBe(4); }); it('should delete a message identified by index', function() { - logCtrl.rmLog(logCtrl.logs[1]); - expect(logCtrl.logs.length).toBe(3); + logScope.rmLog(logScope.logs[1]); + expect(logScope.logs.length).toBe(3); - logCtrl.rmLog(logCtrl.logs[2]); - expect(logCtrl.logs.length).toBe(2); - expect(logCtrl.logs[0].msg).toBe('message1'); - expect(logCtrl.logs[1].msg).toBe('message3'); + logScope.rmLog(logScope.logs[2]); + expect(logScope.logs.length).toBe(2); + expect(logScope.logs[0].msg).toBe('message1'); + expect(logScope.logs[1].msg).toBe('message3'); }); it('should update cookies when a log is deleted', function() { - expect(logCtrl.$cookies.logs).toMatch(/\[\{.*?\}(,\{.*?\}){3}\]/); + expect(logScope.$cookies.logs).toMatch(/\[\{.*?\}(,\{.*?\}){3}\]/); - logCtrl.rmLog(logCtrl.logs[1]); - expect(logCtrl.$cookies.logs).toMatch(/\[\{.*?\}(,\{.*?\}){2}\]/); + logScope.rmLog(logScope.logs[1]); + expect(logScope.$cookies.logs).toMatch(/\[\{.*?\}(,\{.*?\}){2}\]/); - logCtrl.rmLog(logCtrl.logs[0]); - logCtrl.rmLog(logCtrl.logs[0]); - logCtrl.rmLog(logCtrl.logs[0]); - expect(logCtrl.$cookies.logs).toMatch(/\[\]/); + logScope.rmLog(logScope.logs[0]); + logScope.rmLog(logScope.logs[0]); + logScope.rmLog(logScope.logs[0]); + expect(logScope.$cookies.logs).toMatch(/\[\]/); }); }); @@ -101,24 +96,24 @@ describe('example.personalLog.LogCtrl', function() { describe('rmLogs', function() { beforeEach(function() { - logCtrl.addLog('message1'); - logCtrl.addLog('message2'); - logCtrl.addLog('message3'); - logCtrl.addLog('message4'); - expect(logCtrl.logs.length).toBe(4); + logScope.addLog('message1'); + logScope.addLog('message2'); + logScope.addLog('message3'); + logScope.addLog('message4'); + expect(logScope.logs.length).toBe(4); }); it('should remove all logs', function() { - logCtrl.rmLogs(); - expect(logCtrl.logs).toEqual([]); + logScope.rmLogs(); + expect(logScope.logs).toEqual([]); }); it('should remove logs cookie', function() { - expect(logCtrl.$cookies.logs).toBeTruthy(); - logCtrl.rmLogs(); - expect(logCtrl.$cookies.logs).not.toBeDefined(); + expect(logScope.$cookies.logs).toBeTruthy(); + logScope.rmLogs(); + expect(logScope.$cookies.logs).not.toBeDefined(); }); }); }); diff --git a/src/directives.js b/src/directives.js index 1d5b36f2..53d03573 100644 --- a/src/directives.js +++ b/src/directives.js @@ -97,28 +97,30 @@ angularDirective("ng:init", function(expression){ <doc:example> <doc:source> <script type="text/javascript"> - function SettingsController() { - this.name = "John Smith"; - this.contacts = [ + function SettingsController($scope) { + $scope.name = "John Smith"; + $scope.contacts = [ {type:'phone', value:'408 555 1212'}, {type:'email', value:'john.smith@example.org'} ]; - } - SettingsController.prototype = { - greet: function() { + + $scope.greet = function() { alert(this.name); - }, - addContact: function() { + }; + + $scope.addContact = function() { this.contacts.push({type:'email', value:'yourname@example.org'}); - }, - removeContact: function(contactToRemove) { + }; + + $scope.removeContact = function(contactToRemove) { var index = this.contacts.indexOf(contactToRemove); this.contacts.splice(index, 1); - }, - clearContact: function(contact) { + }; + + $scope.clearContact = function(contact) { contact.type = 'phone'; contact.value = ''; - } - }; + }; + } </script> <div ng:controller="SettingsController"> Name: <input type="text" ng:model="name"/> @@ -156,16 +158,15 @@ angularDirective("ng:init", function(expression){ </doc:scenario> </doc:example> */ -angularDirective("ng:controller", function(expression){ - this.scope(function(scope){ - var Controller = - getter(scope, expression, true) || - getter(window, expression, true); +angularDirective("ng:controller", function(expression) { + this.scope(true); + return ['$injector', '$window', function($injector, $window) { + var scope = this, + Controller = getter(scope, expression, true) || getter($window, expression, true); + assertArgFn(Controller, expression); - inferInjectionArgs(Controller); - return Controller; - }); - return noop; + $injector.instantiate(Controller, {$scope: scope}); + }]; }); /** @@ -189,8 +190,8 @@ angularDirective("ng:controller", function(expression){ <doc:example> <doc:source> <script> - function Ctrl() { - this.name = 'Whirled'; + function Ctrl($scope) { + $scope.name = 'Whirled'; } </script> <div ng:controller="Ctrl"> @@ -277,9 +278,9 @@ angularDirective("ng:bind", function(expression, element){ <doc:example> <doc:source> <script> - function Ctrl() { - this.salutation = 'Hello'; - this.name = 'World'; + function Ctrl($scope) { + $scope.salutation = 'Hello'; + $scope.name = 'World'; } </script> <div ng:controller="Ctrl"> @@ -363,8 +364,8 @@ angularDirective("ng:bind-template", function(expression, element){ <doc:example> <doc:source> <script> - function Ctrl() { - this.query = 'AngularJS'; + function Ctrl($scope) { + $scope.query = 'AngularJS'; } </script> <div ng:controller="Ctrl"> @@ -470,10 +471,10 @@ angularDirective("ng:click", function(expression, element){ <doc:example> <doc:source> <script> - function Ctrl() { - this.list = []; - this.text = 'hello'; - this.submit = function() { + function Ctrl($scope) { + $scope.list = []; + $scope.text = 'hello'; + $scope.submit = function() { if (this.text) { this.list.push(this.text); this.text = ''; diff --git a/src/scenario/Runner.js b/src/scenario/Runner.js index cfde1f64..06ad3aa1 100644 --- a/src/scenario/Runner.js +++ b/src/scenario/Runner.js @@ -152,7 +152,16 @@ angular.scenario.Runner.prototype.afterEach = function(body) { * @param {Object} scope parent scope */ angular.scenario.Runner.prototype.createSpecRunner_ = function(scope) { - return scope.$new(angular.scenario.SpecRunner); + var child = scope.$new(); + var Cls = angular.scenario.SpecRunner; + + // Export all the methods to child scope manually as now we don't mess controllers with scopes + // TODO(vojta): refactor scenario runner so that these objects are not tightly coupled as current + for (var name in Cls.prototype) + child[name] = angular.bind(child, Cls.prototype[name]); + + Cls.call(child); + return child; }; /** diff --git a/src/service/compiler.js b/src/service/compiler.js index 727f7983..adf1ffa9 100644 --- a/src/service/compiler.js +++ b/src/service/compiler.js @@ -22,7 +22,7 @@ function $CompileProvider(){ var childScope = scope, locals = {$element: element}; if (this.newScope) { - childScope = isFunction(this.newScope) ? scope.$new(this.newScope(scope)) : scope.$new(); + childScope = scope.$new(); element.data($$scope, childScope); } forEach(this.linkFns, function(fn) { diff --git a/src/service/filter/filters.js b/src/service/filter/filters.js index 3e7f8e37..69bfbacf 100644 --- a/src/service/filter/filters.js +++ b/src/service/filter/filters.js @@ -18,8 +18,8 @@ <doc:example> <doc:source> <script> - function Ctrl() { - this.amount = 1234.56; + function Ctrl($scope) { + $scope.amount = 1234.56; } </script> <div ng:controller="Ctrl"> @@ -69,8 +69,8 @@ function currencyFilter($locale) { <doc:example> <doc:source> <script> - function Ctrl() { - this.val = 1234.56789; + function Ctrl($scope) { + $scope.val = 1234.56789; } </script> <div ng:controller="Ctrl"> @@ -448,8 +448,8 @@ var uppercaseFilter = valueFn(uppercase); <doc:example> <doc:source> <script> - function Ctrl() { - this.snippet = + function Ctrl($scope) { + $scope.snippet = '<p style="color:blue">an html\n' + '<em onmouseover="this.textContent=\'PWN3D!\'">click here</em>\n' + 'snippet</p>'; @@ -538,8 +538,8 @@ function htmlFilter() { <doc:example> <doc:source> <script> - function Ctrl() { - this.snippet = + function Ctrl($scope) { + $scope.snippet = 'Pretty text with some links:\n'+ 'http://angularjs.org/,\n'+ 'mailto:us@somewhere.org,\n'+ diff --git a/src/service/filter/limitTo.js b/src/service/filter/limitTo.js index a250bd3b..eb97fdad 100644 --- a/src/service/filter/limitTo.js +++ b/src/service/filter/limitTo.js @@ -25,9 +25,9 @@ <doc:example> <doc:source> <script> - function Ctrl() { - this.numbers = [1,2,3,4,5,6,7,8,9]; - this.limit = 3; + function Ctrl($scope) { + $scope.numbers = [1,2,3,4,5,6,7,8,9]; + $scope.limit = 3; } </script> <div ng:controller="Ctrl"> diff --git a/src/service/filter/orderBy.js b/src/service/filter/orderBy.js index 2e5a0286..c67d2769 100644 --- a/src/service/filter/orderBy.js +++ b/src/service/filter/orderBy.js @@ -32,14 +32,14 @@ <doc:example> <doc:source> <script> - function Ctrl() { - this.friends = + function Ctrl($scope) { + $scope.friends = [{name:'John', phone:'555-1212', age:10}, {name:'Mary', phone:'555-9876', age:19}, {name:'Mike', phone:'555-4321', age:21}, {name:'Adam', phone:'555-5678', age:35}, {name:'Julie', phone:'555-8765', age:29}] - this.predicate = '-age'; + $scope.predicate = '-age'; } </script> <div ng:controller="Ctrl"> diff --git a/src/service/formFactory.js b/src/service/formFactory.js index 15a4733f..565b22a4 100644 --- a/src/service/formFactory.js +++ b/src/service/formFactory.js @@ -25,15 +25,13 @@ <doc:example> <doc:source> <script> - function EditorCntl() { - this.html = '<b>Hello</b> <i>World</i>!'; + function EditorCntl($scope) { + $scope.html = '<b>Hello</b> <i>World</i>!'; } - HTMLEditorWidget.$inject = ['$element', 'htmlFilter']; - function HTMLEditorWidget(element, htmlFilter) { - var self = this; - - this.$parseModel = function() { + HTMLEditorWidget.$inject = ['$element', '$scope', 'htmlFilter']; + function HTMLEditorWidget(element, scope, htmlFilter) { + scope.$parseModel = function() { // need to protect for script injection try { this.$viewValue = htmlFilter(this.$modelValue || '').get(); @@ -47,13 +45,13 @@ } } - this.$render = function() { + scope.$render = function() { element.html(this.$viewValue); } element.bind('keyup', function() { - self.$apply(function() { - self.$emit('$viewChange', element.html()); + scope.$apply(function() { + scope.$emit('$viewChange', element.html()); }); }); } @@ -104,7 +102,8 @@ function $FormFactoryProvider() { var $parse; - this.$get = ['$rootScope', '$parse', function($rootScope, $parse_) { + this.$get = ['$rootScope', '$parse', '$injector', + function($rootScope, $parse_, $injector) { $parse = $parse_; /** * @ngdoc proprety @@ -136,7 +135,9 @@ function $FormFactoryProvider() { return formFactory; function formFactory(parent) { - return (parent || formFactory.rootForm).$new(FormController); + var scope = (parent || formFactory.rootForm).$new(); + $injector.instantiate(FormController, {$scope: scope}); + return scope; } }]; @@ -230,8 +231,11 @@ function $FormFactoryProvider() { * @param {*} viewValue The new value for the view which will be assigned to `widget.$viewValue`. */ - function FormController() { - var form = this, + FormController.$inject = ['$scope', '$injector']; + function FormController($scope, $injector) { + this.$injector = $injector; + + var form = this.form = $scope, $error = form.$error = {}; form.$on('$destroy', function(event){ @@ -257,6 +261,7 @@ function $FormFactoryProvider() { }); propertiesUpdate(form); + form.$createWidget = bind(this, this.$createWidget); function removeWidget(queue, errorKey, widget) { if (queue) { @@ -354,17 +359,19 @@ function $FormFactoryProvider() { * @returns {Widget} Instance of a widget scope. */ FormController.prototype.$createWidget = function(params) { - var form = this, + var form = this.form, modelScope = params.scope, onChange = params.onChange, alias = params.alias, scopeGet = $parse(params.model), scopeSet = scopeGet.assign, - widget = this.$new(params.controller, params.controllerArgs); + widget = form.$new(); + + this.$injector.instantiate(params.controller, extend({$scope: widget}, params.controllerArgs)); if (!scopeSet) { throw Error("Expression '" + params.model + "' is not assignable!"); - }; + } widget.$error = {}; // Set the state to something we know will change to get the process going. diff --git a/src/service/http.js b/src/service/http.js index b008aa8e..9d57ed76 100644 --- a/src/service/http.js +++ b/src/service/http.js @@ -395,29 +395,28 @@ function $HttpProvider() { <doc:example> <doc:source jsfiddle="false"> <script> - function FetchCtrl($http) { - var self = this; - this.method = 'GET'; - this.url = 'examples/http-hello.html'; + function FetchCtrl($scope, $http) { + $scope.method = 'GET'; + $scope.url = 'examples/http-hello.html'; - this.fetch = function() { - self.code = null; - self.response = null; + $scope.fetch = function() { + $scope.code = null; + $scope.response = null; - $http({method: self.method, url: self.url}). + $http({method: $scope.method, url: $scope.url}). success(function(data, status) { - self.status = status; - self.data = data; + $scope.status = status; + $scope.data = data; }). error(function(data, status) { - self.data = data || "Request failed"; - self.status = status; + $scope.data = data || "Request failed"; + $scope.status = status; }); }; - this.updateModel = function(method, url) { - self.method = method; - self.url = url; + $scope.updateModel = function(method, url) { + $scope.method = method; + $scope.url = url; }; } </script> diff --git a/src/service/route.js b/src/service/route.js index 77d94e9c..04bcfdb6 100644 --- a/src/service/route.js +++ b/src/service/route.js @@ -63,8 +63,8 @@ </doc:example> */ function $RouteProvider(){ - this.$get = ['$rootScope', '$location', '$routeParams', - function( $rootScope, $location, $routeParams) { + this.$get = ['$rootScope', '$location', '$routeParams', '$injector', + function( $rootScope, $location, $routeParams, $injector) { /** * @ngdoc event * @name angular.module.ng.$route#$beforeRouteChange @@ -278,8 +278,10 @@ function $RouteProvider(){ } } else { copy(next.params, $routeParams); - (Controller = next.controller) && inferInjectionArgs(Controller); - next.scope = parentScope.$new(Controller); + next.scope = parentScope.$new(); + if (next.controller) { + $injector.instantiate(next.controller, {$scope: next.scope}); + } } } $rootScope.$broadcast('$afterRouteChange', next, last); diff --git a/src/service/scope.js b/src/service/scope.js index fe72c953..089e4a41 100644 --- a/src/service/scope.js +++ b/src/service/scope.js @@ -126,8 +126,9 @@ function $RootScopeProvider(){ * @function * * @description - * Creates a new child {@link angular.module.ng.$rootScope.Scope scope}. The new scope can optionally behave as a - * controller. The parent scope will propagate the {@link angular.module.ng.$rootScope.Scope#$digest $digest()} and + * Creates a new child {@link angular.module.ng.$rootScope.Scope scope}. + * + * The parent scope will propagate the {@link angular.module.ng.$rootScope.Scope#$digest $digest()} and * {@link angular.module.ng.$rootScope.Scope#$digest $digest()} events. The scope can be removed from the scope * hierarchy using {@link angular.module.ng.$rootScope.Scope#$destroy $destroy()}. * @@ -135,13 +136,10 @@ function $RootScopeProvider(){ * the scope and its child scopes to be permanently detached from the parent and thus stop * participating in model change detection and listener notification by invoking. * - * @param {function()=} Class Constructor function which the scope should be applied to the scope. - * @param {...*} curryArguments Any additional arguments which are curried into the constructor. - * See {@link guide/dev_guide.di dependency injection}. * @returns {Object} The newly created child scope. * */ - $new: function(Class, curryArguments) { + $new: function() { var Child = function() {}; // should be anonymous; This is so that when the minifier munges // the name it does not become random set of chars. These will then show up as class // name in the debugger. @@ -161,15 +159,6 @@ function $RootScopeProvider(){ } else { this.$$childHead = this.$$childTail = child; } - // short circuit if we have no class - if (Class) { - // can't use forEach, we need speed! - var ClassPrototype = Class.prototype; - for(var key in ClassPrototype) { - child[key] = bind(child, ClassPrototype[key]); - } - $injector.invoke(Class, child, curryArguments); - } return child; }, diff --git a/src/widget/form.js b/src/widget/form.js index 49e3a545..f3134db4 100644 --- a/src/widget/form.js +++ b/src/widget/form.js @@ -52,8 +52,8 @@ <doc:example> <doc:source> <script> - function Ctrl() { - this.text = 'guest'; + function Ctrl($scope) { + $scope.text = 'guest'; } </script> <div ng:controller="Ctrl"> diff --git a/src/widget/input.js b/src/widget/input.js index a744e567..5db52704 100644 --- a/src/widget/input.js +++ b/src/widget/input.js @@ -31,9 +31,9 @@ var INTEGER_REGEXP = /^\s*(\-|\+)?\d+\s*$/; <doc:example> <doc:source> <script> - function Ctrl() { - this.text = 'guest'; - this.word = /^\w*$/; + function Ctrl($scope) { + $scope.text = 'guest'; + $scope.word = /^\w*$/; } </script> <div ng:controller="Ctrl"> @@ -96,8 +96,8 @@ var INTEGER_REGEXP = /^\s*(\-|\+)?\d+\s*$/; <doc:example> <doc:source> <script> - function Ctrl() { - this.text = 'me@example.com'; + function Ctrl($scope) { + $scope.text = 'me@example.com'; } </script> <div ng:controller="Ctrl"> @@ -136,9 +136,8 @@ var INTEGER_REGEXP = /^\s*(\-|\+)?\d+\s*$/; </doc:scenario> </doc:example> */ -angularInputType('email', function() { - var widget = this; - this.$on('$validate', function(event){ +angularInputType('email', function(element, widget) { + widget.$on('$validate', function(event) { var value = widget.$viewValue; widget.$emit(!value || value.match(EMAIL_REGEXP) ? "$valid" : "$invalid", "EMAIL"); }); @@ -170,8 +169,8 @@ angularInputType('email', function() { <doc:example> <doc:source> <script> - function Ctrl() { - this.text = 'http://google.com'; + function Ctrl($scope) { + $scope.text = 'http://google.com'; } </script> <div ng:controller="Ctrl"> @@ -210,9 +209,8 @@ angularInputType('email', function() { </doc:scenario> </doc:example> */ -angularInputType('url', function() { - var widget = this; - this.$on('$validate', function(event){ +angularInputType('url', function(element, widget) { + widget.$on('$validate', function(event) { var value = widget.$viewValue; widget.$emit(!value || value.match(URL_REGEXP) ? "$valid" : "$invalid", "URL"); }); @@ -239,8 +237,8 @@ angularInputType('url', function() { <doc:example> <doc:source> <script> - function Ctrl() { - this.names = ['igor', 'misko', 'vojta']; + function Ctrl($scope) { + $scope.names = ['igor', 'misko', 'vojta']; } </script> <div ng:controller="Ctrl"> @@ -270,7 +268,7 @@ angularInputType('url', function() { </doc:scenario> </doc:example> */ -angularInputType('list', function() { +angularInputType('list', function(element, widget) { function parse(viewValue) { var list = []; forEach(viewValue.split(/\s*,\s*/), function(value){ @@ -278,14 +276,14 @@ angularInputType('list', function() { }); return list; } - this.$parseView = function() { - isString(this.$viewValue) && (this.$modelValue = parse(this.$viewValue)); + widget.$parseView = function() { + isString(widget.$viewValue) && (widget.$modelValue = parse(widget.$viewValue)); }; - this.$parseModel = function() { - var modelValue = this.$modelValue; + widget.$parseModel = function() { + var modelValue = widget.$modelValue; if (isArray(modelValue) - && (!isString(this.$viewValue) || !equals(parse(this.$viewValue), modelValue))) { - this.$viewValue = modelValue.join(', '); + && (!isString(widget.$viewValue) || !equals(parse(widget.$viewValue), modelValue))) { + widget.$viewValue = modelValue.join(', '); } }; }); @@ -318,8 +316,8 @@ angularInputType('list', function() { <doc:example> <doc:source> <script> - function Ctrl() { - this.value = 12; + function Ctrl($scope) { + $scope.value = 12; } </script> <div ng:controller="Ctrl"> @@ -388,8 +386,8 @@ angularInputType('number', numericRegexpInputType(NUMBER_REGEXP, 'NUMBER')); <doc:example> <doc:source> <script> - function Ctrl() { - this.value = 12; + function Ctrl($scope) { + $scope.value = 12; } </script> <div ng:controller="Ctrl"> @@ -449,9 +447,9 @@ angularInputType('integer', numericRegexpInputType(INTEGER_REGEXP, 'INTEGER')); <doc:example> <doc:source> <script> - function Ctrl() { - this.value1 = true; - this.value2 = 'YES' + function Ctrl($scope) { + $scope.value1 = true; + $scope.value2 = 'YES' } </script> <div ng:controller="Ctrl"> @@ -477,9 +475,8 @@ angularInputType('integer', numericRegexpInputType(INTEGER_REGEXP, 'INTEGER')); </doc:scenario> </doc:example> */ -angularInputType('checkbox', function(inputElement) { - var widget = this, - trueValue = inputElement.attr('ng:true-value'), +angularInputType('checkbox', function(inputElement, widget) { + var trueValue = inputElement.attr('ng:true-value'), falseValue = inputElement.attr('ng:false-value'); if (!isString(trueValue)) trueValue = true; @@ -496,7 +493,7 @@ angularInputType('checkbox', function(inputElement) { }; widget.$parseModel = function() { - widget.$viewValue = this.$modelValue === trueValue; + widget.$viewValue = widget.$modelValue === trueValue; }; widget.$parseView = function() { @@ -522,8 +519,8 @@ angularInputType('checkbox', function(inputElement) { <doc:example> <doc:source> <script> - function Ctrl() { - this.color = 'blue'; + function Ctrl($scope) { + $scope.color = 'blue'; } </script> <div ng:controller="Ctrl"> @@ -545,9 +542,7 @@ angularInputType('checkbox', function(inputElement) { </doc:scenario> </doc:example> */ -angularInputType('radio', function(inputElement) { - var widget = this; - +angularInputType('radio', function(inputElement, widget) { //correct the name inputElement.attr('name', widget.$id + '@' + inputElement.attr('name')); inputElement.bind('click', function() { @@ -569,9 +564,8 @@ angularInputType('radio', function(inputElement) { function numericRegexpInputType(regexp, error) { - return ['$element', function(inputElement) { - var widget = this, - min = 1 * (inputElement.attr('min') || Number.MIN_VALUE), + return function(inputElement, widget) { + var min = 1 * (inputElement.attr('min') || Number.MIN_VALUE), max = 1 * (inputElement.attr('max') || Number.MAX_VALUE); widget.$on('$validate', function(event){ @@ -598,7 +592,7 @@ function numericRegexpInputType(regexp, error) { ? '' + widget.$modelValue : ''; }; - }]; + }; } @@ -640,8 +634,8 @@ var HTML5_INPUTS_TYPES = makeMap( <doc:example> <doc:source> <script> - function Ctrl() { - this.user = {name: 'guest', last: 'visitor'}; + function Ctrl($scope) { + $scope.user = {name: 'guest', last: 'visitor'}; } </script> <div ng:controller="Ctrl"> @@ -713,7 +707,8 @@ angularWidget('input', function(inputElement){ this.descend(true); var modelExp = inputElement.attr('ng:model'); return modelExp && - ['$defer', '$formFactory', '$element', function($defer, $formFactory, inputElement){ + ['$defer', '$formFactory', '$element', + function($defer, $formFactory, inputElement) { var form = $formFactory.forElement(inputElement), // We have to use .getAttribute, since jQuery tries to be smart and use the // type property. Trouble is some browser change unknown to text. @@ -762,7 +757,7 @@ angularWidget('input', function(inputElement){ } //TODO(misko): setting $inject is a hack - !TypeController.$inject && (TypeController.$inject = ['$element']); + !TypeController.$inject && (TypeController.$inject = ['$element', '$scope']); widget = form.$createWidget({ scope: modelScope, model: modelExp, @@ -866,7 +861,7 @@ angularWidget('textarea', angularWidget('input')); function watchElementProperty(modelScope, widget, name, element) { var bindAttr = fromJson(element.attr('ng:bind-attr') || '{}'), - match = /\s*{{(.*)}}\s*/.exec(bindAttr[name]), + match = /\s*\{\{(.*)\}\}\s*/.exec(bindAttr[name]), isBoolean = BOOLEAN_ATTR[name]; widget['$' + name] = isBoolean ? ( // some browsers return true some '' when required is set without value. diff --git a/src/widget/select.js b/src/widget/select.js index d4be91d9..b0f5eac5 100644 --- a/src/widget/select.js +++ b/src/widget/select.js @@ -65,15 +65,15 @@ <doc:example> <doc:source> <script> - function MyCntrl() { - this.colors = [ + function MyCntrl($scope) { + $scope.colors = [ {name:'black', shade:'dark'}, {name:'white', shade:'light'}, {name:'red', shade:'dark'}, {name:'blue', shade:'dark'}, {name:'yellow', shade:'light'} ]; - this.color = this.colors[2]; // red + $scope.color = $scope.colors[2]; // red } </script> <div ng:controller="MyCntrl"> @@ -140,11 +140,11 @@ angularWidget('select', function(element){ optionsExp = selectElement.attr('ng:options'), modelExp = selectElement.attr('ng:model'), widget = form.$createWidget({ - scope: this, + scope: modelScope, model: modelExp, onChange: selectElement.attr('ng:change'), alias: selectElement.attr('name'), - controller: optionsExp ? Options : (multiple ? Multiple : Single)}); + controller: ['$scope', optionsExp ? Options : (multiple ? Multiple : Single)]}); selectElement.bind('$destroy', function() { widget.$destroy(); }); @@ -174,11 +174,9 @@ angularWidget('select', function(element){ //////////////////////////// - function Multiple() { - var widget = this; - - this.$render = function() { - var items = new HashMap(this.$viewValue); + function Multiple(widget) { + widget.$render = function() { + var items = new HashMap(widget.$viewValue); forEach(selectElement.children(), function(option){ option.selected = isDefined(items.get(option.value)); }); @@ -198,9 +196,7 @@ angularWidget('select', function(element){ } - function Single() { - var widget = this; - + function Single(widget) { widget.$render = function() { selectElement.val(widget.$viewValue); }; @@ -214,9 +210,8 @@ angularWidget('select', function(element){ widget.$viewValue = selectElement.val(); } - function Options() { - var widget = this, - match; + function Options(widget) { + var match; if (! (match = optionsExp.match(NG_OPTIONS_REGEXP))) { throw Error( @@ -224,8 +219,7 @@ angularWidget('select', function(element){ " but got '" + optionsExp + "'."); } - var widgetScope = this, - displayFn = $parse(match[2] || match[1]), + var displayFn = $parse(match[2] || match[1]), valueName = match[4] || match[6], keyName = match[5], groupByFn = $parse(match[3] || ''), @@ -253,7 +247,7 @@ angularWidget('select', function(element){ selectElement.html(''); // clear contents selectElement.bind('change', function() { - widgetScope.$apply(function() { + widget.$apply(function() { var optionGroup, collection = valuesFn(modelScope) || [], key = selectElement.val(), @@ -288,13 +282,13 @@ angularWidget('select', function(element){ } } if (isDefined(value) && modelScope.$viewVal !== value) { - widgetScope.$emit('$viewChange', value); + widget.$emit('$viewChange', value); } }); }); - widgetScope.$watch(render); - widgetScope.$render = render; + widget.$watch(render); + widget.$render = render; function render() { var optionGroups = {'':[]}, // Temporary location for the option groups before we render them diff --git a/src/widgets.js b/src/widgets.js index 09a800de..6b3e93ee 100644 --- a/src/widgets.js +++ b/src/widgets.js @@ -54,11 +54,11 @@ <doc:example> <doc:source jsfiddle="false"> <script> - function Ctrl() { - this.templates = + function Ctrl($scope) { + $scope.templates = [ { name: 'template1.html', url: 'examples/ng-include/template1.html'} , { name: 'template2.html', url: 'examples/ng-include/template2.html'} ]; - this.template = this.templates[0]; + $scope.template = $scope.templates[0]; } </script> <div ng:controller="Ctrl"> @@ -171,9 +171,9 @@ angularWidget('ng:include', function(element){ <doc:example> <doc:source> <script> - function Ctrl() { - this.items = ['settings', 'home', 'other']; - this.selection = this.items[0]; + function Ctrl($scope) { + $scope.items = ['settings', 'home', 'other']; + $scope.selection = $scope.items[0]; } </script> <div ng:controller="Ctrl"> @@ -701,10 +701,10 @@ angularWidget('ng:view', function(element) { <doc:example> <doc:source> <script> - function Ctrl() { - this.person1 = 'Igor'; - this.person2 = 'Misko'; - this.personCount = 1; + function Ctrl($scope) { + $scope.person1 = 'Igor'; + $scope.person2 = 'Misko'; + $scope.personCount = 1; } </script> <div ng:controller="Ctrl"> diff --git a/test/directivesSpec.js b/test/directivesSpec.js index 1825dc49..7600a9c8 100644 --- a/test/directivesSpec.js +++ b/test/directivesSpec.js @@ -460,60 +460,66 @@ describe("directive", function() { }); describe('ng:controller', function() { + var element; - var temp; + beforeEach(inject(function($window) { + $window.Greeter = function($scope) { + // private stuff (not exported to scope) + this.prefix = 'Hello '; - beforeEach(function() { - temp = window.temp = {}; - temp.Greeter = function() { - this.$root.greeter = this; - this.greeting = 'hello'; - this.suffix = '!'; + // public stuff (exported to scope) + var ctrl = this; + $scope.name = 'Misko'; + $scope.greet = function(name) { + return ctrl.prefix + name + ctrl.suffix; + }; + + $scope.protoGreet = bind(this, this.protoGreet); }; - temp.Greeter.prototype = { - greet: function(name) { - return this.greeting + ' ' + name + this.suffix; + $window.Greeter.prototype = { + suffix: '!', + protoGreet: function(name) { + return this.prefix + name + this.suffix; } }; - }); + + $window.Child = function($scope) { + $scope.name = 'Adam'; + }; + })); afterEach(function() { - window.temp = undefined; + dealoc(element); }); - it('should bind', inject(function($rootScope, $compile) { - var element = $compile('<div ng:controller="temp.Greeter"></div>')($rootScope); - expect($rootScope.greeter.greeting).toEqual('hello'); - expect($rootScope.greeter.greet('misko')).toEqual('hello misko!'); + + it('should instantiate controller and bind methods', inject(function($compile, $rootScope) { + element = $compile('<div ng:controller="Greeter">{{greet(name)}}</div>')($rootScope); + $rootScope.$digest(); + expect(element.text()).toBe('Hello Misko!'); })); - it('should support nested controllers', inject(function($rootScope, $compile) { - temp.ChildGreeter = function() { - this.greeting = 'hey'; - this.$root.childGreeter = this; - }; - temp.ChildGreeter.prototype = { - greet: function() { - return this.greeting + ' dude' + this.suffix; - } - }; - var element = $compile('<div ng:controller="temp.Greeter"><div ng:controller="temp.ChildGreeter">{{greet("misko")}}</div></div>')($rootScope); - expect($rootScope.greeting).not.toBeDefined(); - expect($rootScope.greeter.greeting).toEqual('hello'); - expect($rootScope.greeter.greet('misko')).toEqual('hello misko!'); - expect($rootScope.greeter.greeting).toEqual('hello'); - expect($rootScope.childGreeter.greeting).toEqual('hey'); - expect($rootScope.childGreeter.$parent.greeting).toEqual('hello'); + + it('should allow nested controllers', inject(function($compile, $rootScope) { + element = $compile('<div ng:controller="Greeter"><div ng:controller="Child">{{greet(name)}}</div></div>')($rootScope); + $rootScope.$digest(); + expect(element.text()).toBe('Hello Adam!'); + dealoc(element); + + element = $compile('<div ng:controller="Greeter"><div ng:controller="Child">{{protoGreet(name)}}</div></div>')($rootScope); $rootScope.$digest(); - expect(element.text()).toEqual('hey dude!'); + expect(element.text()).toBe('Hello Adam!'); })); - it('should infer injection arguments', inject(function($rootScope, $compile, $http) { - temp.MyController = function($http) { - this.$root.someService = $http; + + it('should instantiate controller defined on scope', inject(function($compile, $rootScope) { + $rootScope.Greeter = function($scope) { + $scope.name = 'Vojta'; }; - var element = $compile('<div ng:controller="temp.MyController"></div>')($rootScope); - expect($rootScope.someService).toBe($http); + + element = $compile('<div ng:controller="Greeter">{{name}}</div>')($rootScope); + $rootScope.$digest(); + expect(element.text()).toBe('Vojta'); })); }); diff --git a/test/scenario/RunnerSpec.js b/test/scenario/RunnerSpec.js index 15bcc4b0..c4ad6f95 100644 --- a/test/scenario/RunnerSpec.js +++ b/test/scenario/RunnerSpec.js @@ -43,9 +43,6 @@ describe('angular.scenario.Runner', function() { location: {} }; runner = new angular.scenario.Runner($window); - runner.createSpecRunner_ = function(scope) { - return scope.$new(MockSpecRunner); - }; runner.on('SpecError', angular.mock.rethrow); runner.on('StepError', angular.mock.rethrow); }); diff --git a/test/scenario/SpecRunnerSpec.js b/test/scenario/SpecRunnerSpec.js index 4cffc63a..c104a9b7 100644 --- a/test/scenario/SpecRunnerSpec.js +++ b/test/scenario/SpecRunnerSpec.js @@ -40,7 +40,13 @@ describe('angular.scenario.SpecRunner', function() { }; $root.application = new ApplicationMock($window); $root.$window = $window; - runner = $root.$new(angular.scenario.SpecRunner); + runner = $root.$new(); + + var Cls = angular.scenario.SpecRunner; + for (var name in Cls.prototype) + runner[name] = angular.bind(runner, Cls.prototype[name]); + + Cls.call(runner); })); it('should bind futures to the spec', function() { diff --git a/test/service/formFactorySpec.js b/test/service/formFactorySpec.js index fbe601c6..1a23aa49 100644 --- a/test/service/formFactorySpec.js +++ b/test/service/formFactorySpec.js @@ -13,23 +13,24 @@ describe('$formFactory', function() { var scope; var log; - function WidgetCtrl($formFactory){ - this.$formFactory = $formFactory; + function WidgetCtrl($formFactory, $scope) { log += '<init>'; - this.$render = function() { + $scope.$render = function() { log += '$render();'; }; - this.$on('$validate', function(e){ + $scope.$on('$validate', function(e){ log += '$validate();'; }); + + this.$formFactory = $formFactory; } - WidgetCtrl.$inject = ['$formFactory']; + WidgetCtrl.$inject = ['$formFactory', '$scope']; WidgetCtrl.prototype = { - getFormFactory: function() { - return this.$formFactory; - } + getFormFactory: function() { + return this.$formFactory; + } }; beforeEach(inject(function($rootScope, $formFactory) { @@ -70,11 +71,6 @@ describe('$formFactory', function() { expect(widget.$modelValue).toEqual('xyz'); })); - - - it('should have controller prototype methods', inject(function($rootScope, $formFactory) { - expect(widget.getFormFactory()).toEqual($formFactory); - })); }); diff --git a/test/service/routeSpec.js b/test/service/routeSpec.js index 95560d29..1bb1312f 100644 --- a/test/service/routeSpec.js +++ b/test/service/routeSpec.js @@ -112,7 +112,7 @@ describe('$route', function() { inject(function($route, $location, $rootScope) { var onChangeSpy = jasmine.createSpy('onChange'); - function NotFoundCtrl() {this.notFoundProp = 'not found!';} + function NotFoundCtrl($scope) {$scope.notFoundProp = 'not found!';} $route.when('/foo', {template: 'foo.html'}); $route.otherwise({template: '404.html', controller: NotFoundCtrl}); @@ -169,10 +169,11 @@ describe('$route', function() { it('should infer arguments in injection', inject(function($route, $location, $rootScope) { - $route.when('/test', {controller: function($route){ this.$route = $route; }}); + var injectedRoute; + $route.when('/test', {controller: function($route) {injectedRoute = $route;}}); $location.path('/test'); $rootScope.$digest(); - expect($route.current.scope.$route).toBe($route); + expect(injectedRoute).toBe($route); })); @@ -304,9 +305,9 @@ describe('$route', function() { $route.when('/foo', {controller: FooCtrl, reloadOnSearch: false}); $rootScope.$on('$beforeRouteChange', reloaded); - function FooCtrl() { + function FooCtrl($scope) { reloaded(); - this.$on('$routeUpdate', routeUpdateEvent); + $scope.$on('$routeUpdate', routeUpdateEvent); } expect(reloaded).not.toHaveBeenCalled(); @@ -368,8 +369,8 @@ describe('$route', function() { $route.when('/foo', {controller: FooCtrl}); $route.when('/bar/:barId', {controller: FooCtrl, reloadOnSearch: false}); - function FooCtrl() { - this.$watch(function() { + function FooCtrl($scope) { + $scope.$watch(function() { return $route.current.params; }, function(scope, value) { routeParams(value); @@ -414,10 +415,10 @@ describe('$route', function() { } function createController(name) { - return function() { + return function($scope) { log.push('init-' + name); - this.$on('$destroy', logger('destroy-' + name)); - this.$on('$routeUpdate', logger('route-update')); + $scope.$on('$destroy', logger('destroy-' + name)); + $scope.$on('$routeUpdate', logger('route-update')); }; } diff --git a/test/service/scopeSpec.js b/test/service/scopeSpec.js index 96271bc9..68ef2834 100644 --- a/test/service/scopeSpec.js +++ b/test/service/scopeSpec.js @@ -53,35 +53,6 @@ describe('Scope', function() { $rootScope.a = 123; expect(child.a).toEqual(123); })); - - - it('should instantiate controller and bind functions', inject(function($rootScope) { - function Cntl($browser, name) { - this.$browser = $browser; - this.callCount = 0; - this.name = name; - } - Cntl.$inject = ['$browser', 'name']; - - Cntl.prototype = { - myFn: function() { - expect(this).toEqual(cntl); - this.callCount++; - } - }; - - var cntl = $rootScope.$new(Cntl, {name:'misko'}); - - expect($rootScope.$browser).toBeUndefined(); - expect($rootScope.myFn).toBeUndefined(); - - expect(cntl.$browser).toBeDefined(); - expect(cntl.name).toEqual('misko'); - - cntl.myFn(); - cntl.$new().myFn(); - expect(cntl.callCount).toEqual(2); - })); }); @@ -341,7 +312,7 @@ describe('Scope', function() { $rootScope.$digest(); expect(isNaN(log.shift())).toBe(true); //jasmine's toBe and toEqual don't work well with NaNs expect(log).toEqual([undefined, '', false, {}, 23]); - log = [] + log = []; $rootScope.$digest(); expect(log).toEqual([]); })); diff --git a/test/widgetsSpec.js b/test/widgetsSpec.js index f119174f..88d9e1b8 100644 --- a/test/widgetsSpec.js +++ b/test/widgetsSpec.js @@ -713,12 +713,12 @@ describe('widget', function() { $route.when('/foo', {controller: ParentCtrl, template: 'viewPartial.html'}); $rootScope.log = []; - function ParentCtrl() { - this.log.push('parent'); + function ParentCtrl($scope) { + $scope.log.push('parent'); } - $rootScope.ChildCtrl = function() { - this.log.push('child'); + $rootScope.ChildCtrl = function($scope) { + $scope.log.push('child'); }; $location.path('/foo'); |
