AngularJS reusable modal bootstrap directive
Asked Answered
H

3

10

I'm new with AngularJS. I'm trying to implement a reusable modal Bootstrap.
This is the index.html:

<div ng-controller="mymodalcontroller">
    <modal lolo="modal1" modal-body='body' modal-footer='footer' modal-header='header' data-ng-click="myRightButton()"></modal>
    <a href="#{{modal1}}" role="button" class="btn btn-success" data-toggle="modal">Launch Demo Modal</a>
</div>

This is the module, controller and directive:

var myModal = angular.module('myModal', []);
myModal.controller('mymodalcontroller', function ($scope) {
    $scope.header = 'Put here your header';
    $scope.body = 'Put here your body';
    $scope.footer = 'Put here your footer';

    $scope.myRightButton = function (bool) {
            alert('!!! first function call!');
    };
});
myModal.directive('modal', function () {
    return {
        restrict: 'EA',
        scope: {
            title: '=modalTitle',
            header: '=modalHeader',
            body: '=modalBody',
            footer: '=modalFooter',
            callbackbuttonleft: '&ngClickLeftButton',
            callbackbuttonright: '&ngClick',
            handler: '=lolo'
        },
        templateUrl: 'partialmodal.html',
        transclude: true,
        controller: function ($scope) {
            $scope.handler = 'pop'; 
        },
    };
});

And this is the html template:

<div id="{{handler}}" class="modal fade">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                <h4 class="modal-title">{{header}}</h4>
            </div>
            <div class="modal-body">

                <p class="text-warning">{{body}}</p>

            </div>
            <div class="modal-footer">

                <p class="text-left">{{footer}}</p>

                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                <button type="button" class="btn btn-primary" data-ng-click="callbackbuttonright(), $event.stopPropagation()">Save changes</button>

            </div>
        </div>
    </div>
</div>

I want the 'Launch Alert' button (in the modal) executes the alert and it does it well. The problem is that it is launched when clicking the 'Cancel' button in the Modal and when the window closes. Any ideas?
Here is the working code:Code
Thank you.

Holguin answered 18/3, 2014 at 15:34 Comment(1)
Not answering but this could help you : angular-ui.github.io/bootstrap/#/modalAmelia
A
13

I would suggest you not bind to ng-click. It does some other magic stuff that can screw with things. There is also a syntax error in your partial.

I've fixed those issues in my fork here:

http://plnkr.co/edit/2jK2GFcKSiKgMQMynD1R?p=preview

To summarize:

script.js:

Change your callbackbuttonright binding from ngClick to ngClickRightButton

myModal.directive('modal', function () {
    return {
        restrict: 'EA',
        scope: {
            title: '=modalTitle',
            header: '=modalHeader',
            body: '=modalBody',
            footer: '=modalFooter',
            callbackbuttonleft: '&ngClickLeftButton',
            callbackbuttonright: '&ngClickRightButton',
            handler: '=lolo'
        },
        templateUrl: 'partialmodal.html',
        transclude: true,
        controller: function ($scope) {
            $scope.handler = 'pop'; 
        },
    };
});

index.html:

Change data-ng-click to data-ng-click-right-button

<modal lolo="modal1" modal-body="body" modal-footer="footer" modal-header="header" data-ng-click-right-button="myRightButton()"></modal>

Another minor issue:

partialmodal.html:

Change , to ;

<button type="button" class="btn btn-primary" data-ng-click="callbackbuttonright(); $event.stopPropagation()">Launch Alert</button>
Amati answered 18/3, 2014 at 15:55 Comment(3)
Hi bijtitus nice answer. In your answer plnkr, you said the code contains reusable modal bootstrap directive, however when I tried to create another modal window nothing is happening. Could you look into the code I've created linkLorenlorena
How can I get the event object in myRightButton function in the controller? Please help...Gourmont
thanks, it is the better example I found. In Fact, it is minimalistHirsutism
U
10

If anyone is still interested, here is a example I recently worked on with bootstrap modal and angularjs directive.

HTML:

    <modal visible="showModal1" on-sown="modalOneShown()" on-hide="modalOneHide()">
        <modal-header title="Modal Titel 1"></modal-header>
        <modal-body>
            <h3>This is modal body</h3>
        </modal-body>
        <modal-footer>
            <button class="btn btn-primary"  ng-click="hide(1)">Save</button>
        </modal-footer>
    </modal>

JavaScript:

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

myModalApp.directive('modal', function(){
        return {
            template: '<div class="modal fade bs-example-modal-lg" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true"><div class="modal-dialog modal-sm"><div class="modal-content" ng-transclude><div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button><h4 class="modal-title" id="myModalLabel">Modal title</h4></div></div></div></div>', 
            restrict: 'E',
            transclude: true,
            replace:true,
            scope:{visible:'=', onSown:'&', onHide:'&'},   
            link:function postLink(scope, element, attrs){

                $(element).modal({
                    show: false, 
                    keyboard: attrs.keyboard, 
                    backdrop: attrs.backdrop
                });

                scope.$watch(function(){return scope.visible;}, function(value){

                    if(value == true){
                        $(element).modal('show');
                    }else{
                        $(element).modal('hide');
                    }
                });

                $(element).on('shown.bs.modal', function(){
                  scope.$apply(function(){
                    scope.$parent[attrs.visible] = true;
                  });
                });

                $(element).on('shown.bs.modal', function(){
                  scope.$apply(function(){
                      scope.onSown({});
                  });
                });

                $(element).on('hidden.bs.modal', function(){
                  scope.$apply(function(){
                    scope.$parent[attrs.visible] = false;
                  });
                });

                $(element).on('hidden.bs.modal', function(){
                  scope.$apply(function(){
                      scope.onHide({});
                  });
                });
            }
        };
    }
);

myModalApp.directive('modalHeader', function(){
    return {
        template:'<div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button><h4 class="modal-title">{{title}}</h4></div>',
        replace:true,
        restrict: 'E',
        scope: {title:'@'}
    };
});

myModalApp.directive('modalBody', function(){
    return {
        template:'<div class="modal-body" ng-transclude></div>',
        replace:true,
        restrict: 'E',
        transclude: true
    };
});

myModalApp.directive('modalFooter', function(){
    return {
        template:'<div class="modal-footer" ng-transclude></div>',
        replace:true,
        restrict: 'E',
        transclude: true
    };
});

function ModalController($scope){
    $scope.title = "Angularjs Bootstrap Modal Directive Example";
    $scope.showModal1 = false;
    $scope.showModal2 = false;

    $scope.hide = function(m){
        if(m === 1){
            $scope.showModal1 = false;
        }else{
            $scope.showModal2 = false;
        }
    }

    $scope.modalOneShown = function(){
        console.log('model one shown');
    }

    $scope.modalOneHide = function(){
        console.log('model one hidden');
    }
}
Urbanize answered 10/1, 2015 at 14:22 Comment(1)
@S Hasan Is reusable?Premium
D
7

Compared to other options, below given the minimalist approach using Angular Bootstrap and an angular factory. See a sample snippet below.

  1. Reusable modal view - ConfirmationBox.html

<div class="modal-header">
  <h3 class="modal-title">{{title}}</h3>
</div>
<div class="modal-body">
  {{message}}
</div>
<div class="modal-footer">
  <button type="button" class="btn btn-primary btn-warn" data-ng-click="ok(); $event.stopPropagation()">OK</button>

  <button type="button" class="btn btn-default" data-ng-click="cancel(); $event.stopPropagation()">Cancel</button>
</div>
  1. Reusable module and shared factory, for handling the reusable modal dialog

angular.module('sharedmodule',['ui.bootstrap', 'ui.bootstrap.tpls'])
.factory("sharedService",["$q", "$modal", function ($q, $modal)
{
    var _showConfirmDialog = function (title, message)
    {
        var defer = $q.defer();

        var modalInstance = $modal.open({
            animation: true,
            size: "sm",
            templateUrl: 'ConfirmationBox.html',
            controller: function ($scope, $modalInstance)
            {
                $scope.title = title;
                $scope.message = message;

                $scope.ok = function ()
                {
                    modalInstance.close();
                    defer.resolve();
                };

                $scope.cancel = function ()
                {
                    $modalInstance.dismiss();
                    defer.reject();
                };
            }
        });

        return defer.promise;
    }

    return {

        showConfirmDialog: _showConfirmDialog
    };

}]);
  1. Portion of your View, using the shared modal dialog

<a data-ng-click="showConfirm()">Go Back to previous page</a>
  1. Controller of your view, opening your shared reusable modal dialog and handling notifications (Ok and Cancel)

var myModule = angular.module("mymodule", ['sharedmodule', 'ui.bootstrap', 'ui.bootstrap.tpls']);

myModule.controller('myController', ["$scope", "sharedService", "$window",
function ($scope, sharedService, $window)
{
    $scope.showConfirm = function ()
    {
        sharedService.showConfirmDialog(
            'Confirm!',
            'Any unsaved edit will be discarded. Are you sure to navigate back?')
            .then(function ()
            {
                $window.location = '#/';
            },
            function ()
            {
            });
    };
}]);
Dryasdust answered 1/7, 2015 at 17:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.