diff options
| -rw-r--r-- | CHANGELOG.md | 8 | ||||
| -rw-r--r-- | src/Angular.js | 6 | ||||
| -rw-r--r-- | src/Compiler.js | 20 | ||||
| -rw-r--r-- | src/widgets.js | 19 | ||||
| -rw-r--r-- | test/BinderSpec.js | 31 | ||||
| -rw-r--r-- | test/CompilerSpec.js | 5 | ||||
| -rw-r--r-- | test/ScenarioSpec.js | 9 | ||||
| -rw-r--r-- | test/ValidatorsSpec.js | 5 | ||||
| -rw-r--r-- | test/directivesSpec.js | 3 | ||||
| -rw-r--r-- | test/markupSpec.js | 1 | ||||
| -rw-r--r-- | test/testabilityPatch.js | 1 | ||||
| -rw-r--r-- | test/widgetsSpec.js | 95 |
12 files changed, 95 insertions, 108 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index de7b3f4f..979d2435 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ <a name="0.9.12"><a/> # <angular/> 0.9.12 thought-implanter (in-progress) # +### Breaking changes +- Removed the $init() method after the compilation. The old way of compiling the DOM element was + angular.compile(element).$init(); The $init was there to allow the users to do any work to the + scope before the view would be bound. This is a left over from not having proper MVC. The new + recommended way to deal with initializing scope is to put it in the root constructor controller. + To migrate simply remove the call to $init() and move any code you had before $init() to the + root controller. + <a name="0.9.11"><a/> # <angular/> 0.9.11 snow-maker (2011-02-08) # diff --git a/src/Angular.js b/src/Angular.js index f9047d32..5bd5e547 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -800,10 +800,8 @@ function merge(src, dst) { * Compiles a piece of HTML or DOM into a {@link angular.scope scope} object. <pre> var scope1 = angular.compile(window.document); - scope1.$init(); var scope2 = angular.compile('<div ng:click="clicked = true">click me</div>'); - scope2.$init(); </pre> * * @param {string|DOMElement} element Element to compile. @@ -948,7 +946,7 @@ function toKeyValue(obj) { (function(window, previousOnLoad){ window.onload = function(){ try { (previousOnLoad||angular.noop)(); } catch(e) {} - angular.compile(window.document).$init(); + angular.compile(window.document); }; })(window, window.onload); </script> @@ -1002,8 +1000,6 @@ function angularInit(config){ $browser.addCss(config.base_url + config.css); else if(msie<8) $browser.addJs(config.base_url + config.ie_compat, config.ie_compat_id); - - scope.$init(); } } diff --git a/src/Compiler.js b/src/Compiler.js index 804a9622..6aee40b8 100644 --- a/src/Compiler.js +++ b/src/Compiler.js @@ -13,7 +13,7 @@ function Template(priority) { } Template.prototype = { - init: function(element, scope) { + attach: function(element, scope) { var inits = {}; this.collectInits(element, inits, scope); forEachSorted(inits, function(queue){ @@ -96,18 +96,14 @@ Compiler.prototype = { template = this.templatize(element, index, 0) || new Template(); return function(element, parentScope){ element = jqLite(element); - var scope = parentScope && parentScope.$eval ? - parentScope : createScope(parentScope); + var scope = parentScope && parentScope.$eval + ? parentScope + : createScope(parentScope); element.data($$scope, scope); - return extend(scope, { - $element:element, - $init: function() { - template.init(element, scope); - scope.$eval(); - delete scope.$init; - return scope; - } - }); + template.attach(element, scope); + scope.$element = element; + scope.$eval(); + return scope; }; }, diff --git a/src/widgets.js b/src/widgets.js index 7438254d..66c9ecc5 100644 --- a/src/widgets.js +++ b/src/widgets.js @@ -677,7 +677,6 @@ angularWidget('ng:include', function(element){ element.html(response); childScope = useScope || createScope(scope); compiler.compile(element)(element, childScope); - childScope.$init(); scope.$eval(onloadExp); }); } else { @@ -795,7 +794,6 @@ var ngSwitch = angularWidget('ng:switch', function (element){ element.append(caseElement); childScope.$tryEval(switchCase.change, element); switchCase.template(caseElement, childScope); - childScope.$init(); } }); }); @@ -891,7 +889,7 @@ angularWidget('a', function() { angularWidget("@ng:repeat", function(expression, element){ element.removeAttr('ng:repeat'); element.replaceWith(jqLite("<!-- ng:repeat: " + expression + " --!>")); - var template = this.compile(element); + var linker = this.compile(element); return function(reference){ var match = expression.match(/^\s*(.+)\s+in\s+(.*)\s*$/), lhs, rhs, valueIdent, keyIdent; @@ -912,6 +910,7 @@ angularWidget("@ng:repeat", function(expression, element){ var children = [], currentScope = this; this.$onEval(function(){ var index = 0, + cloneElement, childCount = children.length, lastElement = reference, collection = this.$tryEval(rhs, reference), @@ -937,16 +936,17 @@ angularWidget("@ng:repeat", function(expression, element){ if (keyIdent) childScope[keyIdent] = key; } else { // grow children - childScope = template(quickClone(element), createScope(currentScope)); + childScope = createScope(currentScope); childScope[valueIdent] = collection[key]; if (keyIdent) childScope[keyIdent] = key; - lastElement.after(childScope.$element); childScope.$index = index; childScope.$position = index == 0 ? - 'first' : - (index == collectionLength - 1 ? 'last' : 'middle'); - childScope.$element.attr('ng:repeat-index', index); - childScope.$init(); + 'first' : + (index == collectionLength - 1 ? 'last' : 'middle'); + cloneElement = quickClone(element); + lastElement.after(cloneElement); + cloneElement.attr('ng:repeat-index', index); + linker(cloneElement, childScope); children.push(childScope); } childScope.$eval(); @@ -1069,7 +1069,6 @@ angularWidget('ng:view', function(element) { $xhr('GET', src, function(code, response){ element.html(response); compiler.compile(element)(element, childScope); - childScope.$init(); }); } else { element.html(''); diff --git a/test/BinderSpec.js b/test/BinderSpec.js index 73650bd6..c3f90ad7 100644 --- a/test/BinderSpec.js +++ b/test/BinderSpec.js @@ -3,16 +3,18 @@ describe('Binder', function(){ beforeEach(function(){ var self = this; - this.compile = function(html, initialScope, parent) { + this.compile = function(html, parent) { var compiler = new Compiler(angularTextMarkup, angularAttrMarkup, angularDirective, angularWidget); if (self.element) dealoc(self.element); - var element = self.element = jqLite(html); + var element; + if (parent) { + parent.html(html); + element = parent.children(); + } else { + element = jqLite(html); + } + self.element = element; var scope = compiler.compile(element)(element); - - if (parent) parent.append(element); - - extend(scope, initialScope); - scope.$init(); return {node:element, scope:scope}; }; this.compileToHtml = function (content) { @@ -27,8 +29,8 @@ describe('Binder', function(){ }); - it('ChangingTextfieldUpdatesModel', function(){ - var state = this.compile('<input type="text" name="model.price" value="abc">', {model:{}}); + it('text-field should default to value attribute', function(){ + var state = this.compile('<input type="text" name="model.price" value="abc">'); state.scope.$eval(); assertEquals('abc', state.scope.model.price); }); @@ -443,8 +445,7 @@ describe('Binder', function(){ }); it('ActionOnAHrefThrowsError', function(){ - var model = {books:[]}; - var c = this.compile('<a ng:click="action()">Add Phone</a>', model); + var c = this.compile('<a ng:click="action()">Add Phone</a>'); c.scope.action = function(){ throw new Error('MyError'); }; @@ -517,9 +518,9 @@ describe('Binder', function(){ }); it('ValidateForm', function(){ - var c = this.compile('<div><input name="name" ng:required>' + - '<div ng:repeat="item in items"><input name="item.name" ng:required/></div></div>', - undefined, jqLite(document.body)); + var c = this.compile('<div id="test"><input name="name" ng:required>' + + '<input ng:repeat="item in items" name="item.name" ng:required/></div>', + jqLite(document.body)); var items = [{}, {}]; c.scope.$set("items", items); c.scope.$eval(); @@ -547,7 +548,7 @@ describe('Binder', function(){ }); it('ValidateOnlyVisibleItems', function(){ - var c = this.compile('<div><input name="name" ng:required><input ng:show="show" name="name" ng:required></div>', undefined, jqLite(document.body)); + var c = this.compile('<div><input name="name" ng:required><input ng:show="show" name="name" ng:required></div>', jqLite(document.body)); c.scope.$set("show", true); c.scope.$eval(); assertEquals(2, c.scope.$service('$invalidWidgets').length); diff --git a/test/CompilerSpec.js b/test/CompilerSpec.js index 291a5011..647cc366 100644 --- a/test/CompilerSpec.js +++ b/test/CompilerSpec.js @@ -28,7 +28,6 @@ describe('compiler', function(){ compile = function(html){ var e = jqLite("<div>" + html + "</div>"); var scope = compiler.compile(e)(e); - scope.$init(); return scope; }; }); @@ -48,10 +47,8 @@ describe('compiler', function(){ }; }; var template = compiler.compile(e); - scope = template(e); - var init = scope.$init; expect(log).toEqual("found"); - init(); + scope = template(e); expect(e.hasClass('ng-directive')).toEqual(true); expect(log).toEqual("found:init"); }); diff --git a/test/ScenarioSpec.js b/test/ScenarioSpec.js index 50b5e51c..cd1e3115 100644 --- a/test/ScenarioSpec.js +++ b/test/ScenarioSpec.js @@ -13,25 +13,24 @@ describe("ScenarioSpec: Compilation", function(){ it("should compile dom node and return scope", function(){ var node = jqLite('<div ng:init="a=1">{{b=a+1}}</div>')[0]; scope = compile(node); - scope.$init(); expect(scope.a).toEqual(1); expect(scope.b).toEqual(2); }); it("should compile jQuery node and return scope", function(){ - scope = compile(jqLite('<div>{{a=123}}</div>')).$init(); + scope = compile(jqLite('<div>{{a=123}}</div>')); expect(jqLite(scope.$element).text()).toEqual('123'); }); it("should compile text node and return scope", function(){ - scope = compile('<div>{{a=123}}</div>').$init(); + scope = compile('<div>{{a=123}}</div>'); expect(jqLite(scope.$element).text()).toEqual('123'); }); }); describe('scope', function(){ - it("should have set, get, eval, $init, updateView methods", function(){ - scope = compile('<div>{{a}}</div>').$init(); + it("should have $set, $get, $eval, $updateView methods", function(){ + scope = compile('<div>{{a}}</div>'); scope.$eval("$invalidWidgets.push({})"); expect(scope.$set("a", 2)).toEqual(2); expect(scope.$get("a")).toEqual(2); diff --git a/test/ValidatorsSpec.js b/test/ValidatorsSpec.js index 60d20418..65b93133 100644 --- a/test/ValidatorsSpec.js +++ b/test/ValidatorsSpec.js @@ -9,7 +9,7 @@ describe('ValidatorTest', function(){ }; var scope = compile('<input name="name" ng:validate="myValidator:\'hevery\'"/>'); scope.name = 'misko'; - scope.$init(); + scope.$eval(); assertEquals('misko', validator.first); assertEquals('hevery', validator.last); expect(validator._this.$id).toEqual(scope.$id); @@ -99,7 +99,6 @@ describe('ValidatorTest', function(){ jqLite(document.body).append(self.$element); self.$element.data('$validate', noop); self.$root = self; - self.$init(); }); afterEach(function(){ @@ -110,7 +109,6 @@ describe('ValidatorTest', function(){ var value, fn; var scope = compile('<input type="text" name="name" ng:validate="asynchronous:asyncFn"/>'); jqLite(document.body).append(scope.$element); - scope.$init(); var input = scope.$element; scope.asyncFn = function(v,f){ value=v; fn=f; @@ -155,7 +153,6 @@ describe('ValidatorTest', function(){ scope.asyncFn = jasmine.createSpy(); scope.updateFn = jasmine.createSpy(); scope.name = 'misko'; - scope.$init(); scope.$eval(); expect(scope.asyncFn).wasCalledWith('misko', scope.asyncFn.mostRecentCall.args[1]); assertTrue(scope.$element.hasClass('ng-input-indicator-wait')); diff --git a/test/directivesSpec.js b/test/directivesSpec.js index caf0bc15..8e5a10ee 100644 --- a/test/directivesSpec.js +++ b/test/directivesSpec.js @@ -7,7 +7,6 @@ describe("directive", function(){ compile = function(html) { element = jqLite(html); model = compiler.compile(element)(element); - model.$init(); return model; }; }); @@ -116,7 +115,7 @@ describe("directive", function(){ expect(element.attr('src')).toEqual('http://localhost/mysrc'); expect(element.attr('alt')).toEqual('myalt'); }); - + it('should not pretty print JSON in attributes', function(){ var scope = compile('<img alt="{{ {a:1} }}"/>'); expect(element.attr('alt')).toEqual('{"a":1}'); diff --git a/test/markupSpec.js b/test/markupSpec.js index 16efba55..2462f19e 100644 --- a/test/markupSpec.js +++ b/test/markupSpec.js @@ -9,7 +9,6 @@ describe("markups", function(){ compile = function(html) { element = jqLite(html); scope = compiler.compile(element)(element); - scope.$init(); }; }); diff --git a/test/testabilityPatch.js b/test/testabilityPatch.js index 32272a4d..dc6acf8b 100644 --- a/test/testabilityPatch.js +++ b/test/testabilityPatch.js @@ -28,6 +28,7 @@ beforeEach(function(){ compileCache = {}; // reset to jQuery or default to us. bindJQuery(); + jqLite(document.body).html(''); this.addMatchers({ toBeInvalid: function(){ var element = jqLite(this.actual); diff --git a/test/widgetsSpec.js b/test/widgetsSpec.js index 9aa3b95d..606491a9 100644 --- a/test/widgetsSpec.js +++ b/test/widgetsSpec.js @@ -5,12 +5,14 @@ describe("widget", function(){ scope = null; element = null; var compiler = new Compiler(angularTextMarkup, angularAttrMarkup, angularDirective, angularWidget); - compile = function(html, before, parent) { - element = jqLite(html); + compile = function(html, parent) { + if (parent) { + parent.html(html); + element = parent.children(); + } else { + element = jqLite(html); + } scope = compiler.compile(element)(element); - (before||noop).apply(scope); - if (parent) parent.append(element); - scope.$init(); return scope; }; }); @@ -77,9 +79,7 @@ describe("widget", function(){ }); it("should come up blank if null", function(){ - compile('<input type="text" name="age" ng:format="number"/>', function(){ - scope.age = null; - }); + compile('<input type="text" name="age" ng:format="number" ng:init="age=null"/>'); expect(scope.age).toBeNull(); expect(scope.$element[0].value).toEqual(''); }); @@ -137,9 +137,7 @@ describe("widget", function(){ describe("checkbox", function(){ it("should format booleans", function(){ - compile('<input type="checkbox" name="name"/>', function(){ - scope.name = false; - }); + compile('<input type="checkbox" name="name" ng:init="name=false"/>'); expect(scope.name).toEqual(false); expect(scope.$element[0].checked).toEqual(false); }); @@ -184,7 +182,7 @@ describe("widget", function(){ describe("ng:validate", function(){ it("should process ng:validate", function(){ compile('<input type="text" name="price" value="abc" ng:validate="number"/>', - undefined, jqLite(document.body)); + jqLite(document.body)); expect(element.hasClass('ng-validation-error')).toBeTruthy(); expect(element.attr('ng-validation-error')).toEqual('Not a number'); @@ -238,7 +236,7 @@ describe("widget", function(){ }); it("should process ng:required", function(){ - compile('<input type="text" name="price" ng:required/>', undefined, jqLite(document.body)); + compile('<input type="text" name="price" ng:required/>', jqLite(document.body)); expect(element.hasClass('ng-validation-error')).toBeTruthy(); expect(element.attr('ng-validation-error')).toEqual('Required'); @@ -255,7 +253,7 @@ describe("widget", function(){ it('should allow conditions on ng:required', function() { compile('<input type="text" name="price" ng:required="ineedz"/>', - undefined, jqLite(document.body)); + jqLite(document.body)); scope.$set('ineedz', false); scope.$eval(); expect(element.hasClass('ng-validation-error')).toBeFalsy(); @@ -336,25 +334,21 @@ describe("widget", function(){ }); it('should honor model over html checked keyword after', function(){ - compile('<div>' + + compile('<div ng:init="choose=\'C\'">' + '<input type="radio" name="choose" value="A""/>' + '<input type="radio" name="choose" value="B" checked/>' + '<input type="radio" name="choose" value="C"/>' + - '</div>', function(){ - this.choose = 'C'; - }); + '</div>'); expect(scope.choose).toEqual('C'); }); it('should honor model over html checked keyword before', function(){ - compile('<div>' + + compile('<div ng:init="choose=\'A\'">' + '<input type="radio" name="choose" value="A""/>' + '<input type="radio" name="choose" value="B" checked/>' + '<input type="radio" name="choose" value="C"/>' + - '</div>', function(){ - this.choose = 'A'; - }); + '</div>'); expect(scope.choose).toEqual('A'); }); @@ -396,7 +390,7 @@ describe("widget", function(){ '<select name="selection" ng:required>' + '<option value="{{$index}}" ng:repeat="opt in options">{{opt}}</option>' + '</select>', - undefined, jqLite(document.body)); + jqLite(document.body)); scope.selection = 1; scope.options = ['one', 'two']; scope.$eval(); @@ -492,14 +486,13 @@ describe("widget", function(){ }); it('should allow binding to objects through index', function(){ - compile('<select name="selection" multiple ng:format="index:list">' + - '<option selected value="0">A</option>' + - '<option selected value="1">B</option>' + - '<option value="2">C</option>' + - '</select>', - function(){ - scope.list = [{name:'A'}, {name:'B'}, {name:'C'}]; - }); + compile('<div ng:init="list = [{name:\'A\'}, {name:\'B\'}, {name:\'C\'}]">' + + '<select name="selection" multiple ng:format="index:list">' + + '<option selected value="0">A</option>' + + '<option selected value="1">B</option>' + + '<option value="2">C</option>' + + '</select>' + + '</div>'); scope.$eval(); expect(scope.selection).toEqual([{name:'A'}, {name:'B'}]); }); @@ -517,14 +510,13 @@ describe("widget", function(){ }); it('should be contain the selected object', function(){ - compile('<select name="selection" multiple ng:format="index:list">' + - '<option value="0">A</option>' + - '<option value="1" selected>B</option>' + - '<option value="2">C</option>' + - '</select>', - function(){ - scope.list = [{name:'A'}, {name:'B'}, {name:'C'}]; - }); + compile('<div ng:init="list = [{name:\'A\'}, {name:\'B\'}, {name:\'C\'}]">' + + '<select name="selection" multiple ng:format="index:list">' + + '<option value="0">A</option>' + + '<option value="1" selected>B</option>' + + '<option value="2">C</option>' + + '</select>' + + '</div>'); scope.$eval(); expect(scope.selection).toEqual([{name:'B'}]); }); @@ -604,7 +596,7 @@ describe("widget", function(){ it('should call change on switch', function(){ var scope = angular.compile('<ng:switch on="url" change="name=\'works\'"><div ng:switch-when="a">{{name}}</div></ng:switch>'); scope.url = 'a'; - scope.$init(); + scope.$eval(); expect(scope.name).toEqual(undefined); expect(scope.$element.text()).toEqual('works'); dealoc(scope); @@ -619,7 +611,7 @@ describe("widget", function(){ scope.childScope.name = 'misko'; scope.url = 'myUrl'; scope.$service('$xhr.cache').data.myUrl = {value:'{{name}}'}; - scope.$init(); + scope.$eval(); scope.$service('$browser').defer.flush(); expect(element.text()).toEqual('misko'); dealoc(scope); @@ -632,7 +624,7 @@ describe("widget", function(){ scope.childScope.name = 'igor'; scope.url = 'myUrl'; scope.$service('$xhr.cache').data.myUrl = {value:'{{name}}'}; - scope.$init(); + scope.$eval(); scope.$service('$browser').defer.flush(); expect(element.text()).toEqual('igor'); @@ -649,7 +641,7 @@ describe("widget", function(){ var scope = angular.compile(element); scope.url = 'myUrl'; scope.$service('$xhr.cache').data.myUrl = {value:'{{c=c+1}}'}; - scope.$init(); + scope.$eval(); scope.$service('$browser').defer.flush(); // this one should really be just '1', but due to lack of real events things are not working @@ -666,7 +658,7 @@ describe("widget", function(){ scope.url = 'myUrl'; scope.$service('$xhr.cache').data.myUrl = {value:'my partial'}; - scope.$init(); + scope.$eval(); scope.$service('$browser').defer.flush(); expect(element.text()).toEqual('my partial'); expect(scope.loaded).toBe(true); @@ -800,7 +792,6 @@ describe("widget", function(){ beforeEach(function() { rootScope = angular.compile('<ng:view></ng:view>'); - rootScope.$init(); $route = rootScope.$service('$route'); $location = rootScope.$service('$location'); $browser = rootScope.$service('$browser'); @@ -867,15 +858,19 @@ describe("widget", function(){ }); it('should be possible to nest ng:view in ng:include', function() { - dealoc(rootScope); - rootScope = angular.compile('<div>include: <ng:include src="\'includePartial.html\'"></ng:include></div>'); - $browser = rootScope.$service('$browser'); + var myApp = angular.scope(); + var $browser = myApp.$service('$browser'); $browser.xhr.expectGET('includePartial.html').respond('view: <ng:view></ng:view>'); $browser.setUrl('http://server/#/foo'); - $route = rootScope.$service('$route'); + var $route = myApp.$service('$route'); $route.when('/foo', {controller: angular.noop, template: 'viewPartial.html'}); - rootScope.$init(); + + dealoc(rootScope); // we are about to override it. + rootScope = angular.compile( + '<div>' + + 'include: <ng:include src="\'includePartial.html\'">' + + '</ng:include></div>', myApp); $browser.xhr.expectGET('viewPartial.html').respond('content'); $browser.xhr.flush(); |
