0

假设我有一个包含一些数据的指令,我想在第二个组件(指令或其他)中的其他位置插入它,而不需要控制器链接它们。

例如,以 angularjs 网页的 zippy 为例,但我们没有将输入<div ng-controller="Ctrl3">中的数据竞价到zippy 指令,而是有两个独立的组件:

    <!-- first component with data -->
    <div ng-controller="aCtrl">

    Title: <input ng-model="title"> <br>
    Text: <textarea ng-model="text"></textarea>
    </div>

    <hr>
    <!-- a second component wanting to show the data -->
    <div class="zippy" zippy-title="Details: {{title}}...">{{text}}</div>

我的问题是如何在 Angularjs 中很好地链接它们?

我尝试通过服务,注册数据更改,然后尝试通过注入指令或通过控制器将其与我的 DOM 绑定,但未成功。

(我想在另一个指令“窗口”中显示指令中包含的数据,但我不想用控制器包装我的所有代码只是为了绑定数据)

有没有办法做得很好?

4

2 回答 2

0

这是一种使用触发自定义事件的服务的解决方案$rootScope,然后在指令的控制器中侦听事件

app.factory('SharedData',function($rootScope){
    return{
        data:{text : 'World', title:'Foo bar'},
        upDate:function(prop,val){
           this.data[prop]=val;
           $rootScope.$emit('dataUpdate',prop)
        }
    }
});


app.controller('aCtrl', function ($scope,SharedData) {
    angular.forEach(SharedData.data,function(value,key){
        $scope[key] = value;
        $scope.$watch(key,function(){
            SharedData.upDate(key,$scope[key]);
        });
    });
});

app.directive('zippy',function($rootScope,SharedData){
    return{
        restrict:'C',
        replace:false,
        scope:{},
        controller:function($scope) {
            $rootScope.$on('dataUpdate',function(event,prop) {
                $scope[prop] = SharedData.data[prop];
            });
        }
    }
});

Plunker 演示

于 2013-03-24T20:55:10.740 回答
0

除了发出事件或将指令包装到父控制器中之外,还有另一种选择(顺便说一句,这些选项没有错)。另一种选择是拥有一个通用服务/工厂,您可以在其中注册任意指令控制器,然后在其他相关或非相关指令中使用这些注册的控制器。

下面有一个服务directiveCommunicator,你可以在其中获取、设置和取消设置指令控制器(如果需要,你可以使用工厂,这只是我使用服务的偏好)。然后,我们有另外 2 个指令,称为fooand bar,这些foo指令注册了要使用的控制器,而该控制器又被bar指令使用。请注意,foobar指令与父/子无关

// Service used to register/use any arbitrary controller
app.service('directiveCommunicator',
    function()
    {
        var _controllers = {};

        this.get =
            function(id)
            {
                if (!(id in _controllers)) {
                    return null;
                }

                return _controllers[id];
            };

        this.set =
            function(id, controller)
            {
                _controllers[id] = controller;
            };

        this.unset =
            function(id)
            {
                if (!(id in _controllers)) {
                    return;
                }

                delete _controllers[i];
            }
    }
);

app.directive('foo',
    [
        'directiveCommunicator',
        function(directiveCommunicator)
        {
            return {
                'restrict': 'A',
                'scope':
                    {
                        'colour': '='
                    },
                'controller':
                    function($scope)
                    {
                        // We register out controller with a unique ID so we can use it in other directives
                        directiveCommunicator.set('colourBox', this);

                        // We also unregister it once we get destroyed, otherwise we'll be leaking memory
                        $scope.$on('$destroy',
                            function()
                            {
                                directiveCommunicator.unset('colourBox');
                            }
                        );

                        this.changeColour =
                            function(colour)
                            {
                                $scope.$apply(
                                    function()
                                    {
                                        $scope._colour = colour;
                                    }
                                );
                            }
                    },
                'link':
                    function($scope, $element, $attr)
                    {
                        $scope._colour = $attr.colour;

                        $scope.$watch('_colour',
                            function()
                            {
                                $element.attr('class', $scope._colour);
                            }
                        );
                    }
            }
        }
    ]
);

app.directive('bar',
    [
        'directiveCommunicator',
        function(directiveCommunicator)
        {
            return {
                'restrict': 'A',
                'scope':
                    {
                        'colour': '='
                    },
                'link':
                    function($scope, $element, $attr)
                    {
                        $element.text($attr.colour);

                        $element.bind('click',
                            function()
                            {
                                // We get the registered controller and call the 'changeColour' method on it
                                var ctrl = directiveCommunicator.get('colourBox');

                                ctrl.changeColour($attr.colour);
                            }
                        );
                    }
            }
        }
    ]
);

我做了一个小Plunker演示来查看foobar操作。该foo指令只是一个小方形 div,您可以在其中更改关联控制器中的背景。bar是另一个不相关的指令,它将调用foo的控制器方法changeColour并根据提供的属性更改颜色。

尚未在生产中使用此设置,您还需要处理注销控制器,但应该可以。您还可以在方法中使用第三个参数directiveCommunicator.set作为控制器的范围,该方法将自动添加到 $destroy/unregister 设置中,因此不必再directiveCommunicator.unset调用

于 2015-08-20T11:16:36.150 回答