Angular directive for bootstrap popover - angularjs

I write my custom directive for bootstrap popover, but face some trouble.
This is the code:
angular.module('CommandCenterApp')
.directive('bzPopover', function($compile,$http, $commandHelper) {
return{
restrict: "A",
replace: false,
scope: {
currencies:"=data",
selected:"=selected"
},
link: function (scope, element, attrs) {
var html = '<div class="currency-popup">' +
'<span class="select-label">Select currency:</span>'+
'<select class="custom-select" ng-model="selected" ng-options="currency.CurrencyName for currency in currencies track by currency.CurrencyId">' +
'</select>' +
'<button class="btn btn-green" ng-click="saveCurrency()">Save</button>'+
'</div>';
var compiled = $compile(html)(scope);
$(element).popover({
content:compiled,
html: true,
placement:'bottom'
});
scope.saveCurrency = function () {
var obj = {
Currency:scope.selected,
venueId: $commandHelper.getVenueId()
}
$http.post("/api/currencyapi/changecurrency", obj).success(function() {
scope.$emit('currencySaved', scope.selected);
});
//$(element).popover('hide');
}
scope.$watch('selected', function() {
console.log(scope.selected);
});
}
}
});
When I first time invoke popover all works fine, I click on button and it trigger scope.saveChanges function. Then I close popover and invoke it again, and directive doesnt work anymore.
In markup popover present as:
<a bz-popover data="controller.currencies" selected="controller.selectedCurrency" class="change-currency hidden-xs hidden-sm" href>Change currency</a>
Can anyone help me with this?
UPDATE: it looks like all bindings(scope.saveCurrency,watched on selected property) stop working after popover hidding.

Not really sure if this is the problem you're describing because in my fiddle I had to click twice on the button to show the popover after closing the popover.
I don't know what's the problem but with trigger: 'manual' and binding to click event it is working as expected.
Please have a look at the demo below or in this jsfiddle.
I've commented some of your code because it's not needed to show the popover behaviour and also the ajax call is not working in the demo.
angular.module('CommandCenterApp', [])
.controller('MainController', function() {
this.currencies = [{
CurrencyId: 1,
CurrencyName: 'Dollar'},{
CurrencyId: 2,
CurrencyName: 'Euro'}];
})
.directive('bzPopover', function($compile,$http) { //, $commandHelper) {
return{
restrict: "A",
replace: false,
scope: {
currencies:"=data",
selected:"=selected"
},
link: function (scope, element, attrs) {
var html = '<div class="currency-popup">' +
'<span class="select-label">Select currency:</span>'+
'<select class="custom-select" ng-model="selected" ng-options="currency.CurrencyName for currency in currencies track by currency.CurrencyId">' +
'</select>' +
'<button class="btn btn-green" ng-click="saveCurrency()">Save</button>'+
'</div>';
var compiled = $compile(html)(scope);
$(element).popover({
content:compiled,
html: true,
placement:'bottom',
trigger: 'manual'
});
$(element).bind('click', function() {
$(element).popover('toggle');
});
scope.saveCurrency = function () {
var obj = {
Currency:scope.selected,
venueId: 1//$commandHelper.getVenueId()
}
$http.post("/api/currencyapi/changecurrency", obj).success(function() {
scope.$emit('currencySaved', scope.selected);
});
$(element).popover('hide');
}
scope.$watch('selected', function() {
console.log(scope.selected);
});
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular.js"></script>
<script src="https://code.jquery.com/jquery-1.11.3.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/js/bootstrap.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/css/bootstrap.css" rel="stylesheet"/>
<div ng-app="CommandCenterApp" ng-controller="MainController as controller">
<button bz-popover data="controller.currencies" selected="controller.selectedCurrency" class="change-currency hidden-xs hidden-sm">Change currency</button>
</div>

Shameless self-promotion here, but you may want to take a look at the Angualr UI Bootstrap library as we've already done this for you. And even if you don't want to use it, you can just grab the code you need...

Related

How do I dynamically change class in Angular direcitves?

I'm trying to write a custom directive to replace similar buttons on my page. But when I move ng-class into directive's template, it's not working anymore. Is it wrong to include ng-class within custom directive? Should I use addClass and removeClass in link function instead?
html:
<dt-button ngclass="{'active-button': selectedRows.length >=1}" text="tablebuttons.delete" icon="v-delete" ng-click="deleteDialog()"></dt-button>
directive
.directive('dtButton', function() {
return {
restrict: 'E',
scope: {
icon: '#',
text: '#',
ngclass: '='
},
link: function(scope, ielem, iattrs) {
},
template:
'<button ng-class="{{ngclass}}">' +
'<span class="{{icon}}"></span>' +
'<p translate="{{text}}">' +
'</p>' +
'</button>'
}
})
try use this. change class to ng-class in your template.
you pass a model to directive for text in view while it is not 2 way data binding.
template:
'<button class="active-button" ng-class="{{ngclass}}">' +
'<span class="{{icon}}"></span>' +
'<p translate="{{text}}">' +
'</p>' +
'</button>'
// Code goes here
var app = angular
.module('MyApp', [])
.controller('Main', ['$scope',
function($scope) {
var vm = this;
vm.selectedRows = 4;
vm.deleteDialog = function() {
console.log(vm.selectedRows);
vm.selectedRows = 0;
}
}
])
.directive('dtButton', function() {
return {
restrict: 'E',
scope: {
icon: '#',
text: '#',
ngclass: '='
},
controller: "Main as ctrl",
link: function(scope, ielem, iattrs) {
},
template: '<button ng-class="ngclass" >' +
'<p>{{text}}</p>' +
'</button>'
}
});
.active-button {
background-color: green;
color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="main-content" ng-app="MyApp" ng-controller="Main as ctrl">
<div>
<dt-button ngclass="{'active-button':ctrl.selectedRows >=1}" ng-click="ctrl.deleteDialog()" text="delete"></dt-button>
</div>
</div>
I think nothing wrong with your approach to put ng-class at template of directive. I have tried to reproduce your code snippet at this plunk it is give the correct class name active-button which i defined at style.css with background color blue. But because i don't know much about expression selectedRows.length >=1 on your ngclass attribute, i make it just to true value which will always give active-button class to the element. When you change it to false, it will remove the active-button class.
My guess is seem something wrong with your expression selectedRows.length >=1. At following element declaration :
<dt-button ngclass="{'active-button': selectedRows.length >=1}" text="tablebuttons.delete" icon="v-delete" ng-click="deleteDialog()"></dt-button>
Maybe you can check by bind those expression return value to the element with double curly brace or any other way.
Small correction for your code, you may need to put semicolon ( ; ) at the end of return keyword inside .directive().
Try This
jimApp = angular.module("mainApp", []);
jimApp.controller('mainCtrl', function($scope){
$scope.selectedRows = [0];
$scope.tablebuttons = {delete:"Delete"};
$scope.deleteDialog = function(){
$scope.selectedRows = [];
}
});
jimApp.directive('dtButton', function() {
return {
restrict: 'E',
scope: {
icon: '#',
text: '#',
myClass: '#'
},
link: function(scope, ielem, iattrs) {
console.log(scope.myClass);
},
template:
'<button class="{{myClass}}">' +
'<span class="{{icon}}"></span>' +
'{{text}}' +
'</button>'
}
})
.active-button{
background:red;
}
.inactive-button{
background:#ccc;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="mainApp" ng-controller="mainCtrl">
<dt-button my-class="{{selectedRows.length?'active-button':'inactive-button'}}" text="{{tablebuttons.delete}}" icon="v-delete" ng-click="deleteDialog()"></dt-button>
</div>

how to create directive for daterangepicker?

I came across this nice datepicker on this site: http://luisfarzati.github.io/ng-bs-daterangepicker/. It works fine here : http://plnkr.co/edit/qmj5urjBb4TdtUYCuwap?p=preview
However I would like to make a directive to reuse in my site:
app.directive('dateRange', function () {
return {
restrict: 'E',
templateUrl: 'picker.html'
};
});
picker.html:
<link rel="stylesheet" href="http://luisfarzati.github.io/ng-bs-daterangepicker/bower_components/bootstrap-daterangepicker/daterangepicker-bs3.css"/>
<script src="http://luisfarzati.github.io/ng-bs-daterangepicker/bower_components/momentjs/moment.js"></script>
<script src="http://luisfarzati.github.io/ng-bs-daterangepicker/bower_components/bootstrap-daterangepicker/daterangepicker.js"></script>
<script src="http://luisfarzati.github.io/ng-bs-daterangepicker/ng-bs-daterangepicker.js"></script>
<input type="daterange" ng-model="dates4" ranges="ranges">
I used my directive in an index.html:
<date-range></date-range>
Even though it works in the 1st plunkr I cant get it too work as a directive. Why am I getting this error:
Uncaught Error: [$injector:modulerr] http://errors.angularjs.org/1.3.0-beta.14/$injector/modulerr?p0=filtersampl….com%2Fajax%2Flibs%2Fangularjs%2F1.3.0-beta.14%2Fangular.min.js%3A18%3A139)
plunkr:http://plnkr.co/edit/nr8iOIpIDSf26DxiWEJF?p=preview
I have another code for datepicker try this if you found helpful,
datepicker.directive('datepicker', function($compile,$modal) {
return {
restrict: "A",
link: function(scope, element, attr) {
element.addClass("datepicker-input");
element.after("<span class='datepicker-icon'><i class='fa fa-calendar'></i></span>");
if (attr.withmore) {
element.addClass("withMore");
element.next(".datepicker-icon").after('<i class="fa fa-search-plus"></i>');
$compile(element.next(".datepicker-icon").next('.more-datepicker-icon'))(scope);
}
element.datepicker({
format: attr.format ? attr.format : 'dd-mm-yyyy',
autoclose: true,
todayHighlight: true
});
scope.selectdaterange = function(){
scope.modalInstance = $modal.open({
template : '<div class="modal-header">'+
'<h3 class="modal-title">Select Daterange</h3>'+
'</div>'+
'<div class="modal-body">'+
'You have not selected any News to delete. Please select at least one News to delete.'+
'</div>'+
'<div class="modal-footer">'+
'<button class="btn btn-important" ng-click="deleteCancel()">OK</button>'+
'</div>',
scope : scope
});
}
}
};
});

AngularJS: How to implement a directive that outputs its markup?

DEMO
Imagine I have some markup, e.g.:
<my-input model="data.firstName"></my-input>
Now, I would like to create a my-markup directive that will add a button to show/hide its markup.
So, this:
<div my-markup>
<my-input model="data.firstName"></my-input>
</div>
should result in this:
and when the button is clicked, the markup should appear:
The my-markup directive should not break any data bindings of its children.
Here is my attempt to implement this.
The markup appears, but the button doesn't work. Any ideas how to fix this?
PLAYGROUND HERE
Here is my approach. Couple of things:-
1) Instead of isolated scope on myMarkup, create a child scope, ultimately the actual directive myInput will be isolated. This would be required if you do need to support multiple myMarkup directive under the same scope.
2) You need a click event on the button, i wouldn't do logic on the markup instead abstract out to a method on the scope.
3) You would just need one button, do not need 2 buttons. Just change the text of the button.
.directive('myMarkup', function($compile) {
return {
restrict: 'A',
scope: true, //Create a child scope
compile: function(element) {
//Just need one button
var showButton = '<button ng-click="toggleMarkup()">{{model.showMarkup ? "Hide": "Show"}} Markup</button>';
var markup = '<pre ng-show="model.showMarkup">' + escapeHtml(element.html()) + '</pre>';
//append the markups
element.append(showButton).append(markup);
return linker;
}
};
function linker(scope, element) {
scope.model = {
showMarkup: false
};
//Click event handler on the button to toggle markup
scope.toggleMarkup = function(){
scope.model.showMarkup = !scope.model.showMarkup;
}
};
});
Demo
Please see below
function escapeHtml(html) {
return html.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"');
}
angular.module('App', []).controller('AppCtrl', function($scope) {
$scope.data = {
firstName: 'David'
};
}).directive('myInput', function() {
return {
restrict: 'E',
scope: {
model: '='
},
template: '<input class="my-input" type="text" ng-model="model">'
};
}).directive('myMarkup', function() {
return {
restrict: 'A',
scope: {},
link: function(scope, elem, attr) {
},
compile: function(element) {
var showButton = '<button ng-if="data.showMarkup" ng-click="data.showMarkup=!data.showMarkup">Hide Markup</button>';
var hideButton = '<button ng-if="!data.showMarkup" ng-click="data.showMarkup=!data.showMarkup">Show Markup</button>';
var markup = '<pre ng-if="data.showMarkup">' + escapeHtml(element.html()) + '</pre>';
element.append(showButton);
element.append(hideButton);
element.append(markup);
return function(scope, element) {
scope.data = {
showMarkup: true
};
};
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="App" ng-controller="AppCtrl">
<pre>data = {{ data | json }}</pre>
<div my-markup>
<my-input model="data.firstName"></my-input>
</div>
</body>

AngularUI modal to be draggable and resizable

I have an angularUi modal window wrapped in a directive:
html:
<!doctype html>
<html ng-app="plunker">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.8/angular.js"></script>
<script src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.10.0.js"></script>
<script src="main.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div my-modal="{ data: 'test2'}">test2</div>
</body>
</html>
javascript:
angular.module('plunker', ['ui.bootstrap', 'myModal']);
angular.module("myModal", []).directive("myModal", function ($modal) {
"use strict";
return {
template: '<div ng-click="clickMe(rowData)" ng-transclude></div>',
replace: true,
transclude: true,
scope: {
rowData: '&myModal'
},
link: function (scope, element, attrs) {
scope.clickMe = function () {
$modal.open({
template: "<div>Created By:" + scope.rowData().data + "</div>"
+ "<div class=\"modal-footer\">"
+ "<button class=\"btn btn-primary\" ng-click=\"ok()\">OK</button>"
+ "<button class=\"btn btn-warning\" ng-click=\"cancel()\">Cancel</button>"
+ "</div>",
controller: function ($scope, $modalInstance) {
$scope.ok = function () {
$modalInstance.close({ test: "test"});
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
}
});
}
}
};
});
plunker: http://plnkr.co/edit/yzxtWwZQdq94Tagdiswa?p=preview
I want to make the modal draggable and resizable. I searched through the internet and was able to find the following solution for implementing draggable:
http://plnkr.co/edit/jHS4SJ?p=preview
This is the important part:
app.directive('dragable', function(){
return {
restrict: 'A',
link : function(scope,elem,attr){
$(elem).draggable();
}
}
});
but was not able to make it work with my example. Can someone help me with this? I wonder is it possible to use jqueryui modal wrapped in a directive (instead of bootstrap) ? I am not very good at javascript and will be very greatefull for any working example with both options. Thanks
EDIT:
I added jqueryui reference and managed to make the modal draggable by adding this line:
$(".modal-dialog").draggable();
The problem is that I am not sure when to add this line. In the moment I have added this in the cancel method (just to make it work):
$scope.cancel = function () {
$(".modal-dialog").draggable();
};
So when the modal is opened I need to call cancel and only then the modal is draggable. If I call it earlier the .modal-dialog does not yer exist. Suggestions?
updated plunker:
http://plnkr.co/edit/yzxtWwZQdq94Tagdiswa?p=preview
I am missing something little, can someome provide working example ?
I've created a native directive to make the modal draggable. You only need AngularJs and jQuery. The Directive uses the "modal-dialog" class from Ui-Bootstrap modal and you can only move the modal in the header.
.directive('modalDialog', function(){
return {
restrict: 'AC',
link: function($scope, element) {
var draggableStr = "draggableModal";
var header = $(".modal-header", element);
header.on('mousedown', (mouseDownEvent) => {
var modalDialog = element;
var offset = header.offset();
modalDialog.addClass(draggableStr).parents().on('mousemove', (mouseMoveEvent) => {
$("." + draggableStr, modalDialog.parents()).offset({
top: mouseMoveEvent.pageY - (mouseDownEvent.pageY - offset.top),
left: mouseMoveEvent.pageX - (mouseDownEvent.pageX - offset.left)
});
}).on('mouseup', () => {
modalDialog.removeClass(draggableStr);
});
});
}
}
});
If you don't want to modify built-in templates you can write a directive that targets modalWindow:
.directive('modalWindow', function(){
return {
restrict: 'EA',
link: function(scope, element) {
element.draggable();
}
}
});
Please note that you will have to load both jQuery and jQuery UI before AngularJS scripts.
NOTE: Also keep in mind that newer versions of Angular UI bootstrap have been prefixed with "uib" so "modalWindow" becomes "uibModalWindow" with thanks to #valepu
I combined the two above answers and made my modal dragable.
.directive('modalWindow', function(){
return {
restrict: 'EA',
link: function(scope, element) {
$(".modal-dialog").draggable();
}
}
});
an Angular UI modal with a draggable title bar
NOTE: have to load both jQuery and jQuery UI before AngularJS scripts.
angular.module('xxApp')
.directive('uibModalWindow', function () {
return {
restrict: 'EA',
link: function (scope, element) {
$('.modal-content').draggable({handle: ".modal-header"});
}
}
});
Thank you for your examples. I little bit polished your code and this is my final result. to my solution it works perfectly :-)
HTML:
<div class="draggableModal ui-widget-content">
<div class="modal-header">
...
</div>
</div>
angular.module('posProductsManager').directive('modalDialog', function () {
var definition = {
restrict: 'AC',
link: function ($scope, element) {
var draggableStr = "draggableModal";
var header = $(".modal-header", element);
var modalDialog = element;
var clickPosition = null;
var clickOffset = null;
header[0].addEventListener('mousedown', function (position) {
clickPosition = position;
clickOffset = position;
window.addEventListener('mouseup', mouseUpEvent);
window.addEventListener('mousemove', mouseMoveEvent);
});
function mouseUpEvent() {
clickPosition = null;
window.removeEventListener('mouseup', mouseUpEvent);
window.removeEventListener('mousemove', mouseMoveEvent);
}
function mouseMoveEvent(position) {
var offset = modalDialog.parents().offset();
$("." + draggableStr, modalDialog.parents()).offset({
left: clickPosition.pageX + (position.pageX - clickPosition.pageX) - clickOffset.offsetX,
top: clickPosition.pageY + (position.pageY - clickPosition.pageY) - clickOffset.offsetY,
});
clickPosition = position;
}
}
};
return definition;
});
Try using
$(elem).closest('div.modal-dialog').draggable();
in link function

angularjs custom confirm box

So I'm trying to implement a custom confirm box using Angular. Ideally, I would simply like to add an attribute to enable the functionality. Example:
<button type="button" ng-click="delete(foo)">Delete</button> -> <button type="button" ng-click="delete(foo)" ng-confirm="Are you sure you want to delete this foo?">Delete</button>
(foo is inside an ng-repeat... foo in fooList..)
So all of the problems I am having revolve around tying the click event that would normally happen to a different button. I have a seperate directive "confirmBox" that will create my modal (not using bootstrap) and handle all of the showing/hiding/etc.
What I am currently using requires me to alter my ng-click functionality, which I really want to get away from:
Current Implementation:
<button ... ng-click="confirm('Are you sure you want to delete this foo?, 'delete', foo)">Delete</button>
var confirmModule = angular.module('confirm', []);
confirmModule.run(function($rootScope) {
$rootScope.confirm = function(text, func, obj) {
$rootScope.$broadcast('confirm', func, obj, text);
};
});
confirmModule.directive('confirmBox', function($parse) {
return {
restrict: 'A',
template: myModalTemplate,
link: function(scope, element, attrs){
element.hide();
var noBtn = element.find("[name='no']");
noBtn.bind("click", function() {
element.hide();
});
scope.$on("confirm", function(event, func, obj, text) {
var yesBtn = element.find("[name='yes']");
element.show();
yesBtn.unbind("click").bind("click", function() {
scope[func](obj);
});
});
}
}
});
Anyone have any ideas? I started by adding the directive for the button and then unbinding the click event so ng-click doesn't fire. Then I am left with the string 'delete(foo)' from the ng-click attribute that I can execute with $parse(attrs.ngClick)(scope), but I don't know how to tie that to the separate directives button click.
Edit: Here is a fiddle with my current attempt at implementation. The problem is the variable being passed in to the function is always undefined.
http://jsfiddle.net/UCtbj/2/
Edit2: Updated implementation, however I don't particularly like how it links the two directives together by targetting the other directives elements.
http://jsfiddle.net/UCtbj/3/
It seems to me that you're trying to do things the jQuery way from within the directive. However, what you want is as simple as pulling in the UI-Bootstrap directive for confirming actions. http://plnkr.co/edit/JhfAF1?p=preview
First simple service for modal windows:
app.service('ConfirmService', function($modal) {
var service = {};
service.open = function (text, onOk) {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalConfirmCtrl',
resolve: {
text: function () {
return text;
}
}
});
modalInstance.result.then(function (selectedItem) {
onOk();
}, function () {
});
};
return service;
})
app.controller('ModalConfirmCtrl', function ($scope, $modalInstance, text) {
$scope.text = text;
$scope.ok = function () {
$modalInstance.close(true);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
});
Then simple directive that uses it:
app.directive('confirm', function(ConfirmService) {
return {
restrict: 'A',
scope: {
eventHandler: '&ngClick'
},
link: function(scope, element, attrs){
element.unbind("click");
element.bind("click", function(e) {
ConfirmService.open(attrs.confirm, scope.eventHandler);
});
}
}
});
And here u go:
<button ng-click="test(12)" confirm='Are you sure?'>Button</button>
http://plnkr.co/edit/LOZOnsVyx3JU5XoKYn74?p=preview
To allow a button to be marked up like
<button type="button" ng-click="deleteItem(drink)" ng-confirm="Are you sure you want to delete '{{drink.name}}'">Delete</button>
You can write a directive that
Intercepts the click event before ngClick's click handler can run
Opens a dialog (using $modal and not the removed $dialog)
On close of the dialog (which is treated as a success) run the function specified by the ngClick attribute on the element.
Basing the code on the previous answer, you can do this as follows:
app.directive('ngConfirm', function($modal, $parse) {
return {
// So the link function is run before ngClick's, which has priority 0
priority: -1,
link: function(scope, element, attrs) {
element.on('click', function(e) {
// Don't run ngClick's handler
e.stopImmediatePropagation();
$modal.open({
templateUrl: 'ng-confirm-template',
controller: 'ngConfirmController',
resolve: {
message: function() {
return attrs.ngConfirm;
}
}
}).result.then(function() {
// Pass original click as '$event', just like ngClick
$parse(attrs.ngClick)(scope, {$event: e});
});
});
}
};
});
which needs a simple controller:
app.controller('ngConfirmController', function($scope, $modalInstance, message) {
$scope.message = message;
$scope.yes = function() {
$modalInstance.close();
};
$scope.no = function() {
$modalInstance.dismiss();
};
});
and template for the dialog:
<script type="text/ng-template" id="ng-confirm-template">
<div class="modal-body">
<p>{{message}}</p>
</div>
<div class="modal-footer">
<button class="btn btn-link pull-left" ng-click="no()">No</button>
<button class="btn btn-primary pull-right" ng-click="yes()">Yes</button>
</div>
</script>
You can see this running at http://plnkr.co/edit/Gm9lFsGb099w6kCMQoVY?p=preview
Edit: changed plunker link to example without scrollbar appearing/disappearing on display of the dialog
Here is a nice directive for that.That is ngBootbox. Check it out.
<button class="btn btn-lg btn-primary"
ng-bootbox-title="A cool title!"
ng-bootbox-custom-dialog="Some custom text"
ng-bootbox-buttons="customDialogButtons"
ng-bootbox-class-name="some-class">
Custom dialog
</button>
<script>
$scope.customDialogButtons = {
warning: {
label: "Warning!",
className: "btn-warning",
callback: function() { $scope.addAction('Warning', false); }
},
success: {
label: "Success!",
className: "btn-success",
callback: function() { $scope.addAction('Success!', true) }
},
danger: {
label: "Danger!",
className: "btn-danger",
callback: function() { $scope.addAction('Danger!', false) }
},
main: {
label: "Click ME!",
className: "btn-primary",
callback: function() { $scope.addAction('Main...!', true) }
}
};
</script>
Demo
ngBootbox
I created a repo for this functionality. It wraps the ui-bootstrap modal to produce a confirmation box. It is customizable and easily integrated into any application.
Here is the link to the GitHub: https://github.com/Schlogen/angular-confirm
Example Usages:
As a directive:
<button type="button" ng-click="delete()" confirm-if="checked" confirm="Are you sure, {{name}}?">Delete</button>
As a service:
$confirm({text: 'Are you sure you want to delete?'})
.then(function() {
$scope.deletedConfirm = 'Deleted';
});
Ok, here is the one I ended up going with
1) Create a service for the dialog
app.service('dialogModal', [
'$modal', function($modal) {
return function(message, title, okButton, cancelButton) {
okButton = okButton === false ? false : (okButton || 'Yes');
cancelButton = cancelButton === false ? false : (cancelButton || 'No');
var modalInstance = $modal.open({
templateUrl: '/templates/deletePrompt.html',
controller: ModalInstanceCtrl,
resolve: {
settings: function() {
return {
modalTitle: title,
modalBody: message,
okButton: okButton,
cancelButton: cancelButton
};
}
}
});
// return the modal instance
return modalInstance;
}
}
]);
2) Create a controller and pass the model instance in it
var ModalInstanceCtrl = function ($scope, $modalInstance, settings) {
angular.extend($scope, settings);
$scope.ok = function () {
$modalInstance.close(true);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
};
3) included the link into the header to take on default styling
<link data-require="bootstrap-css#3.x" data-semver="3.1.1" rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" />
4) overwrote the styling in my own css
5) Here is my delete prompt template
<div id="overlayClearMainDiv" class="dialog-modal">
<div id="overlayClearText">
<span>{{modalBody}}</span>
</div>
<div id="overlayClearButton">
<button id="overlayClearYesButton" class="confirmButton" type="button" ng-click="ok()" ng-show="okButton">{{okButton}}</button>
<button class="confirmButton-white" ng-click="cancel()" ng-show="cancelButton">{{cancelButton}}</button>
</div>
</div>
Here's a quick one for you - http://plnkr.co/edit/YklthDZcknmvMjU5A6pe?p=preview
So basically if you are interested in showing a modal dialog once a user clicks on let's say, a button there's no need to make it difficult.
All you need is a simple directive that encapsulate $modal service found in ui-bootstrap.
In my simple example I just pass in a string representing a message and then defining a on-confirm attribute that my directive invokes once the user confirms. Invoking the function itself leverages the awesomeness of $parse to resolve the expression and once resolved, invoke it with the scope.
Nice and clear and here's how it looks like.
View
<body ng-controller="AppController">
<input type="button" value="Delete"
confirm="'Are you sure you want to delete me?'" on-confirm="delete()" />
<script type="text/ng-template" id="modal.html">
<div class="modal-header">
<h3 class="modal-title">Confirm</h3>
</div>
<div class="modal-body">
<p>The world won't be a better place if you delete me.</p>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="ok()">OK</button>
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
</div>
</script>
</body>
Controller / Directive
angular
.module('App', ['ui.bootstrap'])
.controller('AppController', ['$scope', function($scope){
$scope.delete = function(){
alert('Woho, Im deleted!');
};
}])
.directive('confirm', ['$modal', '$parse', function($modal, $parse){
return {
link: function(scope, el, attr){
el.bind('click', function(){
var instance = $modal.open({
templateUrl: 'modal.html',
controller: ['$scope', '$modalInstance', modalController]
});
instance.result.then(function(){
// close - action!
$parse(attr.onConfirm)(scope);
},function(){
// dimisss - do nothing
});
});
}
};
function modalController(modalScope, $modalInstance){
modalScope.ok = function(){
modalInstance.close();
};
modalScope.cancel = function(){
modalInstance.dismiss();
};
}
}]);

Resources