okolobaxa
okolobaxa

Reputation: 342

AngularJS modal window directive

I'm trying to make a directive angularJS directive for Twitter Bootstrap Modal.

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

demoApp.controller('DialogDemoCtrl', function AutocompleteDemoCtrl($scope) {
    $scope.Langs = [
        {Id:"1", Name:"ActionScript"},
        {Id:"2", Name:"AppleScript"},
        {Id:"3", Name:"Asp"},
        {Id:"4", Name:"BASIC"},
        {Id:"5", Name:"C"},
        {Id:"6", Name:"C++"}
    ];

    $scope.confirm = function (id) {
        console.log(id);
        var item = $scope.Langs.filter(function (item) { return item.Id == id })[0];
        var index = $scope.Langs.indexOf(item);
        $scope.Langs.splice(index, 1);
    };
});

demoApp.directive('modal', function ($compile, $timeout) {
    var modalTemplate = angular.element("<div id='{{modalId}}' class='modal' style='display:none'  tabindex='-1' role='dialog' aria-labelledby='myModalLabel' aria-hidden='true'><div class='modal-header'><h3 id='myModalLabel'>{{modalHeaderText}}</h3></div><div class='modal-body'><p>{{modalBodyText}}</p></div><div class='modal-footer'><a class='{{cancelButtonClass}}' data-dismiss='modal' aria-hidden='true'>{{cancelButtonText}}</a><a ng-click='handler()' class='{{confirmButtonClas}}'>{{confirmButtonText}}</a></div></div>");
    var linkTemplate = "<a href='#{{modalId}}' id= role='button' data-toggle='modal' class='btn small_link_button'>{{linkTitle}}</a>"

    var linker = function (scope, element, attrs) {
        scope.confirmButtonText = attrs.confirmButtonText;
        scope.cancelButtonText = attrs.cancelButtonText;
        scope.modalHeaderText = attrs.modalHeaderText;
        scope.modalBodyText = attrs.modalBodyText;
        scope.confirmButtonClass = attrs.confirmButtonClass;
        scope.cancelButtonClass = attrs.cancelButtonClass;
        scope.modalId = attrs.modalId;
        scope.linkTitle = attrs.linkTitle;

        $compile(element.contents())(scope);
        var newTemplate = $compile(modalTemplate)(scope);

        $(newTemplate).appendTo('body');

        $("#" + scope.modalId).modal({
            backdrop: false,
            show: false
        });
    }

    var controller = function ($scope) {
        $scope.handler = function () {
            $timeout(function () {
                $("#"+ $scope.modalId).modal('hide');        
                $scope.confirm();            
            });
        }
    }

    return {
        restrict: "E",
        rep1ace: true,
        link: linker,
        controller: controller,
        template: linkTemplate
        scope: {
            confirm: '&'
        }
    };
});​

Here is JsFiddle example http://jsfiddle.net/okolobaxa/unyh4/15/

But handler() function runs as many times as directives on page. Why? What is the right way?

Upvotes: 8

Views: 34880

Answers (4)

Olivier
Olivier

Reputation: 3471

There is a working native implementation in AngularStrap for Bootstrap3 that leverages ngAnimate from AngularJS v1.2+

You may also want to checkout:

Upvotes: 7

emz
emz

Reputation: 41

I know it might be late but i started trying to figure out why the handler got called several times as an exercise and I couldn't stop until done :P

The reason was simply that each div you created for each modal had no unique id, once I fixed that everything started working. Don't ask me as to what the exact reason for this is though, probably has something to do with the $('#' + scope.modalId).modal() call.

Just though I should post my finding if someone else is trying to figure this out :)

Upvotes: 4

Will Vincent
Will Vincent

Reputation: 331

I've found that just using twitter bootstrap modals the way the twitter bootstrap docs say to is enough to get them working.

I am using a modal to house a user edit form on my admin page. The button I use to launch it has an ng-click attribute that passes the user ID to a function of that scope, which in turn passes that off to a service. The contents of the modal is tied to its own controller that listens for changes from the service and updates values to display on the form.

So.. the ng-click attribute is actually only passing data off, the modal is still triggered with the data-toggle and href tags. As for the content of the modal itself, that's a partial. So, I have multiple buttons on the page that all trigger the single instance of the modal that's in the markup, and depending on the button clicked, the values on the form in that modal are different.

I'll take a look at my code and see if I can pull any of it out to build a plnkr demo.

EDIT: I've thrown together a quick plunker demo illustrating essentially what I'm using in my app: http://embed.plnkr.co/iqVl0Wb57rmKymza7AlI/preview

Bonus, it's got some tests to ensure two password fields match (or highlights them as errored), and disables the submit button if the passwords don't match, or for new users username and password fields are empty. Of course, save doesn't do anything, since it's just a demo.

Enjoy.

Upvotes: 8

maxisam
maxisam

Reputation: 22745

Well, unless you want to reinvent this, otherwise I think there is already a solution.

Check out this from AngularUI. It runs without twitter bootstrap.

Upvotes: 6

Related Questions