Skip to content

Instantly share code, notes, and snippets.

@joelstein
Last active November 20, 2017 22:04
Show Gist options
  • Save joelstein/a594854d207804b8dedf2d1669a63929 to your computer and use it in GitHub Desktop.
Save joelstein/a594854d207804b8dedf2d1669a63929 to your computer and use it in GitHub Desktop.
AngularJS Bootstrap 4 Modal Service
(function(angular) {
// Define module.
var module = angular.module('bootstrapModal', []);
// Define service.
module.service('$bootstrapModal', ['$q', '$templateRequest', '$rootScope', '$compile', '$controller', function($q, $templateRequest, $rootScope, $compile, $controller) {
var self = this, $element, opened, closed;
// Gets template or template URL.
var getTemplate = function(template, templateUrl) {
var deferred = $q.defer();
// Template string.
if (template) {
deferred.resolve(template);
}
// Template URL.
else if (templateUrl) {
$templateRequest(templateUrl, true).then(function(template) {
deferred.resolve(template);
}, function(error) {
deferred.reject(error);
});
}
// No template specified.
else {
deferred.reject('No modal template or templateUrl was specified.');
}
return deferred.promise;
};
// Closes modal.
self.close = function() {
var deferred = $q.defer();
if ($element) {
deferred.promise = $q.race(opened.promise).finally(function() {
$element.modal('hide');
});
}
else {
deferred.resolve();
}
return deferred.promise;
};
// Opens modal.
self.open = function(options) {
opened = $q.defer();
closed = $q.defer();
// Close open modal.
self.close().catch(function(error) {
opened.reject(error);
})
// Get template.
.then(function() {
return getTemplate(options.template, options.templateUrl).catch(function(error) {
opened.reject(error);
});
})
// Open modal.
.then(function(template) {
// Create scope with special $close() method and options.scopeData.
var scope = (options.scope || $rootScope).$new();
angular.extend(scope, {$close: self.close}, options.scopeData);
// Bind template to scope.
var element = $compile(template)(scope);
// Create controller with $scope.
element.controller = $controller(options.controller, {$scope: scope});
// Append modal element to body.
$element = $(element).appendTo('body')
// Modal is shown.
.on('shown.bs.modal', function() {
// Autofocus support.
angular.forEach($(this).find('input,button,select,textarea'), function(input) {
if (input.attributes.getNamedItem('autofocus')) {
input.focus();
}
});
// Resolve open deferred.
opened.resolve();
})
// Modal is closed.
.on('hidden.bs.modal', function() {
// Remove element.
$(this).modal('dispose').remove();
$element = null;
// Resolve closed deferred.
closed.resolve();
})
// Show modal.
.modal();
});
return {
opened: opened.promise,
closed: closed.promise
};
};
}]);
}(angular));
var module = angular.module('MyModule', ['bootstrapModal']);
module.controller('MyController', ['$bootstrapModal', function($bootstrapModal) {
$scope.openModal = function() {
var modal = $bootstrapModal.open({
templateUrl: 'login.html',
controller: 'LoginController', // can also be a controller function
scope: $scope, // or omit for new child of root scope
scopeData: { // gets set in controller's $scope
name: 'value',
}
})
modal.opened.then(function() {
console.log('modal is open');
}, function(error) {
console.log('modal could not open');
});
modal.closed.then(function() {
console.log('modal closed');
});
};
$scope.closeModal = function() {
$bootstrapModal.close('some reason');
}
}]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment