Draggable Angular UI Modal loses focus - angularjs

In this plunk I have an Angular UI modal with a draggable title bar. When you drag the bar, the entire modal moves. Problem is that if I move the mouse relatively fast up and down, the cursor loses focus on the bar and the modal stops moving. Any ideas how to fix this? Any other method is also welcome.
HTML
<body ng-app="app" ng-controller="ctl">
<script type="text/ng-template" id="myModalContent.html">
<div class="topbar">This is the title</div>
<div class="modal-header">
<h3 class="modal-title" id="modal-title">I'm a modal!</h3>
</div>
<div class="modal-footer">
<button class="btn btn-primary" type="button" ng-click="ok()">OK</button>
</div>
</script>
<button type="button" class="btn btn-default" ng-click="open()">Open me!</button>
</body>
Javascript
var app = angular.module("app", ['ui.bootstrap']);
app.controller("ctl", function($scope,$uibModal,$timeout) {
var modalInstance;
$scope.open = function () {
modalInstance = $uibModal.open({
animation: false,
windowClass: 'the-modal',
templateUrl: 'myModalContent.html'
});
$timeout(function(){
$('.modal-content').draggable({
drag: function( event, ui ) {
if(event.toElement.className.indexOf("topbar") == -1 ) return false;
}
});
},10);
};
});

To solve the problem use draggable correctly. To drag a container by a specified element use handle.
Instead of:
$('.modal-content').draggable({
drag: function( event, ui ) {
if(event.toElement.className.indexOf("topbar") == -1 ) return false;
}
});
Use:
$('.modal-content').draggable({ handle: ".topbar" });
See updated Plunker

Related

AngularJS OpenLayers directive - does not work within angular-ui-dialog

I would like to use AngularJS OpenLayers directive on my page - it works OK but when I put this directive into angular-ui-dialog it won't work.
I cannot see any error in console, any ideas what can be causing this?
Sample usage:
<openlayers width="100px" height="100px"></openlayers>
Plnkr with a demo:
http://plnkr.co/edit/YSfcKaTmNsSpkvSI6wt7?p=preview
It's some kind of a refreshing/rendering issue. You can go around it by adding map to DOM after modal is rendered.
HTML template
<button class="btn btn-primary"
ng-click="demo.modal()">
Open modal
</button>
<script type="text/ng-template"
id="modal.html">
<div class="modal-header">
<h3 class="modal-title">Modal window</h3>
</div>
<div class="modal-body">
<openlayers width="100px"
height="100px"
ng-if="modal.rendered"> <!-- ng-if adds/removes DOM elements -->
</openlayers>
</div>
<div class="modal-footer">
<button class="btn btn-default"
ng-click="$dismiss()">
Cancel
</button>
</div>
</script>
JavaScript
angular.module('app', ['ui.bootstrap', 'openlayers-directive'])
.controller('demoController', function($q, $modal) {
var demo = this;
demo.modal = function() {
$modal.open({
controller: 'modalController',
controllerAs: 'modal',
templateUrl: 'modal.html'
});
};
})
.controller('modalController', function($modalInstance, $timeout) {
var modal = this;
modal.rendered = false;
$modalInstance.rendered.then(function() { // magic here
$timeout(function() {
modal.rendered = true;
});
});
});

Best way to create a reusable modal window in angularjs

I am using html5, angularjs, bootstrap. So each one of them gives many options to create a modal window. Whole of my website has 2 things, one is confirmation dialog or form dialog. So which is the best reusable approach. Should i use html5 or create a directive ?
As mentioned in the comments ui-bootstrap Modal is very useful.
Just for an example here is a factory for confirm modal that you can extend according to your use case:
yourApp.factory("dialog", ["$modal",
function($modal) {
var dialogService = {
confirm: function(options) {
var modalInstance = $modal.open({
templateUrl: 'partials/confirm-modal.html',
controller: ['$scope',
function($scope) {
$scope.header = options.header;
$scope.body = options.body;
$scope.confirmText = options.confirmText || "Close";
$scope.cancelText = options.cancelText || "Confirm";
$scope.hideCancelButton = options.hideCancelButton;
$scope.cancel = function() {
modalInstance.dismiss('cancel');
};
$scope.confirm = function() {
modalInstance.close();
};
}
]
});
return modalInstance.result;
}
}
}
])
And here is your template:
<div class="modal-header">
<button type="button" data-dismiss="modal" aria-hidden="true" class="btn close" ng-click="cancel()">×</button>
<h4 id="noteLabel" class="modal-title">{{header}}</h4>
</div>
<div class="modal-body">
<p ng-bind-html="body" style="font-size: 16px"></p>
</div>
<div class="modal-footer">
<button ng-show="!hideCancelButton" class="btn btn-default" ng-click="cancel()">{{cancelText}}</button>
<button ng-click="confirm()" class="btn btn-primary">{{confirmText}}</button>
</div>

Angular Bootstrap Modal leaves backdrop open

I'm using AngularUI to integrate Bootstrap components in my Angular 1.4 app, such as Modals.
I'm calling a Modal in my controller like so:
var modalInstance = $modal.open({
animation: true,
templateUrl: '/static/templates/support-report-modal.html',
controller: 'ModalInstanceCtrl'
});
Unfortunately, when I want to close the Modal by using:
modalInstance.close();
The modal itself dissapears, and the backdrop also fades out, but it isn't removed from the DOM, so it overlays the whole page leaving the page unresponsive.
When I inspect, I'm seeing this:
In the example in the Documentation on https://angular-ui.github.io/bootstrap/#/modal The class modal-open is removed from body and the whole modal-backdropis removed from the DOM on close.
Why is the Modal fading out but the backdrop not removed from the DOM in my example?
I've checked out many of the other questions about the backdrop of bootstrap Modals but I can't seem to figure out what's going wrong.
This is apparently due to a bug. AngularUI doesn't support Angular 1.4 yet. Once http://github.com/angular-ui/bootstrap/issues/3620 is resolved this will work.
Until the team gets this sorted here is a work around.
<div class="modal-footer">
<button class="btn btn-primary"
ng-click="registerModal.ok()"
remove-modal>OK</button>
<button class="btn btn-warning"
ng-click="registerModal.cancel()"
remove-modal>Cancel</button>
</div>
/*global angular */
(function () {
'use strict';
angular.module('CorvetteClub.removemodal.directive', [])
.directive('removeModal', ['$document', function ($document) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.bind('click', function () {
$document[0].body.classList.remove('modal-open');
angular.element($document[0].getElementsByClassName('modal-backdrop')).remove();
angular.element($document[0].getElementsByClassName('modal')).remove();
});
}
};
}]);
}());
Unfortunately it appears that the team is not on the same page concerning this issue as it was pushed to a separate thread by a contributor and then the thread it was pushed to was closed by another as it was considered "off topic" by another.
Simply you can do like this, first close the modal u have opened
$('#nameOfModal').modal('hide');
basically id of modal Second this to remove if any
$('body').removeClass('modal-open');
lastly to close backdrop
$('.modal-backdrop').remove();
<button type="button" class="close" onclick="$('.modal-backdrop').remove();"
data-dismiss="modal">
$(document).keypress(function(e) {
if (e.keyCode == 27) {
$('.modal-backdrop').remove();
}
});
I am using Angular version 1.3.13 and have a similar issue. I been researching the problem and believe this bug extends from angular version 1.3.13 to 1.4.1 details here https://github.com/angular-ui/bootstrap/pull/3400
And if you scroll to the bottom of that link you will see a post by fernandojunior showing the versions he tested and upgraded to still showing the same issue. He even created a plnker to simulate the issue http://plnkr.co/edit/xQOL58HDXTuvSDsHRbra and I've simulated the issue in the code snippet below using the Angular-UI modal code example.
// angular.module('ui.bootstrap.demo', ['ngAnimate', 'ui.bootstrap']);
angular
.module('ui.bootstrap.demo', [
'ngAnimate',
'ui.bootstrap',
]);
angular.module('ui.bootstrap.demo').controller('ModalDemoCtrl', function ($scope, $modal, $log) {
$scope.items = ['item1', 'item2', 'item3'];
$scope.animationsEnabled = true;
$scope.open = function (size) {
var modalInstance = $modal.open({
animation: $scope.animationsEnabled,
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
size: size,
resolve: {
items: function () {
return $scope.items;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
$scope.toggleAnimation = function () {
$scope.animationsEnabled = !$scope.animationsEnabled;
};
});
// Please note that $modalInstance represents a modal window (instance) dependency.
// It is not the same as the $modal service used above.
angular.module('ui.bootstrap.demo').controller('ModalInstanceCtrl', function ($scope, $modalInstance, items) {
$scope.items = items;
$scope.selected = {
item: $scope.items[0]
};
$scope.ok = function () {
$modalInstance.close($scope.selected.item);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
});
<!doctype html>
<html ng-app="ui.bootstrap.demo">
<head>
<!-- angular 1.4.1 -->
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.1/angular.js"></script>
<!-- angular animate 1.4.1 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.1/angular-animate.min.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.13.0.js"></script>
<script src="example.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div ng-controller="ModalDemoCtrl">
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3 class="modal-title">I'm a modal!</h3>
</div>
<div class="modal-body">
<ul>
<li ng-repeat="item in items">
<a ng-click="selected.item = item">{{ item }}</a>
</li>
</ul>
Selected: <b>{{ selected.item }}</b>
</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>
<button class="btn btn-default" ng-click="open()">Open me!</button>
<button class="btn btn-default" ng-click="open('lg')">Large modal</button>
<button class="btn btn-default" ng-click="open('sm')">Small modal</button>
<button class="btn btn-default" ng-click="toggleAnimation()">Toggle Animation ({{ animationsEnabled }})</button>
<div ng-show="selected">Selection from a modal: {{ selected }}</div>
</div>
</body>
</html>
In you submit button or which ever button/selection that moves you to another page, just have data-dismiss="modal" and that should take care of the back drop. It is just telling to dismiss the modal when you have made your selection.
I am also using Angular 1.3.0 and I am also using UI bootstrap-tpls-0.11.2 and for some reason my issue was happening when I was redirecting to the new page and the backdrop was still displaying, so I ended up adding this code...
.then(function () {
$("#delete").on('hidden.bs.modal', function () {
$scope.$apply();
})
});
which I actually found here....
Hide Bootstrap 3 Modal & AngularJS redirect ($location.path)

Angular UI basic modal not working (demo from docs - with jsfiddle)

I am trying to learn angular ui and copy pasted a demo from their website into a jsfiddle. For some reason it's not working and not giving an error. Can anybody see what I am doing wrong?
If you go into the jsfiddle below and then click the open button nothing happens and there is no error.
JSfiddle: http://jsfiddle.net/baswg1wz/1/
Javascript:
angular.module('ui.bootstrap.demo', ['ui.bootstrap']);
angular.module('ui.bootstrap.demo').controller('ModalDemoCtrl', function ($scope, $modal, $log) {
$scope.items = ['item1', 'item2', 'item3'];
$scope.open = function (size) {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
size: size,
resolve: {
items: function () {
return $scope.items;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
});
// Please note that $modalInstance represents a modal window (instance) dependency.
// It is not the same as the $modal service used above.
angular.module('ui.bootstrap.demo').controller('ModalInstanceCtrl', function ($scope, $modalInstance, items) {
$scope.items = items;
$scope.selected = {
item: $scope.items[0]
};
$scope.ok = function () {
$modalInstance.close($scope.selected.item);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
});
HTML
<div ng-controller="ModalDemoCtrl">
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3 class="modal-title">I'm a modal!</h3>
</div>
<div class="modal-body">
<ul>
<li ng-repeat="item in items">
<a ng-click="selected.item = item">{{ item }}</a>
</li>
</ul>
Selected: <b>{{ selected.item }}</b>
</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>
<button class="btn btn-default" ng-click="open()">Open me!</button>
<button class="btn btn-default" ng-click="open('lg')">Large modal</button>
<button class="btn btn-default" ng-click="open('sm')">Small modal</button>
<div ng-show="selected">Selection from a modal: {{ selected }}</div>
</div>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui/0.4.0/angular-ui.min.js"></script>
It's not giving any errors because you didn't bootstrap your Angular application. You should wrap your entire html in a div (in a real page you should do this on the html or body tag) and then use the ng-app attribute to initialize/bootstrap your application:
<div ng-app="ui.bootstrap.demo">
<!-- your html -->
</div>
Also i noticed you didn't include the right ui library, you're using:
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui/0.4.0/angular-ui.min.js"></script>
You should be using: (also note the http://)
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.0/ui-bootstrap-tpls.min.js"></script>
Furhermore, when using Angular in JSFiddle you should use the no wrap - in <head> option.
That should get you a lot further, but i would recommend using Plunker, if you checked the modal example on the ui.bootstrap site you could have noticed the blue Edit in plunker on the topright of the code, try clicking that.
http://angular-ui.github.io/bootstrap/#/modal

AngularJS UI Bootstrap Scope not disposed after modal dismiss

plunker: http://plnkr.co/edit/CrvOFHSfGnXFFWbaXNxn?p=preview
It seems scope for modal is not disposed of after closing the dialog. I have directive that emits when certain div is available, and modal controller receives it. It works fine on first open and close, one emit one receive. On 2nd dialog open and close, one emit and two receives, showing that there are two controller instances, and it goes on for any subsequent dialog open and close.
Is there anyway to make sure to dispose controller scope after modal dialog is dismissed?
html:
<!doctype html>
<html ng-app="ui.bootstrap.demo">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.11.2.js"></script>
<script src="example.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div ng-controller="ModalDemoCtrl">
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3 class="modal-title">I'm a modal!</h3>
</div>
<div class="modal-body" my-hook>
<ul>
<li ng-repeat="item in items">
<a ng-click="selected.item = item">{{ item }}</a>
</li>
</ul>
Selected: <b>{{ selected.item }}</b>
</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>
<button class="btn btn-default" ng-click="open()">Open me!</button>
<button class="btn btn-default" ng-click="open('lg')">Large modal</button>
<button class="btn btn-default" ng-click="open('sm')">Small modal</button>
<div ng-show="selected">Selection from a modal: {{ selected }}</div>
</div>
</body>
</html>
js:
angular.module('ui.bootstrap.demo', ['ui.bootstrap']);
angular.module('ui.bootstrap.demo').controller('ModalDemoCtrl', function ($scope, $modal, $log) {
$scope.items = ['item1', 'item2', 'item3'];
$scope.open = function (size) {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
size: size,
resolve: {
items: function () {
return $scope.items;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
});
// Please note that $modalInstance represents a modal window (instance) dependency.
// It is not the same as the $modal service used above.
angular.module('ui.bootstrap.demo').controller('ModalInstanceCtrl', function ($scope, $modalInstance, $rootScope, items) {
$scope.items = items;
$scope.selected = {
item: $scope.items[0]
};
$scope.ok = function () {
$modalInstance.close($scope.selected.item);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
$rootScope.$on ('MyTestHook', function(event) {
console.log("MyTestHook received");
});
});
angular.module('ui.bootstrap.demo').directive('myHook', function($timeout,$rootScope) {
function link(scope,element,attrs) {
$timeout(function(){
scope.$root.$emit("MyTestHook");
},500);
}
return {
link: link
};
});
This is not the problem of Modal. Modal scope is destroyed completely on dismiss.
Problem is in the code as you have attached $on on $rootScope so every time you click on model it add new listener in $$listeners and listener's count increased by one because $rootscope doesn't get disposed.
$rootScope.$on ('MyTestHook', function(event) { //every call to open modal will add new listener in rootscope
console.log("MyTestHook received");
});
To avoid this use attach $on on scope that disposed on modal dismiss.
See below debugger image.
http://plnkr.co/edit/iR7rGCFgIchsk4sBg26Q?p=preview

Resources