Abiel Muren
Abiel Muren

Reputation: 375

Simplest Angular UI-Bootstrap Modals

I would like to know if I can simplify the modals of ui-bootstrap like the original ones in bootstrap, because for angular is a bunch of code I am really having a nightmare with the ui-bootstrap modals for angular. And it seems that the code is just for customize modals etc, but you need to add functions for open etc.

What if I need an other modal with other template? or what if I need many modals?

This is the code I have from the ui-bootstrap reference help. I tried to erease all unecesary code but still too complex.

VIEW

<div ng-controller="ModalDemoCtrl as $ctrl" class="modal-demo">
    <script type="text/ng-template" id="myModalContent.html">
        <div class="modal-header">
            <h3 class="modal-title" id="modal-title">I'm a modal!</h3>
        </div>
        <div class="modal-body" id="modal-body">
            <ul>
                <li ng-repeat="item in $ctrl.items">
                    <a href="#" ng-click="$event.preventDefault(); $ctrl.selected.item = item">{{ item }}</a>
                </li>
            </ul>
            Selected: <b>{{ $ctrl.selected.item }}</b>
        </div>
        <div class="modal-footer">
            <button class="btn btn-primary" type="button" ng-click="$ctrl.ok()">OK</button>
            <button class="btn btn-warning" type="button" ng-click="$ctrl.cancel()">Cancel</button>
        </div>
    </script>


    <button type="button" class="btn btn-default" ng-click="$ctrl.open('lg')">Large modal</button>
</div>

APP

// MODAL CONTROLLERS
myApp.controller('ModalDemoCtrl', function ($uibModal, $log, $document) {
    var $ctrl = this;
    $ctrl.items = ['item1', 'item2', 'item3'];

    $ctrl.animationsEnabled = true;

    $ctrl.open = function (size, parentSelector) {
        var parentElem = parentSelector ? 
        angular.element($document[0].querySelector('.modal-demo ' + parentSelector)) : undefined;
        var modalInstance = $uibModal.open({
            animation: $ctrl.animationsEnabled,
            ariaLabelledBy: 'modal-title',
            ariaDescribedBy: 'modal-body',
            templateUrl: 'myModalContent.html',
            controller: 'ModalInstanceCtrl',
            controllerAs: '$ctrl',
            size: size,
            appendTo: parentElem,
            resolve: {
                items: function () {
                    return $ctrl.items;
                }
            }
        });

        modalInstance.result.then(function (selectedItem) {
            $ctrl.selected = selectedItem;
        }, function () {
            $log.info('Modal dismissed at: ' + new Date());
        });
    };

    $ctrl.openComponentModal = function () {
        var modalInstance = $uibModal.open({
            animation: $ctrl.animationsEnabled,
            component: 'modalComponent',
            resolve: {
                items: function () {
                    return $ctrl.items;
                }
            }
        });

        modalInstance.result.then(function (selectedItem) {
            $ctrl.selected = selectedItem;
        }, function () {
            $log.info('modal-component dismissed at: ' + new Date());
        });
    };

    $ctrl.openMultipleModals = function () {
        $uibModal.open({
            animation: $ctrl.animationsEnabled,
            ariaLabelledBy: 'modal-title-bottom',
            ariaDescribedBy: 'modal-body-bottom',
            templateUrl: 'stackedModal.html',
            size: 'sm',
            controller: function($scope) {
                $scope.name = 'bottom';  
            }
        });

        $uibModal.open({
            animation: $ctrl.animationsEnabled,
            ariaLabelledBy: 'modal-title-top',
            ariaDescribedBy: 'modal-body-top',
            templateUrl: 'stackedModal.html',
            size: 'sm',
            controller: function($scope) {
                $scope.name = 'top';  
            }
        });
    };

    $ctrl.toggleAnimation = function () {
        $ctrl.animationsEnabled = !$ctrl.animationsEnabled;
    };
});

// Please note that $uibModalInstance represents a modal window (instance) dependency.
// It is not the same as the $uibModal service used above.

myApp.controller('ModalInstanceCtrl', function ($uibModalInstance, items) {
    var $ctrl = this;
    $ctrl.items = items;
    $ctrl.selected = {
        item: $ctrl.items[0]
    };

    $ctrl.ok = function () {
        $uibModalInstance.close($ctrl.selected.item);
    };

    $ctrl.cancel = function () {
        $uibModalInstance.dismiss('cancel');
    };
});

// Please note that the close and dismiss bindings are from $uibModalInstance.

myApp.component('modalComponent', {
    templateUrl: 'myModalContent.html',
    bindings: {
        resolve: '<',
        close: '&',
        dismiss: '&'
    },
    controller: function () {
        var $ctrl = this;

        $ctrl.$onInit = function () {
            $ctrl.items = $ctrl.resolve.items;
            $ctrl.selected = {
                item: $ctrl.items[0]
            };
        };

        $ctrl.ok = function () {
            $ctrl.close({$value: $ctrl.selected.item});
        };

        $ctrl.cancel = function () {
            $ctrl.dismiss({$value: 'cancel'});
        };
    }
});

As you can see, is bunch of code. The only think I want is to have the option of the old fashion way, like:

My button with the modal ID

My modal with the content

Apparently this is impossible with ui-bootstrap, any help will be apreciated

Upvotes: 0

Views: 1072

Answers (1)

N.Pisciotti
N.Pisciotti

Reputation: 91

I have to agree with you on this one, I found the documentation to be a bit verbose for me. As you can see, my templateURL is referencing a separate .html file in the same directory that contains the modal content.

Here's what my solution looks like:

In my controller:

myApp.controller('ModalController', function ($log, $uibModal, $scope) {
  $log.debug('ModalController');

  this.createModal = function() {
    let modal = $uibModal.open({
      backdrop: 'static',
      keyboard: true,
      backdropClick: false,
      template: require('./modal-content.html'),
      scope: $scope
    });

    $scope.modalInstance = modal;
    return modal.result;
  };

  this.triggerModal = function() {
    this.createModal()
    .then( (data) => {
      this.handleSuccess(data);
    })
    .then(null, (reason) => {
      this.handleDismiss(reason);
    });
  };

  this.yes = function() {
    $scope.modalInstance.close('Yes Button Clicked');
  };

  this.no = function() {
    $scope.modalInstance.dismiss('No Button Clicked');
  };

  this.handleSuccess = function(data) {
    $log.info('Modal closed: ' + data);
  };

  this.handleDismiss = function(reason) {
    $log.info('Modal dismissed: ' + reason);
  };
}

Here's what the content of 'modal-content.html' looks like:

<div class="modal-header">
  <h3 class="modal-title">I'm a modal!</h3>
</div>
<div class="modal-body">
  <ul>
    <li>item 1</li>
    <li>item 2</li>
    <li>item 3</li>
  </ul>
</div>
<div class="modal-footer">
  <button class="btn btn-primary" ng-click="landingModalCtrl.yes()">yes</button>
  <button class="btn btn-warning" ng-click="landingModalCtrl.no()">no</button>
</div>

Hope that helps!

Upvotes: 1

Related Questions