简体   繁体   English

从角度服务中调用控制器中方法的最佳方法是什么?

[英]What is the best way to call a method in a controller from a service in angular?

I've done some research on this question both in SO and on Google as well. 我已经在SO和Google中对此问题进行了一些研究。 But none of the answers serve my purpose. 但是,没有一个答案符合我的目的。

I have a modal in an HTML view, which I use to show popup notifications in my app. 我在HTML视图中有一个模式,用于在应用程序中显示弹出通知。 I want to show some buttons ('OK', 'Cancel', 'Login', etc.,) in a div on modal which I pass dynamically as a JS object. 我想在模式上的div上显示一些按钮(“确定”,“取消”,“登录”等),我将其作为JS对象动态传递。 Name of the button being the key and the callback function being the value. 按钮的名称为键,而回调函数为值。

Examples: 例子:

{
    "Login": function(){....}
}

{
    "OK": function(){...},
    "Cancel": function(){...}
}

Now I pass this kind of objects to a method showPopup(message, buttonMap) in the controller of the popup modal I have in view. 现在,我将这种对象传递给我所看到的弹出模式的控制器中的showPopup(message, buttonMap)方法。

message being the display message on the popup and buttonMap being the object in examples. message是在弹出显示消息和buttonMap是在实施例中的对象。

Controller: 控制器:

angular.module('core').controller('PopupController', ['$rootScope', 'LogService', 'MessageHandlerService',
    function ($rootScope, LogService, MessageHandlerService) {    
        var ctrl = this;

        ctrl.buttonMap = {};
        ctrl.btnWidth = 100;

        $rootScope.$on('popup', showPopup);

        function showPopup (event, message, buttonMap) {
            $('#genericModalDialog .popup-content p').html(message);
            ctrl.buttonMap = buttonMap;
            var numberOfButtons = Object.keys(buttonMap).length;
            ctrl.btnWidth = (100 - numberOfButtons*2)/numberOfButtons;
            $("#genericModalDialog").modal('show');
        }

        ctrl.callbackFor = function callbackFor(key) {
            ctrl.buttonMap[key].call(null);
        };
    }
]);

Service: 服务:

    angular.module('core').service('PopupService', ['$rootScope', 'LogService', 'CacheService', 'MessageHandlerService',
        function ($rootScope, LogService) {

            this.isPopupShown = function (){
                return $("#genericModalDialog").hasClass('in');
            }

            this.showPopup = function (message, btnMap){
                $rootScope.$broadcast('popup', message, btnMap);
            }

            this.closePopup = function (){
                $("#genericModalDialog").modal('hide');
            }

        }
    ]);

View: 视图:

<div ng-controller="PopupController as popupCtrl" class="modal fade" id="genericModalDialog" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  <div class="vertical-alignment-helper">
    <div class="modal-dialog vertical-align-center" style="width:94%;">
      <div class="modal-content">
        <div class="modal-body">
          <br/><br/>
          <div class="popup-content">
            <p align="center"></p><br/>
            <div class="popup-action">
              <button type="button" class="btn" style="width:{{popupCtrl.btnWidth}}%; margin:1%" ng-repeat="(buttonName, callBack) in popupCtrl.buttonMap" ng-click="popupCtrl.callbackFor(buttonName)">{{buttonName}}</button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

Since I don't want to instantiate PopupController in every other controller/service, I've written a service called PopupService which has a method that can called and will $broadcast an event called "popup" on $rootscope and I am handling this event in PopupController . 由于我不想在所有其他控制器/服务中实例化PopupController ,因此我编写了一个名为PopupService服务,该服务具有一个可以调用的方法,该方法可以在$rootscope$broadcast并调用$rootscope "popup"事件,而我正在处理该事件在PopupController Everything is triggered and working properly in this case. 在这种情况下,一切都已触发并正常工作。 The only problem I face is the delay in rendering the popup on the UI, I see the message as soon as the popup is displayed but the rendering of buttons is very slow (approx 3 secs) this is because of loading of some other web page in the background. 我面临的唯一问题是延迟在UI上渲染弹出窗口,显示弹出窗口后我立即看到消息,但是按钮的渲染非常慢(大约3秒),这是因为加载了其他一些网页在后台。

When I searched about the issue on the internet I also found this total setup can be changed to a directive and the rendering of dynamic content (in this case the popup and buttons on it.) could be placed in a link function of the directive. 当我在Internet上搜索该问题时,我还发现可以将整个设置更改为指令,并且可以将动态内容的呈现方式(在本例中为弹出窗口和按钮)放在该指令的链接函数中。

Another approach I saw was directly handling the DOM manipulation in the service which of course is not a good way. 我看到的另一种方法是直接在服务中处理DOM操作,这当然不是一个好方法。

Did I miss any other approach or a solution to this issue? 我是否错过任何其他方法或解决方案?

All I want to know is what would the best way be, to handling this situation which is programmatically and design wise good. 我想知道的是,最好的方式是处理这种情况,这在程序上和设计上都是明智的。

If I am not clear please let me know. 如果我不清楚,请告诉我。 I'll try explaining the problem again. 我将尝试再次解释该问题。

Directive would be a much better choice that the DOM manipulation. 指令将是比DOM操作更好的选择。 Additionally you should consider changing the usage of jQuery dialog into a https://angular-ui.github.io/bootstrap/#/modal . 另外,您应该考虑将jQuery对话框的用法更改为https://angular-ui.github.io/bootstrap/#/modal

Here is an example how it can be done: 是一个如何完成的示例:

1) Create the directive 1)创建指令

 app.directive('myModal', function() {
   return {
     restrict: 'E',
     scope: {
       items: "=",
       message: "="
     },
     replace: true,
     templateUrl: "directiveTemplate.html",
     controller: function($scope, $uibModal, $log) {

       $scope.open = function(size) {

         var modalInstance = $uibModal.open({
           animation: $scope.animationsEnabled,
           templateUrl: 'myModalContent.html',
           controller: 'ModalInstanceCtrl',
           size: size,
           resolve: {
             items: function() {
               return $scope.items;
             },
             message: function() {
               return $scope.message;
             }
           }
         });

         modalInstance.result.then(function(selectedItem) {
           $scope.button = selectedItem.name;
           $scope[selectedItem.callback](selectedItem.name);
         });
       };

     }
   }
 });

2) Create modalInstance directive 2)创建modalInstance指令

app.controller('ModalInstanceCtrl', function($scope, $uibModalInstance, items, message) {

  $scope.items = items;
  $scope.message = message;

  $scope.close = function(item) {
    $uibModalInstance.close(item);
  };
});

3) create directive template directiveTemplate.html 3)创建指令模板directiveTemplate.html

<div>
  {{buttonClicked}}
  <br> {{button}}

  <button type="button" class="btn btn-default" ng-click="open('sm')">{{message}}</button>
</div>

4) create popup template 'myModalContent.html' 4)创建弹出模板'myModalContent.html'

{{message}}
<button ng-repeat="item in items" type="button" class="btn btn-default" ng-click="close(item)">{{item.name}}</button>

5) define you controller where you will have list of buttons and message to be displayed in the popup (for demo purpose here are two different list of items and two messages) 5)定义您的控制器,您将在其中显示要在弹出窗口中显示的按钮和消息的列表(出于演示目的,这里是两个不同的项目列表和两个消息)

 app.controller('ModalDemoCtrl', function($scope) {
   $scope.message = "modal 1";
   $scope.items = [{
     name: 'item1',
     callback: "test1"
   }, {
     name: 'item2',
     callback: "test2"
   }, {
     name: 'item3',
     callback: "test3"
   }];

   $scope.message2 = "modal 12222";
   $scope.items2 = [{
     name: 'item1222',
     callback: "test1"
   }, {
     name: 'item2222',
     callback: "test2"
   }, {
     name: 'item3222',
     callback: "test3"
   }];

   $scope.test1 = function(message) {
     $scope.buttonClicked = "clicked test1";
   }
   $scope.test2 = function(message) {
     $scope.buttonClicked = "clicked test2";
   }
   $scope.test3 = function(message) {
     $scope.buttonClicked = "clicked test3";
   }

 });

and in order to you the directive you need: 为了给您指令,您需要:

<div ng-controller="ModalDemoCtrl">
  <my-modal items="items" message="message"></my-modal>
    </br>
  <my-modal items="items2" message="message2"></my-modal>
</div>

If you have directive accessed from different angular application instances, than just inject directive application into the needed one (make sure the directive and modal instance to have a their own defined module ex: var app = angular.module('myPopupDynamicModule', ['ngAnimate', 'ui.bootstrap']); and this is the one to be used for injection into other modules following this example: var app2 = angular.module('ui.bootstrap.demo', ['ngAnimate', 'ui.bootstrap', 'myPopupDynamicModule']); ) 如果您从不同的角度应用程序实例访问了指令, var app = angular.module('myPopupDynamicModule', ['ngAnimate', 'ui.bootstrap']);只是将指令应用程序注入所需的实例中(请确保指令和模态实例具有自己定义的模块,例如: var app = angular.module('myPopupDynamicModule', ['ngAnimate', 'ui.bootstrap']);并在以下示例var app2 = angular.module('ui.bootstrap.demo', ['ngAnimate', 'ui.bootstrap', 'myPopupDynamicModule']);其用于注入其他模块: var app2 = angular.module('ui.bootstrap.demo', ['ngAnimate', 'ui.bootstrap', 'myPopupDynamicModule']);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM