0

私が持っているモーダル ディレクティブのリファクタリングについてアドバイスが必要です。私はディレクティブを使い始めたばかりなので、私の問題に対する他のアプローチは大歓迎です。

私のプログラムには、目的のアクションを確認またはキャンセルできる確認モーダルが必要です。多くの場所に表示され、プログラム可能なボタンを使用できるようにする必要があります。キャンセルは、モーダルを非表示にするだけであるという点で一貫しており、確認ボタンは必要なアクションを実行する必要があります。

現在$rootScope、モーダルの表示/非表示/構成に使用しています。これは悪い考えですか?教えてください。

これは私が現在取り組んでいるものです(大まかに言えば、他の不要なコードの多くを切り取ったためです):

index.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関数に一連のデフォルトを設定しました。

app.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、モーダルをトリガーできる my が見つかったビューでボタンを使用します。

eventlist.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

確認するための簡単なディレクティブ:

/**
 * 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

私の方法はベストプラクティスに従っていないかもしれませんが、通常、モーダルのスコープにアクセスし、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();
     }
  }
});

もちろん、サービスの非同期性のため、2 番目のモーダル ポップアップが表示された場合は、いくつかの自動クローズ ロジックを実装する必要があります。そこからは非常に簡単です。具体的なダイアログを個別のサービスとして定義して、詳細を抽象化できます。

 .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)

いくつかの問題があります。まず第一に、モーダルの子スコープにはtitle, buttons, widthプロパティが散らばっているので、transclusion を使用するのは素晴らしいことです。

もう1つのことは、モーダルボディの幅を渡すことですが、それは私の怠惰です(ハードコードされているため、ブートストラップのモーダルボディ幅を適切にスタイルできません)。

また、モーダルのボディ コンテンツは、モーダルを呼び出すコントローラに何らかの形で関連していることが非常に多いため、コントローラからローカル スコープを渡します。たとえば、itemスコープ プロパティとして ItemController があり、モーダルでアイテムの値を編集するための編集ボタンがある場合、子スコープは、それが扱っているモデルを認識している必要があります。したがって、スコープを渡すか、必要な値をオプションで直接渡します。スコープの方が柔軟性が高く、子スコープの初期化により元のモデルを台無しにするのが非常に難しいため、私はスコープを好みます。

全体として、このセットアップが提供するパワーと柔軟性は、サービスが DOM をいじっているという事実を正当化します。rootScope はグローバルな状態から解放され (サービスは外部に詳細を提供せずに独自の状態を管理します)、メイン テンプレートはモーダル パーシャル/ディレクティブ/使用されているかどうかに関係なく解放されます。

于 2013-11-14T15:16:31.723 に答える
0

モーダルが確認された場合、モーダルを開き、必要なコードを実行する小さな確認ディレクティブを作成しました。

app.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>

script.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でボタンをクリックすると、2 つのボタンと、 confirm属性によって渡されたテキストを含むモーダルが開きます。キャンセルボタンをクリックしても何も起こりません。「OK」をクリックして確定すると、 do属性で渡した式が実行されます。

オプションのconfirm-if属性に式を渡すと、式が true の場合にのみモーダルが開かれます。式が false の場合、アクションは確認せずに実行されます。

このスニペットが誰かを助けることを願っています;)

于 2014-03-25T22:32:36.483 に答える