app.factory('ModalHelper', ['$modal', function($modal) {
var baseInjectables = ['$scope', '$modalInstance', '$saveForm', 'resourceAction', 'model'];
/*
* Helps with creation of modal windows.
*
* Dynamically constructs controller for the modal window. Uses `templateUrl` as controller's template. Allows
* to pass a dictionary of resolves for $modal service. These resolves will be copied to the modal's scope once they
* are resolved.
*
* Takes additional parameter `scopeFactories` which is a dictionary of factory functions. The result of calling
* this functions will be copied to the modal's scope. `this` inside of those functions points to the
* ModalController, so it's possible to use controller's functions (getModel, getResolve, ...).
*/
return function(templateUrl, additionalResolves, scopeFactories) {
return new function(){
var self = this;
function ModalController($scope, $modalInstance, $saveForm, resourceAction, model) {
$scope.model = model;
this.getModel = function() {
return $scope.model;
};
// copy resolves to the scope
var resolves = [];
for (var i = baseInjectables.length; i < arguments.length; i++) {
resolves.push(arguments[i]);
}
Object.keys(self.updatedAdditionalResolves).forEach(function(resolveName, index) {
$scope[resolveName] = resolves[index];
});
this.getResolve = function(name) {
if (name in self.updatedAdditionalResolves && name in $scope) {
return $scope[name];
} else {
throw new Error("The resolve '" + name + "' wasn't copied to the modal's scope.")
}
};
var modalController = this;
if (scopeFactories !== undefined) {
Object.keys(scopeFactories).forEach(function(factoryName) {
$scope[factoryName] = scopeFactories[factoryName].call(modalController);
});
}
$scope.cancel = function() {
return $modalInstance.dismiss('cancel');
};
$scope.save = function() {
$saveForm($scope, resourceAction.call(null, $scope.model).$promise, function (savedObject) {
$modalInstance.close(savedObject);
});
};
}
this.openModal = function(model, resourceAction, updatedResolves) {
var injectablesForController = baseInjectables.slice();
self.updatedAdditionalResolves = angular.extend(additionalResolves || {}, updatedResolves || {});
Object.keys(self.updatedAdditionalResolves).forEach(function(resolveName) {
injectablesForController.push(resolveName);
});
injectablesForController.push(ModalController);
var resolveMap = angular.extend({
resourceAction: function() { return resourceAction; },
model: function() { return model; }
}, self.updatedAdditionalResolves);
return $modal.open({
templateUrl: templateUrl,
resolve: resolveMap,
controller: injectablesForController
})
}
};
};
}]);
app.factory('ModalCrudHelper', ['$rootScope', function($rootScope) {
return function(resource, modalHelper, signalPrefix) {
function CrudHelper(resource, modalHelper, signalPrefix) {
function broadcast(eventName, object) {
if (signalPrefix !== undefined) {
$rootScope.$broadcast(signalPrefix + '-' + eventName, object.id);
}
}
this.addObject = function (model, objectsList, updatedResolves) {
var modalInstance = modalHelper.openModal(model, resource.save, updatedResolves);
return modalInstance.result.then(function (object) {
objectsList.push(object);
broadcast('created', object);
});
};
this.editObject = function (object, objectsList, updatedResolves) {
var objectIndex = objectsList.indexOf(object);
var objectCopy = angular.copy(object);
var modalInstance = modalHelper.openModal(objectCopy, resource.update, updatedResolves);
return modalInstance.result.then(function (updatedObject) {
if (objectIndex > -1) {
objectsList.splice(objectIndex, 1, updatedObject);
}
broadcast('updated', updatedObject);
});
};
this.removeObject = function (object, objectsList) {
var index = objectsList.indexOf(object);
return resource.delete({id: object.id}).$promise.then(function () {
if (index > -1) {
objectsList.splice(index, 1);
}
broadcast('deleted', object);
});
};
}
return new CrudHelper(resource, modalHelper, signalPrefix);
}
}]);