简体   繁体   English

从AngularJS中的控制器访问指令:是否有适当的解决方案?

[英]Accessing a directive from a controller in AngularJS: is there a proper solution?

My scenario, as shown in this jsfiddle : I have a directive which creates an empty iframe and attaches a load event which listens for clicks. 我的场景,如这个jsfiddle所示:我有一个指令,它创建一个空的iframe并附加一个侦听点击的load事件。 On click calls scope.emitClick() in the controller, which then uses socket.io to send a message to the backend server. 单击调用控制器中的scope.emitClick() ,然后使用socket.io将消息发送到后端服务器。 Even though I am not sure this is the best way to do it, it works. 虽然我不确定这是最好的方法,但它确实有效。

As it happens, I need to receive notifications from the backend server: the controller uses socket.io to listen for messages, and upon receiving a certain message it should be able to change the contents of the iframe created in the directive. 碰巧,我需要从后端服务器接收通知:控制器使用socket.io来监听消息,并且在收到某个消息后,它应该能够更改指令中创建的iframe的内容。

Is there a way to call a method defined in the directive from the controller? 有没有办法从控制器调用指令中定义的方法? Is there a proper way to do something similar to what I am trying to accomplish? 是否有正确的方法来做类似于我想要完成的事情?

html: HTML:

<div ng-controller="SimulationController">
    <virtual-page id="testPage"/>
</div>

js: JS:

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

myModule.controller('SimulationController', function ($scope, socket) {    
    socket.on('update', function (data) {
        //do something to iframe contents
    });

    $scope.emitClick = function (page, target) {
        //socket.emit("click", { page: page, target: target });
        console.log("clicked");
    }
});

myModule.directive('virtualPage', function () {
    var linkFn = function(scope, element, attrs) {       
        element.load(function () {
            console.log(attrs.id + ": contents loaded");

            jQuery(this).contents().off()
            .on("click", function (event) {
                console.log('>> clicked: ' + attrs.id + " - " + event.target);
                scope.emitClick(attrs.id, event.target);
                return false;
            })
        });

        element[0].contentWindow.contents = "<html><head></head><body>test...</body></html>";
        element[0].src = 'javascript:window["contents"]';
    };
    return {
        restrict: 'E',
        template: '<iframe src="about:blank"></iframe>',
        replace: true,
        link : linkFn
    };
});

myModule.factory('socket', function () {
    return {
      on: function (eventName, callback) {
        //fake
      },
      emit: function (eventName, data, callback) {
        //fake
      }
    };
  }); 

Modifying DOM in controller isn't an angular way IMHO. 在控制器中修改DOM不是一种有角度的方式恕我直言。 My approach to this kind problem would be: 我解决这类问题的方法是:

In directive's linking function: 在指令的链接功能中:

var linkFn = function(scope, element, attrs) {
    ...
    scope.$watch('someData', function(newData) {
        // change element according to the new data
    });
};

In controller: 在控制器中:

socket.on('update', function (data) {
    $scope.someData = newData; // Update data, so directive can take action against it
});

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

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