delegates: allow multiple delegates of same handle

Addresses #877
This commit is contained in:
Andy Joslin
2014-03-24 17:29:30 -06:00
parent 0658699338
commit 1dd7675133
2 changed files with 60 additions and 24 deletions

View File

@@ -3,13 +3,18 @@ function delegateService(methodNames) {
return ['$log', function($log) {
var delegate = this;
this._instances = {};
var instances = this._instances = [];
this._registerInstance = function(instance, handle) {
handle || (handle = ionic.Utils.nextUid());
delegate._instances[handle] = instance;
instance.$$delegateHandle = handle;
instances.push(instance);
return function deregister() {
delete delegate._instances[handle];
var index = instances.indexOf(instance);
if (index !== -1) {
instances.splice(index, 1);
}
};
};
@@ -41,26 +46,33 @@ function delegateService(methodNames) {
}
methodNames.forEach(function(methodName) {
InstanceForHandle.prototype[methodName] = function() {
var instance = delegate._instances[this.handle];
if (!instance) {
return $log.error(
'Delegate with handle "'+this.handle+'" could not find a',
var handle = this.handle;
var instancesToUse = instances.filter(function(instance) {
return instance.$$delegateHandle === handle;
});
if (!instancesToUse.length) {
return $log.warn(
'Delegate for handle "'+this.handle+'" could not find a',
'corresponding element with delegate-handle="'+this.handle+'"!',
methodName, 'was not called!');
}
return instance[methodName].apply(instance, arguments);
return callMethod(instancesToUse, methodName, arguments);
};
delegate[methodName] = function() {
var args = arguments;
var returnValue;
angular.forEach(delegate._instances, function(instance) {
var result = instance[methodName].apply(instance, args);
if (!angular.isDefined(returnValue)) {
returnValue = result;
return callMethod(instances, methodName, arguments);
};
function callMethod(instancesToUse, methodName, args) {
var finalResult;
var result;
instancesToUse.forEach(function(instance) {
result = instance[methodName].apply(instance, args);
if (!angular.isDefined(finalResult)) {
finalResult = result;
}
});
return returnValue;
};
return finalResult;
}
});
}];
}

View File

@@ -2,14 +2,13 @@ describe('DelegateFactory', function() {
function setup(methods) {
var delegate;
inject(function($log, $injector) {
$log.error = jasmine.createSpy('error');
delegate = $injector.instantiate(delegateService(methods || []));
});
return delegate;
}
it('should have properties', function() {
expect(setup()._instances).toEqual({});
expect(setup()._instances).toEqual([]);
expect(setup()._registerInstance).toEqual(jasmine.any(Function));
expect(setup().forHandle).toEqual(jasmine.any(Function));
});
@@ -18,9 +17,10 @@ describe('DelegateFactory', function() {
var delegate = setup();
var instance = {};
var deregister = delegate._registerInstance(instance, 'handle');
expect(delegate._instances['handle']).toBe(instance);
expect(instance.$$delegateHandle).toBe('handle');
expect(delegate._instances[0]).toBe(instance);
deregister();
expect(delegate._instances['handle']).toBeUndefined();
expect(delegate._instances.length).toBe(0);
});
it('should allow reg & dereg of instance, and make its own handle', function() {
@@ -31,9 +31,10 @@ describe('DelegateFactory', function() {
var instance = {};
var deregister = delegate._registerInstance(instance);
expect(ionic.Utils.nextUid).toHaveBeenCalled();
expect(delegate._instances['uid']).toBe(instance);
expect(instance.$$delegateHandle).toBe('uid');
expect(delegate._instances[0]).toBe(instance);
deregister();
expect(delegate._instances['uid']).toBeUndefined();
expect(delegate._instances.length).toBe(0);
});
it('should have given methodNames on root', function() {
@@ -119,9 +120,12 @@ describe('DelegateFactory', function() {
expect(delegate.forHandle('two').a).toEqual(jasmine.any(Function));
expect(delegate.forHandle('invalid').a).toEqual(jasmine.any(Function));
});
it('should do nothing if calling for a non-added instance', function() {
it('should noop & warn if calling for a non-added instance', inject(function($log) {
spyOn($log, 'warn');
expect(delegate.forHandle('one').a()).toBeUndefined();
});
expect($log.warn).toHaveBeenCalled();
}));
it('should call an added instance\'s method', function() {
delegate._registerInstance(instance1, '1');
delegate._registerInstance(instance2, '2');
@@ -137,5 +141,25 @@ describe('DelegateFactory', function() {
expect(instance1.a).not.toHaveBeenCalled();
expect(result).toBe('a2');
});
it('should call multiple instances with the same handle', function() {
var instance3 = {
a: jasmine.createSpy('a3')
};
delegate._registerInstance(instance1, '1');
delegate._registerInstance(instance2, '1');
delegate._registerInstance(instance3, 'other');
var delegateInstance = delegate.forHandle('1');
expect(instance1.a).not.toHaveBeenCalled();
expect(instance2.a).not.toHaveBeenCalled();
expect(instance3.a).not.toHaveBeenCalled();
var result = delegateInstance.a('1');
expect(instance1.a).toHaveBeenCalledWith('1');
expect(instance2.a).toHaveBeenCalledWith('1');
expect(instance3.a).not.toHaveBeenCalled();
expect(result).toBe('a1');
});
});
});