43

I have a modal window that I use to present a form to users. They enter the information and then press a button the has an ng-click. The server processes the request and sends back a response. When the response is success I want to close the modal window from the controller. How can this be achieved?

The modal is a partial included in another page

Main page:

<!-- main content -->
<p>Foo</p>
<!-- angular directive -->
<foo-directive></foo-directive>

Content of that directive:

<div ng-controller="FooCtrl">
    <ul class="thumbnails">
        <li class="span3 tile tile-white" ng-repeat="foo in model.foo">
            <div>
                {{foo.bar}}
            </div>
            <div>
                ({{foo.bam}})
            </div>
            <div>
                <a data-toggle="modal" href="#myModal"><img src="{{foo.imgPath}}"></a>
            </div>
        </li>
    </ul>
    <!-- foo modal partial included by ejs -->
    <% include foo_modal.ejs %>
</div>

Modal markup:

<div id="fooModal" class="modal hide fade in" style="display: none; ">
    <div class="modal-header">
        <a class="close" data-dismiss="modal">×</a>
        <h3>New Device</h3>
    </div>
    <div class="modal-body">
        <h4>Foo Modal</h4>
        <div ng-controller="FooCtrl">
            <form name="fooFrm">
                <input id="email" type="email" class="input-medium" ng-model="fooEmail"
                       placeholder="Email">
                <button class="btn btn-primary btn-small"
                        ng-click="doFoo({email:fooEmail})">Email Link</button>
            </form>
        </div>
    </div>
    <div class="modal-footer">
        <a href="#" class="btn" data-dismiss="modal">Close</a>
    </div>
</div>

Controller code:

functionFooCtrl($scope, FooService) {
    

    $scope.doFoo= function (email) {
       FooService.save({email:email.fooEmail}) {
            alert('Request successful');
            //TODO close Twitter bootstrap modal named fooModal here
        },
            function (err) {
                alert('Your request bonked, sorry');
                //TODO close twitter bootstrap modal named fooModal here
            });
        }
    };

What is the right way to close the modal from the controller in the success and error functions?

starball
  • 20,030
  • 7
  • 43
  • 238
binarygiant
  • 6,362
  • 10
  • 50
  • 73

8 Answers8

53

We can achieve the same without using angular-ui. This can be done using angular directives.

First add the directive to the modal.

<div class="modal fade" my-modal ....>...</div>

Create a new angular directive:

app.directive('myModal', function() {
   return {
     restrict: 'A',
     link: function(scope, element, attr) {
       scope.dismiss = function() {
           element.modal('hide');
       };
     }
   } 
});

Now call the dismiss() method from your controller.

app.controller('MyCtrl', function($scope, $http) {
    // You can call dismiss() here
    $scope.dismiss();
});

I am still in my early days with angular js. I know that we should not manipulate the DOM inside the controllers. So I have the DOM manipulation in the directive. I am not sure if this is equally bad. If I have a better alternative, I shall post it here.

The important thing to note is that we cannot simply use ng-hide or ng-show in the view to hide or show the modal. That simply hides the modal and not the modal backdrop. We have to call the modal() instance method to completely remove the modal.

isubuz
  • 728
  • 1
  • 5
  • 8
  • 1
    Note that in order for this to work, both `jquery.js` and `bootstrap-modal.js` have to be loaded before `angular.js` otherwise the element object will not have the `modal()` function. – lanoxx Feb 20 '14 at 16:07
  • Hi ! I want to do this to 2 modals on the same page. How can I do it ? – Aysennoussi Apr 22 '15 at 00:00
  • 1
    Hey, this doesn't work (at least in my case). If we add `scope.dismiss()` within `link`, I don't think we can use it from a `separate controller`. I tried your solution and it doesn't work. Calling it from the `view` - for example `ng-click="dismiss();"` works, however, taking it to a different `controller` even if the `controller` covers the `directive` doesn't work. – Aakash Nov 28 '15 at 11:49
  • @Syl, But is it a good practice to access the dom element, `$(element).modal` inside the controller. Shouldn't this be done in the service – ashok_khuman Jan 06 '16 at 07:03
  • Hi isubuz, can you answer this question https://stackoverflow.com/questions/43583136/bootstrap-modal-popup-open-and-close-using-angularjs-not-working – Vinoth Jul 31 '17 at 06:10
35

You can do it like this:

angular.element('#modal').modal('hide');
David Ferenczy Rogožan
  • 23,966
  • 9
  • 79
  • 68
Jonathan Flores
  • 351
  • 3
  • 2
22

Have you looked at angular-ui bootstrap? There's a Dialog (ui.bootstrap.dialog) directive that works quite well. You can close the dialog during the call back the angular way (per the example):

$scope.close = function(result){
  dialog.close(result);
};

Update:

The directive has since been renamed Modal.

Foo L
  • 10,977
  • 8
  • 40
  • 52
  • 2
    Closing the dialog is causing the form in side the dialog to submit. Is there any way to stop and just closing? – manikanta May 25 '13 at 03:37
  • I feel that angular-ui bootstrap is not feature complete with the official release of bootstrap, in function and styling. – QueueHammer Aug 28 '13 at 14:56
  • Hi Foo L, can you answer this question https://stackoverflow.com/questions/43583136/bootstrap-modal-popup-open-and-close-using-angularjs-not-working – Vinoth Jul 31 '17 at 06:09
5

Here's a reusable Angular directive that will hide and show a Bootstrap modal.

app.directive("modalShow", function () {
    return {
        restrict: "A",
        scope: {
            modalVisible: "="
        },
        link: function (scope, element, attrs) {

            //Hide or show the modal
            scope.showModal = function (visible) {
                if (visible)
                {
                    element.modal("show");
                }
                else
                {
                    element.modal("hide");
                }
            }

            //Check to see if the modal-visible attribute exists
            if (!attrs.modalVisible)
            {

                //The attribute isn't defined, show the modal by default
                scope.showModal(true);

            }
            else
            {

                //Watch for changes to the modal-visible attribute
                scope.$watch("modalVisible", function (newValue, oldValue) {
                    scope.showModal(newValue);
                });

                //Update the visible value when the dialog is closed through UI actions (Ok, cancel, etc.)
                element.bind("hide.bs.modal", function () {
                    scope.modalVisible = false;
                    if (!scope.$$phase && !scope.$root.$$phase)
                        scope.$apply();
                });

            }

        }
    };

});

Usage Example #1 - this assumes you want to show the modal - you could add ng-if as a condition

<div modal-show class="modal fade"> ...bootstrap modal... </div>

Usage Example #2 - this uses an Angular expression in the modal-visible attribute

<div modal-show modal-visible="showDialog" class="modal fade"> ...bootstrap modal... </div>

Another Example - to demo the controller interaction, you could add something like this to your controller and it will show the modal after 2 seconds and then hide it after 5 seconds.

$scope.showDialog = false;
$timeout(function () { $scope.showDialog = true; }, 2000)
$timeout(function () { $scope.showDialog = false; }, 5000)

I'm late to contribute to this question - created this directive for another question here. Simple Angular Directive for Bootstrap Modal

Hope this helps.

Community
  • 1
  • 1
Ender2050
  • 6,912
  • 12
  • 51
  • 55
  • I was looking for a way to open a modal based on an expression - and this did the trick! Thanks – Kabb5 Dec 09 '14 at 13:08
  • Hi Ender2050, can you answer this question https://stackoverflow.com/questions/43583136/bootstrap-modal-popup-open-and-close-using-angularjs-not-working – Vinoth Jul 31 '17 at 06:11
1

You can add data-dismiss="modal" to your button attributes which call angularjs funtion.

Such as;

<button type="button" class="btn btn-default" data-dismiss="modal">Send Form</button>
maskapsiz
  • 244
  • 5
  • 23
0

I have remixed the answer by @isubuz and this answer by @Umur Kontacı on attribute directives into a version where your controller doesn't call a DOM-like operation like "dismiss", but instead tries to be more MVVM style, setting a boolean property isInEditMode. The view in turn links this bit of info to the attribute directive that opens/closes the bootstrap modal.

var app = angular.module('myApp', []);

app.directive('myModal', function() {
   return {
     restrict: 'A',
     scope: { myModalIsOpen: '=' },
     link: function(scope, element, attr) {
       scope.$watch(
         function() { return scope.myModalIsOpen; },
         function() { element.modal(scope.myModalIsOpen ? 'show' : 'hide'); }
       );
     }
   } 
});

app.controller('MyCtrl', function($scope) {
  $scope.isInEditMode = false;
  $scope.toggleEditMode = function() { 
    $scope.isInEditMode = !$scope.isInEditMode;
  };
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.css" rel="stylesheet"/>

<div ng-app="myApp" ng-controller="MyCtrl as vm">

<div class="modal fade" my-modal my-modal-is-open="isInEditMode">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-body">
        Modal body! IsInEditMode == {{isInEditMode}}
      </div>
      <div class="modal-footer">
        <button class="btn" ng-click="toggleEditMode()">Close</button>
      </div>
    </div>
  </div>
</div>

<p><button class="btn" ng-click="toggleEditMode()">Toggle Edit Mode</button></p> 
<pre>isInEditMode == {{isInEditMode}}</pre>
  
</div>
Community
  • 1
  • 1
Jeroen
  • 60,696
  • 40
  • 206
  • 339
  • Hi Jeroen, can you answer this question https://stackoverflow.com/questions/43583136/bootstrap-modal-popup-open-and-close-using-angularjs-not-working – Vinoth Jul 31 '17 at 06:16
  • @Vinoth Pinging several authors of random (or slightly related) other posts about your question seems like pretty bad form to me. Authoring great questions, updating them with more info and details when you find them, and the bounty system are better ways to get attention for your posts. – Jeroen Jul 31 '17 at 09:13
-1
**just fire bootstrap modal close button click event**
var app = angular.module('myApp', []);
app.controller('myCtrl',function($scope,$http){
  $('#btnClose').click();// this is bootstrap modal close button id that fire click event
})

--------------------------------------------------------------------------------

<div class="modal fade" id="myModal" role="dialog">
    <div class="modal-dialog">
      <div class="modal-content">
        <div class="modal-header">
        </div>
        <div class="modal-body">
          <p>Some text in the modal.</p>
        </div>
        <div class="modal-footer">
          <button type="button" id="btnClose" class="btn btn-default" data-dismiss="modal">Close</button>
        </div>
      </div>
    </div>
  </div>

just set modal 'close button' id as i set btnClose, for closing modal in angular you have to just fire that close button click event as i did $('#btnClose').click()

  • Please consider adding a bit of explanations around your code, and why it solves the question. As is it is hard to understand the purpose of your answer. – Fabien Jul 14 '17 at 18:16
  • Hi peeyush Singh, can you answer this question https://stackoverflow.com/questions/43583136/bootstrap-modal-popup-open-and-close-using-angularjs-not-working – Vinoth Jul 31 '17 at 06:16
-2

You can do it with a simple jquery code.

$('#Mymodal').modal('hide');
cengo
  • 151
  • 1
  • 6