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'); | 
