父级隔离范围阻止与子级的通信

时间:2014-09-26 20:41:23

标签: angularjs

我有以下标记:

<div class="row" loader="loader" address-book>
    <!-- Loading complete - this should show result -->
    <div loader-success></div>

    <!-- Loading failed - this should show some error -->
    <div loader-failure>Failure</div>
</div>

此处,address-book是主应用,loader仅用于在加载页面时显示动画。地址簿的内容将进入loader-success,失败消息(即,如果没有找到内容)将进入loader-failure

所以我的想法是使用以下指令:

app.directive('loader', function($compile, $timeout)
{
    return {
        restrict: 'AE',
        scope: {
            loader: '&'
        },
        transclude: true,
        template: 
            '<div class="row" ng-if="loading">' + 
            '   <div class="small-15 columns text-center">' +
            '       <i class="fa fa-spin fa-circle-o-notch"></i>' +
            '   </div>' +
            '</div>' + 
            '<div ng-transclude></div>',
        link: function(scope, element, attrs)
        {
            scope.loading = true;
            scope.failure = false;
            scope.success = false;

            scope.$watch('loader', function(fn) {
                if (_.isFunction(fn)) {
                    scope.loader()
                    .then(function(){
                        scope.success = true;
                        scope.loading = false;
                        scope.$safeApply();
                    })
                    .catch(function() {
                        scope.failure = true;
                        scope.loading = false;
                        scope.$safeApply();
                    });
                }
            });
        }
    };
}); 

其中scope.loader是来自$q的{​​{1}}集的承诺。在地址簿尝试获取内容后,承诺得到解决/拒绝。

对于我有的成功/失败块:

address-book

但是,由于app.directive('loaderFailure', function() { return { restrict: 'AE', link: function(scope, element, attrs) { element.hide(); scope.$watch('failure', function(value) { if (_.isTrue(value)) { element.show(); } }); } }; }); app.directive('loaderSuccess', function() { return { restrict: 'AE', link: function(scope, element, attrs) { element.hide(); scope.$watch('success', function(value) { if (_.isTrue(value)) { element.show(); } }); } }; }); 上的隔离范围,两个孩子loaderloader-success的范围无法再读取父亲的范围。我无法在loader-failure上使用$compile,因为这会将范围从地址簿的应用中删除。

我该怎么办?

2 个答案:

答案 0 :(得分:2)

您可以使用活动。如果您想将儿童的某些日期发送给父母使用$scope.$emit

从父母与子女$scope.$broadcast - 可能会产生负面影响

当您想要在松散耦合的组件之间进行通信时,使用事件是一种很好的方法。

查看有关活动的更多信息:

https://docs.angularjs.org/api/ng/type/ $ rootScope.Scope#$发射

答案 1 :(得分:0)

所以我最终使用了$emit。但是,由于我的loader指令可以在同一页面上的多个不同组件上使用,因此能够区分这两者是很重要的。此外,loader被添加到元素上,并在其上运行另一个指令。

要解决这些问题,我就这样做了:

                   失败

然后将channel用作唯一标识符。它甚至可以是另一个指令范围的$id,以确保它是完全唯一的。现在,指令如下:

app.directive('loader', function($compile, $rootScope)
{
    return {
        restrict: 'AE',
        scope: {
            loader: '&',
            channel : '@loaderChannel'
        },
        transclude: true,
        template: 
            '<div class="row" ng-if="loading">' + 
            '   <div class="small-15 columns text-center loader">' +
            '       <i class="fa fa-spin fa-circle-o-notch"></i>' +
            '   </div>' +
            '</div>' + 
            '<div ng-transclude></div>',
        link: function(scope, element, attrs)
        {
            scope.loading = true;

            scope.$watch('loader', function(fn) {
                if (_.isFunction(fn)) {
                    scope.loader()
                    .then(function(){
                        scope.loading = false;
                        $rootScope.$emit('LOADER_SUCCESS', scope.channel);
                        scope.$safeApply();
                    })
                    .catch(function() {
                        scope.loading = false;
                        $rootScope.$emit('LOADER_FAILURE', scope.channel);
                        scope.$safeApply();
                    });
                }
            });

        }
    };
});

app.directive('loaderFailure', function($rootScope)
{
    return {
        restrict: 'AE',
        link: function(scope, element, attrs)
        {
            element.hide();
            $rootScope.$on('LOADER_FAILURE', function(event, channel) {
                if (channel == attrs.loaderFailure) element.show();
            });
        }
    };
});

app.directive('loaderSuccess', function($rootScope)
{
    return {
        restrict: 'AE',
        link: function(scope, element, attrs)
        {
            element.hide();
            $rootScope.$on('LOADER_SUCCESS', function(event, channel) {
                if (channel == attrs.loaderSuccess) element.show();
            });
        }
    };
});

基本上,我$emit通道成功或失败。而loader-successloader-failure会收听这些广播,与其频道匹配并相应地表现。

然后,在每个组件中,我只需定义scope.loader = $q.defer()并在需要时解析/拒绝它。