removing support for 'eager-published' services

This commit is contained in:
Igor Minar 2011-01-04 00:46:25 -08:00
parent d0270d9256
commit 3ea5941f0e
9 changed files with 83 additions and 61 deletions

View file

@ -1,12 +1,39 @@
# <angular/> 0.9.9 time-shift (in-progress) #
### Performance
- $location and $cookies services are now lazily initialized to avoid the polling overhead when
not needed.
### Breaking changes
- Many of the services are now lazy created instead of 'eager-publish'. You can get these
services back into the root scope by adding ng:init="$location = $inject('$location')"
in your view. The services effected are:
- Support for 'eager-published' services was removed. This change was done to make explicit
dependency declaration always required in order to allow making relatively expensive services
lazily initialized (e.g. $cookie, $location), as well as remove 'magic' and reduce unnecessary
scope namespace pollution.
Complete list of affected services:
- $location
- $route
- $cookies
- $window
- $document
- $exceptionHandler
- $invalidWidgets
To temporarily preserve the 'eager-published' status for these services, you may use `ng:init`
(e.g. `ng:init="$location = $inject('$location'), ...`) in the view or more correctly create
a service like this:
angular.service('published-svc-shim', function() {
this.$location = this.$inject('$location');
this.$route = this.$inject('$route');
this.$cookies = this.$inject('$cookies');
this.$window = this.$inject('$window');
this.$document = this.$inject('$document');
this.$exceptionHandler = this.$inject('$exceptionHandler');
this.$invalidWidgets = this.$inject('$invalidWidgets');
}, {$creation: 'eager'});
# <angular/> 0.9.8 astral-projection (2010-12-23) #

View file

@ -58,9 +58,9 @@ function createInjector(providerScope, providers, cache) {
creation = provider.$creation;
if (creation == 'eager') {
inject(name);
}
if (creation == 'eager-published') {
setter(value, name, inject(name));
} else {
if (isDefined(creation))
throw "Unknown $creation value '" + creation + "' for service " + name;
}
});
} else {

View file

@ -1,8 +1,7 @@
var URL_MATCH = /^(file|ftp|http|https):\/\/(\w+:{0,1}\w*@)?([\w\.-]*)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/,
HASH_MATCH = /^([^\?]*)?(\?([^\?]*))?$/,
DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp':21},
EAGER = 'eager',
EAGER_PUBLISHED = EAGER + '-published';
EAGER = 'eager';
function angularServiceInject(name, fn, inject, eager) {
angularService(name, fn, {$inject:inject, $creation:eager});
@ -26,7 +25,7 @@ function angularServiceInject(name, fn, inject, eager) {
<input ng:init="greeting='Hello World!'" type="text" name="greeting" />
<button ng:click="$window.alert(greeting)">ALERT</button>
*/
angularServiceInject("$window", bind(window, identity, window), [], EAGER_PUBLISHED);
angularServiceInject("$window", bind(window, identity, window), [], EAGER);
/**
* @workInProgress
@ -39,7 +38,7 @@ angularServiceInject("$window", bind(window, identity, window), [], EAGER_PUBLIS
*/
angularServiceInject("$document", function(window){
return jqLite(window.document);
}, ['$window'], EAGER_PUBLISHED);
}, ['$window'], EAGER);
/**
* @workInProgress
@ -382,7 +381,7 @@ angularServiceInject("$log", function($window){
return logFn;
}
}
}, ['$window'], EAGER_PUBLISHED);
}, ['$window'], EAGER);
/**
* @workInProgress
@ -406,7 +405,7 @@ angularServiceInject('$exceptionHandler', function($log){
return function(e) {
$log.error(e);
};
}, ['$log'], EAGER_PUBLISHED);
}, ['$log'], EAGER);
/**
* @workInProgress
@ -531,7 +530,7 @@ angularServiceInject("$invalidWidgets", function(){
}
return invalidWidgets;
}, [], EAGER_PUBLISHED);
}, [], EAGER);

View file

@ -382,10 +382,12 @@ extend(angularValidator, {
cache.current = input;
var inputState = cache.inputs[input];
var inputState = cache.inputs[input],
$invalidWidgets = scope.$inject('$invalidWidgets');
if (!inputState) {
cache.inputs[input] = inputState = { inFlight: true };
scope.$invalidWidgets.markInvalid(scope.$element);
$invalidWidgets.markInvalid(scope.$element);
element.addClass('ng-input-indicator-wait');
asynchronousFn(input, function(error, data) {
inputState.response = data;
@ -393,14 +395,14 @@ extend(angularValidator, {
inputState.inFlight = false;
if (cache.current == input) {
element.removeClass('ng-input-indicator-wait');
scope.$invalidWidgets.markValid(element);
$invalidWidgets.markValid(element);
}
element.data($$validate)();
scope.$root.$eval();
});
} else if (inputState.inFlight) {
// request in flight, mark widget invalid, but don't show it to user
scope.$invalidWidgets.markInvalid(scope.$element);
$invalidWidgets.markInvalid(scope.$element);
} else {
(updateFn||noop)(inputState.response);
}

View file

@ -271,7 +271,7 @@ function valueAccessor(scope, element) {
formatterName = element.attr('ng:format') || NOOP,
formatter = angularFormatter(formatterName),
format, parse, lastError, required,
invalidWidgets = scope.$invalidWidgets || {markValid:noop, markInvalid:noop};
invalidWidgets = scope.$inject('$invalidWidgets') || {markValid:noop, markInvalid:noop};
if (!validator) throw "Validator named '" + validatorName + "' not found.";
if (!formatter) throw "Formatter named '" + formatterName + "' not found.";
format = formatter.format;

View file

@ -515,38 +515,38 @@ BinderTest.prototype.testValidateForm = function() {
var items = [{}, {}];
c.scope.$set("items", items);
c.scope.$eval();
assertEquals(3, c.scope.$get("$invalidWidgets.length"));
assertEquals(3, c.scope.$inject('$invalidWidgets').length);
c.scope.$set('name', '');
c.scope.$eval();
assertEquals(3, c.scope.$get("$invalidWidgets.length"));
assertEquals(3, c.scope.$inject('$invalidWidgets').length);
c.scope.$set('name', ' ');
c.scope.$eval();
assertEquals(3, c.scope.$get("$invalidWidgets.length"));
assertEquals(3, c.scope.$inject('$invalidWidgets').length);
c.scope.$set('name', 'abc');
c.scope.$eval();
assertEquals(2, c.scope.$get("$invalidWidgets.length"));
assertEquals(2, c.scope.$inject('$invalidWidgets').length);
items[0].name = 'abc';
c.scope.$eval();
assertEquals(1, c.scope.$get("$invalidWidgets.length"));
assertEquals(1, c.scope.$inject('$invalidWidgets').length);
items[1].name = 'abc';
c.scope.$eval();
assertEquals(0, c.scope.$get("$invalidWidgets.length"));
assertEquals(0, c.scope.$inject('$invalidWidgets').length);
};
BinderTest.prototype.testValidateOnlyVisibleItems = function(){
var c = this.compile('<div><input name="name" ng:required><input ng:show="show" name="name" ng:required></div>', undefined, jqLite(document.body));
c.scope.$set("show", true);
c.scope.$eval();
assertEquals(2, c.scope.$get("$invalidWidgets.length"));
assertEquals(2, c.scope.$inject('$invalidWidgets').length);
c.scope.$set("show", false);
c.scope.$eval();
assertEquals(1, c.scope.$invalidWidgets.visible());
assertEquals(1, c.scope.$inject('$invalidWidgets').visible());
};
BinderTest.prototype.testDeleteAttributeIfEvaluatesFalse = function() {

View file

@ -53,19 +53,9 @@ describe('injector', function(){
it('should autostart eager services', function(){
var log = '';
providers('eager', function(){log += 'eager;';}, {$creation: 'eager'});
providers('eager', function(){log += 'eager;'; return 'foo'}, {$creation: 'eager'});
inject();
expect(log).toEqual('eager;');
expect(scope.eager).not.toBeDefined();
expect(inject('eager')).toBe('foo');
});
it('should return a list of published objects', function(){
var log = '';
providers('eager', function(){log += 'eager;'; return 'pub'; }, {$creation: 'eager-published'});
inject();
expect(log).toEqual('eager;');
expect(scope.eager).toEqual('pub');
});
});
});

View file

@ -128,7 +128,7 @@ describe('Validator:asynchronous', function(){
it("should not make second request to same value", function(){
asynchronous.call(self, "kai", function(v,f){value=v; fn=f;});
expect(value).toEqual('kai');
expect(self.$invalidWidgets[0]).toEqual(self.$element);
expect(self.$inject('$invalidWidgets')[0]).toEqual(self.$element);
var spy = jasmine.createSpy();
asynchronous.call(self, "kai", spy);

View file

@ -24,7 +24,7 @@ describe("service", function(){
it("should inject $window", function(){
expect(scope.$window).toEqual(window);
expect(scope.$inject('$window')).toEqual(window);
});
xit('should add stylesheets', function(){
@ -44,11 +44,12 @@ describe("service", function(){
function warn(){ logger+= 'warn;'; }
function info(){ logger+= 'info;'; }
function error(){ logger+= 'error;'; }
var scope = createScope({}, angularService, {$window: {console:{log:log, warn:warn, info:info, error:error}}, $document:[{cookie:''}]});
scope.$log.log();
scope.$log.warn();
scope.$log.info();
scope.$log.error();
var scope = createScope({}, angularService, {$window: {console:{log:log, warn:warn, info:info, error:error}}, $document:[{cookie:''}]}),
$log = scope.$inject('$log');
$log.log();
$log.warn();
$log.info();
$log.error();
expect(logger).toEqual('log;warn;info;error;');
});
@ -56,19 +57,21 @@ describe("service", function(){
var logger = "";
function log(){ logger+= 'log;'; }
var scope = createScope({}, angularService, {$window: {console:{log:log}}, $document:[{cookie:''}]});
scope.$log.log();
scope.$log.warn();
scope.$log.info();
scope.$log.error();
var $log = scope.$inject('$log');
$log.log();
$log.warn();
$log.info();
$log.error();
expect(logger).toEqual('log;log;log;log;');
});
it('should use noop if no console', function(){
var scope = createScope({}, angularService, {$window: {}, $document:[{cookie:''}]});
scope.$log.log();
scope.$log.warn();
scope.$log.info();
scope.$log.error();
var scope = createScope({}, angularService, {$window: {}, $document:[{cookie:''}]}),
$log = scope.$inject('$log');
$log.log();
$log.warn();
$log.info();
$log.error();
});
describe('Error', function(){
@ -112,7 +115,7 @@ describe("service", function(){
it('should log errors', function(){
var error = '';
$log.error = function(m) { error += m; };
scope.$exceptionHandler('myError');
scope.$inject('$exceptionHandler')('myError');
expect(error).toEqual('myError');
});
});
@ -263,25 +266,26 @@ describe("service", function(){
scope = compile('<input name="price" ng:required ng:validate="number"></input>');
jqLite(document.body).append(scope.$element);
scope.$init();
expect(scope.$invalidWidgets.length).toEqual(1);
var $invalidWidgets = scope.$inject('$invalidWidgets');
expect($invalidWidgets.length).toEqual(1);
scope.price = 123;
scope.$eval();
expect(scope.$invalidWidgets.length).toEqual(0);
expect($invalidWidgets.length).toEqual(0);
scope.$element.remove();
scope.price = 'abc';
scope.$eval();
expect(scope.$invalidWidgets.length).toEqual(0);
expect($invalidWidgets.length).toEqual(0);
jqLite(document.body).append(scope.$element);
scope.price = 'abcd'; //force revalidation, maybe this should be done automatically?
scope.$eval();
expect(scope.$invalidWidgets.length).toEqual(1);
expect($invalidWidgets.length).toEqual(1);
jqLite(document.body).html('');
scope.$eval();
expect(scope.$invalidWidgets.length).toEqual(0);
expect($invalidWidgets.length).toEqual(0);
});
});