Javascript 从其他控制器调用指令控制器中的方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14883476/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 18:13:09  来源:igfitidea点击:

Call method in directive controller from other controller

javascriptjqueryangularjsangularjs-directive

提问by user253530

I have a directive that has its own controller. See the below code:

我有一个指令,它有自己的控制器。请参阅以下代码:

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'
    }

});

This is meant to be a notification system for errors/notifications/warnings. What I want to do is from another controller (not a directive one) to call the function showon this controller. And when I do that, I would also want my link function to detect that some properties changed and perform some animations.

这是一个错误/通知/警告通知系统。我想要做的是从另一个控制器(不是指令控制器)调用show这个控制器上的函数。当我这样做时,我还希望我的链接函数检测到某些属性发生了变化并执行了一些动画。

Here is some code to exemplify what I'm asking for:

这是一些代码来举例说明我的要求:

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

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

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

So when calling showon the popdowndirective controller, the link function should also be triggered and perform an animation. How could I achieve that?

所以打电话时show开启popdown指令控制器,链接功能也应该被触发,执行动画。我怎么能做到这一点?

回答by satchmorun

This is an interesting question, and I started thinking about how I would implement something like this.

这是一个有趣的问题,我开始思考如何实现这样的东西。

I came up with this (fiddle);

我想出了这个(小提琴)

Basically, instead of trying to call a directive from a controller, I created a module to house all the popdown logic:

基本上,我没有尝试从控制器调用指令,而是创建了一个模块来容纳所有弹出逻辑:

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

I put two things in the module, a factoryfor the API which can be injected anywhere, and the directivefor defining the behavior of the actual popdown element:

我在模块中放了两件事,一个factory用于可以在任何地方注入的 API ,另一个directive用于定义实际弹出元素的行为:

The factory just defines a couple of functions successand errorand keeps track of a couple of variables:

工厂只定义了几个函数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;
        }
    }
});

The directive gets the API injected into its controller, and watches the api for changes (I'm using bootstrap css for convenience):

该指令将 API 注入到它的控制器中,并观察 API 的变化(为了方便,我使用了 bootstrap 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>'
    }
})

Then I define an appmodule that depends on Popdown:

然后我定义了一个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); }
});

And the HTML looks like:

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>

I'm not sure if it's completely ideal, but it seemed like a reasonable way to set up communication with a global-ish popdown directive.

我不确定它是否完全理想,但它似乎是一种与 global-ish popdown 指令建立通信的合理方式。

Again, for reference, the fiddle.

再次,作为参考,小提琴

回答by Aron

You can also use events to trigger the Popdown.

您还可以使用事件来触发 Popdown。

Here's a fiddlebased on satchmorun's solution. It dispenses with the PopdownAPI, and the top-level controller instead $broadcasts 'success' and 'error' events down the scope chain:

这是基于 satchmorun 解决方案的小提琴。它省去了 PopdownAPI,而顶层控制器则$broadcast在作用域链中使用 'success' 和 'error' 事件:

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

The Popdown module then registers handler functions for these events, e.g:

然后 Popdown 模块为这些事件注册处理函数,例如:

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

This works, at least, and seems to me to be a nicely decoupled solution. I'll let others chime in if this is considered poor practice for some reason.

这至少有效,并且在我看来是一个很好的解耦解决方案。如果出于某种原因这被认为是不好的做法,我会让其他人插话。

回答by luacassus

You could also expose the directive's controller to the parent scope, like ngFormwith nameattribute does: http://docs.angularjs.org/api/ng.directive:ngForm

您还可以将指令的控制器暴露给父作用域,就像ngForm使用name属性一样:http: //docs.angularjs.org/api/ng.directive: ngForm

Here you could find a very basic example how it could be achieved http://plnkr.co/edit/Ps8OXrfpnePFvvdFgYJf?p=preview

在这里你可以找到一个非常基本的例子,它是如何实现的http://plnkr.co/edit/Ps8OXrfpnePFvvdFgYJf?p=preview

In this example I have myDirectivewith dedicated controller with $clearmethod (sort of very simple public API for the directive). I can publish this controller to the parent scope and use call this method outside the directive.

在这个例子中,我使用myDirective了带有$clear方法的专用控制器(该指令的一种非常简单的公共 API)。我可以将此控制器发布到父作用域,并在指令之外使用调用此方法。

回答by Ashwini Jindal

I got much better solution .

我得到了更好的解决方案。

here is my directive , I have injected on object reference in directive and has extend that by adding invoke function in directive code .

这是我的指令,我在指令中注入了对象引用,并通过在指令代码中添加调用函数来扩展它。

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
                    }
                }    
            });
        }
    };
});

Declaring the directive in the HTML with a parameter:

使用参数在 HTML 中声明指令:

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

my Controller:

我的控制器:

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();
}];