0

我需要一些关于重构我拥有的模态指令的建议。我刚刚开始使用指令,因此欢迎使用任何其他方法来解决我的问题。

我的程序需要一个确认模式,我们可以在其中确认或取消所需的操作。它会出现在很多地方,需要能够有一个可编程的按钮。取消是一致的,它只会隐藏模式,确认按钮需要执行所需的任何操作。

我目前正在使用$rootScope显示/隐藏/配置模式。这是一个坏主意吗?请告诉我。

这就是我现在正在使用的(粗略地说,因为我已经删除了很多其他不必要的代码):

索引.html

<!doctype html>
<html lang="en">
    <head>
        <title>My App</title>
    </head>
    <body ng-controller="MenuCtrl">

        <confirmmodal ng-show="$root.confirmModal.isVisible"></confirmmodal>

        <ul>
            <li>Home</li>
            <li>About</li>
            <li>Contact</li>
        </ul>

        <div ng-view></div>

        <!-- build:js scripts/main.js -->
        <script data-main="scripts/main" src="lib/requirejs/require.js"></script>
        <!-- endbuild -->
    </body>
</html>

所以我的模态位于顶部ng-view并且可以从任何地方调用。它位于一个伪全局控制器内,称为MenuCtrl.

这是模态指令代码:

指令.js

/* Confirm Modal */
.directive('confirmmodal', [function() {
    return {
        restrict: 'E',
        templateUrl: 'view/templates/modal-confirm.tpl.html'
    };
}])

它用作以下代码的模板:

modal-confirm.tpl.html

<!-- Confirm Modal Template -->
<div class="overlay">
    <div class="overlay-content extended">
        <span>{{$root.confirmModal.content}}</span>
        <div class="buttons">
            <button class="btn btn-default" ng-click="$root.confirmModal.secondary.action()">{{$root.confirmModal.secondary.content}}</button>
            <button class="btn btn-primary" ng-click="$root.confirmModal.primary.action()">{{$root.confirmModal.primary.content}}</button>
        </div>
    </div>
</div>

我在函数中设置了一堆默认值app.run

应用程序.js

app.run(['$rootScope', function ($rootScope) {
    _.extend($rootScope, {
        confirmModal: {
            isVisible: false,
            content: '',
            primary: {
                action: function() {
                    console.log('hello world');
                },
                content: 'Submit'
            },
            secondary: {
                action: function() {
                    $rootScope.confirmModal.isVisible = false;
                },
                content: 'Cancel'
            }
        }
    });
}]);

所以我还编写了一个模态触发器指令,我的想法是我可以创建不同的触发器,用模态执行不同的操作。

指令.js

/* Resolve Event */
.directive('resolveevent', ['RequestService', '$location', function (RequestService, $location) {
    return {
        restrict: 'A',
        scope: {
            eventtype: '@',
            eventid: '@',
            index: '@'
        },
        controller: ['$scope', function($scope) {

            $scope.remove = function(id) {
                // remove the event from the events array
                $scope.$parent.$parent.$parent.$parent.events.splice(id, 1);
            },

            $scope.config = function(config) {
                _.extend($scope.$root.confirmModal, config);
            },

            $scope.isVisible = function() {
                $scope.$apply(function() {
                    $scope.$root.confirmModal.isVisible = true;
                });
            }
        }],
        link: function( $scope, element, attrs ) {
            var config = {
                content: 'Are you sure you wish to resolve this event?',
                primary: {
                    action: function() {
                        var config = {
                            url: '/Events/' + $scope.eventid,
                            method: 'PUT',
                            data: {
                                event_status: 'resolved'
                            },
                            cache: false
                        }

                        /* Update event with resolved status */
                        RequestService.makeApiRequest(config).success(function(response) {
                            $scope.$root.confirmModal.isVisible = false;
                            $scope.remove($scope.index);
                        });
                    },
                    content: 'Resolve Event'
                }
            }

            element.on('click', function() {
                if (!$scope.$root.confirmModal.isVisible) {
                    $scope.config(config);
                    $scope.isVisible();
                }
            });
        }
    }
}]);

然后我在我所在的视图上使用一个按钮,ng-repeat它能够触发模态:

事件列表.html

<li ng-repeat="event in events">

    <p>Event: {{ event.number }}</p>
    <p>Group: {{ event.group_name }}</p>
    <p>Record Date: {{ event.event_date | moment: 'MM/DD/YYYY h:mm A' }}</p>

    <button resolveevent index="{{$index}}" eventid="{{ event.number }}" class="btn btn-default">Resolve</button>
</li>

这就是我所拥有的,它正在工作,但它似乎有点矫枉过正、效率低下,而且维护起来简直就是一场噩梦。任何人都可以提出改善这一点的方法吗?感谢您的帮助,在此先感谢。

4

4 回答 4

1

你可以看看 bootstrap-ui 项目:http ://angular-ui.github.io/bootstrap/

如果您使用的是 Bootstrap 3,请注意模板,并使用没有它们的版本。您可以在此处下载符合 bootstrap3 的模板:https ://github.com/angular-ui/bootstrap/tree/bootstrap3_bis2_modalPatch

于 2013-11-14T15:10:47.710 回答
1

一个简单的确认指令:

/**
 * A generic confirmation for risky actions.
 * Usage: Add attributes: ng-really-message="Really?" ng-really-click="takeAction()" function
 */
angular.module('app').directive('ngReallyClick', [function() {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            element.bind('click', function() {
                var message = attrs.ngReallyMessage;
                if (message && confirm(message)) {
                    scope.$apply(attrs.ngReallyClick);
                }
            });
        }
    }
}]);
于 2014-07-18T11:31:06.033 回答
0

我创建了一个小的确认指令,如果模态被确认,它会打开一个模态并执行你想要的代码:

应用程序.html

<button type="button" class="btn btn-default"
 nait-confirm-click
 confirm="Do you really want to remove this record?"
 confirm-if="user.disabled == true"
 do="remove(user)">
    Remove
</button>

脚本.js

angular
    .module('xyz', ['ui.bootstrap'])
    .directive('naitConfirmClick', function($modal, $parse) {
        return {
            restrict: 'EA',
            link: function(scope, element, attrs) {
                if (!attrs.do) {
                    return;
                }

                // register the confirmation event
                var confirmButtonText = attrs.confirmButtonText ? attrs.confirmButtonText : 'OK';
                var cancelButtonText = attrs.cancelButtonText ? attrs.cancelButtonText : 'Cancel';
                element.click(function() {
                    // action that should be executed if user confirms
                    var doThis = $parse(attrs.do);

                    // condition for confirmation
                    if (attrs.confirmIf) {
                        var confirmationCondition = $parse(attrs.confirmIf);
                        if (!confirmationCondition(scope)) {
                            // if no confirmation is needed, we can execute the action and leave
                            doThis(scope);
                            scope.$apply();
                            return;
                        }
                    }
                    $modal
                        .open({
                            template: '<div class="modal-body">' + attrs.confirm + '</div>'
                                + '<div class="modal-footer">'
                                +     '<button type="button" class="btn btn-default btn-naitsirch-confirm pull-right" ng-click="$close(\'ok\')">' + confirmButtonText + '</button>'
                                +     '<button type="button" class="btn btn-default btn-naitsirch-cancel pull-right" ng-click="$dismiss(\'cancel\')">' + cancelButtonText + '</button>'
                                + '</div>'
                        })
                        .result.then(function() {
                            doThis(scope);
                            scope.$apply()
                        })
                    ;
                });
            }
        };
    })
;

现在,如果您单击带有nait-confirm-click的按钮,它会打开一个带有两个按钮的模式以及您通过确认属性传递的文本。如果单击取消按钮,则不会发生任何事情。如果您单击“确定”确认,则您通过do属性传递的表达式将被执行。

如果您在可选的confirm-if属性中传递表达式,则仅当表达式为 true 时才会打开模式。如果表达式为假,则无需询问即可执行操作。

我希望这个片段能帮助某人;)

于 2014-03-25T22:32:36.483 回答
0

我的方法可能不符合最佳实践,但我通常最终会创建既可以访问模态范围又可以操作 dom 的专用服务。将其视为自注入指令。

这是模态的容器 html(使用引导程序的样式):

<div class="modal-backdrop"></div>
<div class="modal fade">
    <div class="modal-dialog" ng-style="{width: width}">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" ng-click="close()" aria-hidden="true">&times;</button>
                <h4 class="modal-title">{{title}}</h4>
            </div>
            <div class="modal-body">

            </div>
            <div class="modal-footer">
                <button ng-repeat="(name, callback) in buttons" type="button" ng-click="callback()">{{name}}</button>
            </div>
        </div>
    </div>
</div>

然后是DialogService的伪代码:

.service('DialogService', function($compile, $http, $rootScope) {
  this.open = function(options) {
     //options contain various properties
     //e.g. title, width, template or templateUrl, button map with callbacks
     loadModalContainer()
     .then(loadModalBody)
     .then(init);

     function init() {
       modal = $('body').append(containerHtml).find('.modal');
       modal.append(bodyHtml);
       scope = (options.scope || $rootScope).$new();
       if (options.controller) $controller(options.controller, {$scope: scope});
       $compile(modal)(scope);
       listenForEscKey();
     }
     function close() {
       //clean up event listeners
       //
       if (options.onClose) options.onClose();
       scope.$destroy();
       $('body').find('.modal,.modal-backdrop').remove();
     }
  }
});

当然,由于服务的异步特性,如果弹出第二个模式,您必须实现一些自动关闭逻辑。从那里真的很容易,您可以将具体对话框定义为单独的服务以抽象出细节:

 .service('TermsModal', function(DialogService) {
    this.open = function(acceptCallback, declineCallback, scope) {
       DialogService.open({
         templateUrl: '',
         width: '',
         buttons: {
           accept: acceptCallback,
           decline: declineCallback
         }, 
         scope: scope
       });
    }
 })

然后从任何控制器,您可以使用单线打开模式:TermsModal.open(acceptCallback, declineCallback, $scope)

有几个问题。首先,使用嵌入会很棒,因为现在 modal 的子范围充满了title, buttons, width属性。

另一件事是我传递了模态体的宽度,但这只是我的懒惰(我无法正确设置引导模态体宽度的样式,因为它是硬编码的)。

此外,我从控制器传递本地范围,因为模态的正文内容通常以一种或另一种方式与调用模态的控制器相关。例如,如果我们有 ItemControlleritem作为范围属性,并且我们有一个编辑按钮来编辑模式中的项目值,那么子范围必须知道它正在处理的模型。因此,它要么传递范围,要么直接在选项中传递所需的值。我更喜欢作用域,因为它提供了更大的灵活性,并且通过子作用域初始化,很难弄乱原始模型。

总而言之,这种设置提供的强大功能和灵活性证明了服务与 DOM 有点混淆的事实。您的 rootScope 变得没有全局状态(服务管理自己的状态而不向外界提供详细信息),并且您的主模板没有模态部分/指令/可能使用或可能不使用的任何内容。

于 2013-11-14T15:16:31.723 回答