2013-02-14 81 views
117

我有一個有自己的控制器的指令。請參閱下面的代碼:來自其他控制器的指令控制器中的調用方法

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

popdown.directive('popdown', function() { 
    var PopdownController = function ($scope) { 
     this.scope = $scope; 
    } 

    PopdownController.prototype = { 
     show:function (message, type) { 
      this.scope.message = message; 
      this.scope.type = type; 
     }, 

     hide:function() { 
      this.scope.message = ''; 
      this.scope.type = ''; 
     } 
    } 

    var linkFn = function (scope, lElement, attrs, controller) { 

    }; 

    return { 
     controller: PopdownController, 
     link: linkFn, 
     replace: true, 
     templateUrl: './partials/modules/popdown.html' 
    } 

}); 

這意味着是錯誤/通知/警告的通知系統。我想要做的是從另一個控制器(不是指令控制器)調用該控制器上的功能show。當我這樣做時,我還希望鏈接函數檢測到某些屬性已更改並執行一些動畫。

下面是一些代碼來舉例說明我要問的:

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

app.controller('IndexController', function($scope, RestService) { 
    var result = RestService.query(); 

    if(result.error) { 
     popdown.notify(error.message, 'error'); 
    } 
}); 

所以popdown指令控制器上調用show時,鏈接功能也應該被觸發,執行動畫。我怎麼能做到這一點?

+0

你在哪裏發出呼叫到頁面上的'popdown'指令 - 是它只是在一個地方,其他控制器應該都可以訪問它,或在不同的地方有幾個彈出窗口? – satchmorun 2013-02-14 21:00:19

+0

我的index.html有這樣的:

基本上只有1彈下實例作爲它的意思是全局可用。 – user253530 2013-02-14 21:12:10

+1

我想你的意思是寫'popdown.show(...)'而不是'popdown.notify(...)'是嗎?否則,通知功能有點令人困惑。 – lanoxx 2014-12-08 14:31:01

回答

166

這是一個有趣的問題,我開始考慮如何實現這樣的事情。

我想出了this (fiddle);

基本上,而不是試圖調用來自控制器的指令,我創建了一個模塊來容納所有被彈邏輯:

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

我把兩件事情的模塊中,這種API的一個factory其能在任何地方注入,並且directive定義實際被彈元素的行爲:

工廠只定義了幾個功能successerror,並保持幾個變量的軌跡:

PopdownModule.factory('PopdownAPI', function() { 
    return { 
     status: null, 
     message: null, 
     success: function(msg) { 
      this.status = 'success'; 
      this.message = msg; 
     }, 
     error: function(msg) { 
      this.status = 'error'; 
      this.message = msg; 
     }, 
     clear: function() { 
      this.status = null; 
      this.message = null; 
     } 
    } 
}); 

該指令獲取注入到它的控制器的API,並且手錶的變化API(我使用了方便的自舉的CSS):

PopdownModule.directive('popdown', function() { 
    return { 
     restrict: 'E', 
     scope: {}, 
     replace: true, 
     controller: function($scope, PopdownAPI) { 
      $scope.show = false; 
      $scope.api = PopdownAPI; 

      $scope.$watch('api.status', toggledisplay) 
      $scope.$watch('api.message', toggledisplay) 

      $scope.hide = function() { 
       $scope.show = false; 
       $scope.api.clear(); 
      }; 

      function toggledisplay() { 
       $scope.show = !!($scope.api.status && $scope.api.message);    
      } 
     }, 
     template: '<div class="alert alert-{{api.status}}" ng-show="show">' + 
        ' <button type="button" class="close" ng-click="hide()">&times;</button>' + 
        ' {{api.message}}' + 
        '</div>' 
    } 
}) 

然後我限定app模塊取決於Popdown

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

app.controller('main', function($scope, PopdownAPI) { 
    $scope.success = function(msg) { PopdownAPI.success(msg); } 
    $scope.error = function(msg) { PopdownAPI.error(msg); } 
}); 

和HTML的樣子:

<html ng-app="app"> 
    <body ng-controller="main"> 
     <popdown></popdown> 
     <a class="btn" ng-click="success('I am a success!')">Succeed</a> 
     <a class="btn" ng-click="error('Alas, I am a failure!')">Fail</a> 
    </body> 
</html> 

我不確定它是否完全理想,但它似乎是一種合理的方式來建立與全球ish彈出式指令的溝通。

再次參考the fiddle

+9

+1不應該在指令外調用指令中的函數 - 這是不好的做法。使用服務來管理指令讀取的全局狀態是非常常見的,這是正確的方法。更多的應用程序包括通知隊列和模態對話框。 – 2013-02-14 22:02:48

+2

優秀的答案!你已經回答了這個問題,以及關於如何編寫好的可重用模塊的所有其他問題,這些模塊可以放在任何其他項目中並按原樣使用。非常感謝!過去兩天我一直在尋找這些信息,卻找不到任何答案來回答我的問題。 – user253530 2013-02-14 22:05:05

+6

非常特殊的答案!對於我們這些來自jQuery和Backbone的人來說,這樣一個有用的例子 – Brandon 2013-06-06 16:00:20

26

您還可以使用事件來觸發彈出窗口。

Here's a fiddle基於satchmorun的解決方案。它省去了PopdownAPI和頂級控制器代替$broadcast S「成功」和「錯誤」事件向下範圍鏈:

$scope.success = function(msg) { $scope.$broadcast('success', msg); }; 
$scope.error = function(msg) { $scope.$broadcast('error', msg); }; 

的彈下模塊然後註冊處理函數爲這些事件,例如g:

$scope.$on('success', function(event, msg) { 
    $scope.status = 'success'; 
    $scope.message = msg; 
    $scope.toggleDisplay(); 
}); 

這起作用,至少在我看來是一個很好的解耦解決方案。如果出於某種原因被認爲是不好的練習,我會讓別人加入。

+1

我能想到的一個缺點是,在選定的答案中,您只需要PopdownAPI(易於使用DI)。在這個你需要訪問控制器的範圍來廣播消息。無論如何,它看起來非常簡潔。 – Julian 2013-08-28 03:34:58

+0

我喜歡這樣比簡單用例的服務方式更好,因爲它保持複雜性,並且仍然鬆散耦合 – for3st 2014-10-21 21:40:34

10

你也可以用name屬性暴露指令的控制器父範圍,像ngForm作用:http://docs.angularjs.org/api/ng.directive:ngForm

在這裏,你可以找到一個非常簡單的例子如何可以實現http://plnkr.co/edit/Ps8OXrfpnePFvvdFgYJf?p=preview

在這個例子中,我有myDirective與專用控制器與$clear方法(排序非常簡單的公共API的指令)。我可以將此控制器發佈到父範圍,並使用在該指令外調用此方法。

+0

這需要控制器之間的關係,對吧?由於OP想要一個信息中心,這可能對他而言並不理想。但學習你的方法也很好。它在許多情況下很有用,正如你所說,角本身就是用它的。 – fasfsfgs 2015-07-19 04:09:51

+0

我試圖按照satchmorun提供的例子。我在運行時生成一些html,但我沒有使用指令的模板。我使用指令的控制器來指定一個函數來從添加的HTML調用,但函數沒有被調用。基本上,我有這個指令:directives.directive('abcXyz',函數($ compile {0}返回{ restrict:'AE', require:'ngModel', controller:function($ scope){ $ scope。 function1 = function(){ .. }; },我的html是:「 Mark 2015-08-03 00:51:48

+0

這是唯一可以暴露指令的優雅解決方案api if指令不是單例!我仍然不喜歡使用'$ scope。$ parent [alias]',因爲它對我來說就像使用內部的角度api一樣。但是仍然找不到更優雅的解決方案其他變體如廣播事件或在父控制器中定義空對象以用於指令API更有異味 – djxak 2015-11-26 17:23:22

3

我有更好的解決方案。

這裏是我的指令,我在指令中注入了對象引用,並通過在指令代碼中添加了調用函數來擴展該指令。

app.directive('myDirective', function() { 
    return { 
     restrict: 'E', 
     scope: { 
     /*The object that passed from the cntroller*/ 
     objectToInject: '=', 
     }, 
     templateUrl: 'templates/myTemplate.html', 

     link: function ($scope, element, attrs) { 
      /*This method will be called whet the 'objectToInject' value is changes*/ 
      $scope.$watch('objectToInject', function (value) { 
       /*Checking if the given value is not undefined*/ 
       if(value){ 
       $scope.Obj = value; 
        /*Injecting the Method*/ 
        $scope.Obj.invoke = function(){ 
         //Do something 
        } 
       }  
      }); 
     } 
    }; 
}); 

聲明與參數在HTML指令:

<my-directive object-to-inject="injectedObject"></ my-directive> 

我的控制器:

app.controller("myController", ['$scope', function ($scope) { 
    // object must be empty initialize,so it can be appended 
    $scope.injectedObject = {}; 

    // now i can directly calling invoke function from here 
    $scope.injectedObject.invoke(); 
}]; 
+0

This basicall y違背了關注原則的分離。您向該指令提供了一個在控制器中實例化的對象,並將該對象的管理職責(即創建調用函數)委派給該指令。在我看來,不是更好的解決方案。 – 2016-08-02 14:54:08

相關問題