Files
ionic-framework/js/angular/service/delegateService.js
2014-11-18 16:07:57 -06:00

113 lines
3.8 KiB
JavaScript

function delegateService(methodNames) {
if (methodNames.indexOf('$getByHandle') > -1) {
throw new Error("Method '$getByHandle' is implicitly added to each delegate service. Do not list it as a method.");
}
function trueFn() { return true; }
return ['$log', function($log) {
var delegate = this;
var instances = this._instances = [];
this._registerInstance = function(instance, handle, filterFn) {
instance.$$delegateHandle = handle;
instance.$$filterFn = filterFn || trueFn;
instances.push(instance);
return function deregister() {
var index = instances.indexOf(instance);
if (index !== -1) {
instances.splice(index, 1);
}
};
};
this.$getByHandle = function(handle) {
if (!handle) {
return delegate;
}
return new InstanceForHandle(handle);
};
/*
* Creates a new object that will have all the methodNames given,
* and call them on the given the controller instance matching given
* handle.
* The reason we don't just let $getByHandle return the controller instance
* itself is that the controller instance might not exist yet.
*
* We want people to be able to do
* `var instance = $ionicScrollDelegate.$getByHandle('foo')` on controller
* instantiation, but on controller instantiation a child directive
* may not have been compiled yet!
*
* So this is our way of solving this problem: we create an object
* that will only try to fetch the controller with given handle
* once the methods are actually called.
*/
function InstanceForHandle(handle) {
this.handle = handle;
}
methodNames.forEach(function(methodName) {
InstanceForHandle.prototype[methodName] = function() {
var handle = this.handle;
var args = arguments;
var matchingInstancesFound = 0;
var finalResult;
var result;
//This logic is repeated below; we could factor some of it out to a function
//but don't because it lets this method be more performant (one loop versus 2)
instances.forEach(function(instance) {
if (instance.$$delegateHandle === handle && instance.$$filterFn(instance)) {
matchingInstancesFound++;
result = instance[methodName].apply(instance, args);
//Only return the value from the first call
if (matchingInstancesFound === 1) {
finalResult = result;
}
}
});
if (!matchingInstancesFound) {
return $log.warn(
'Delegate for handle "' + this.handle + '" could not find a ' +
'corresponding element with delegate-handle="' + this.handle + '"! ' +
methodName + '() was not called!\n' +
'Possible cause: If you are calling ' + methodName + '() immediately, and ' +
'your element with delegate-handle="' + this.handle + '" is a child of your ' +
'controller, then your element may not be compiled yet. Put a $timeout ' +
'around your call to ' + methodName + '() and try again.'
);
}
return finalResult;
};
delegate[methodName] = function() {
var args = arguments;
var matchingInstancesFound = 0;
var finalResult;
var result;
//This logic is repeated above
instances.forEach(function(instance, index) {
if (instance.$$filterFn(instance)) {
matchingInstancesFound++;
result = instance[methodName].apply(instance, args);
//Only return the value from the first call
if (matchingInstancesFound === 1) {
finalResult = result;
}
}
});
return finalResult;
};
});
}];
}