【问题标题】:Handling parent scope click in angular directive处理 Angular 指令中的父范围单击
【发布时间】:2014-09-23 18:58:59
【问题描述】:

我有一个上传文件的指令。在我看来,我将其称为“UploadRecords.html”。我在“UploadRecords.html”中有一个名为“Upload”的按钮。单击此按钮时,我想调用在我的指令中的链接函数内定义的“UploadAll”方法。有什么方法可以做到这一点。

基本上我想在单击根范围元素时调用指令函数。

注意:我在指令中使用了隔离作用域

angular.module('fileUpload', [])
.directive(
    "fileUpload",
    function () {
        return ({
            restrict: 'E',
            scope: {                
                onSuccess: '&',
                onError: '&',
            },
            templateUrl: 'Templates/FileUploadTemplate.html',
            link: function (scope, element, attrs) {
                scope.files = [];
                scope.addFile = function (element, documentType) {
                    if (element.files.length > 0) {
                        $.each(element.files, function (index, file) {
                            scope.files.push(file);
                        });
                    }
                    scope.$apply();
                }

                scope.uploadAll = function () {

                    //This is where I upload the files to the web api using a FormData post

                }
            }

        });
    }
    );


<file-upload on-success="onFileUloadAllSuccess()" on-error="onFileUloadAllError()"></file-upload>

<button type="button" class="btn btn-default">Upload All</button>

谢谢, 山姆。

【问题讨论】:

  • 我很困惑。点击是发生在父指令还是子指令上?响应是在另一个未点击的指令上?
  • 对不起,我对使用父母这个词感到困惑。我所说的 parent 是指调用指令的视图。
  • 你能提供一下你的结构的标记吗?很难理解发生了什么、点击了什么以及需要做什么。
  • 我已经更新了这个。好的。我也会添加一些代码。
  • 用你当前的实现,没有办法。阅读我的答案。告诉我您喜欢哪个选项,我可以对此进行扩展。

标签: angularjs angularjs-directive angularjs-scope


【解决方案1】:

按照您设置 HTML 的方式,您的按钮无法与指令通信,因为它们是完全独立的。您有几个选择:

  1. 移动 FileUploadTemplate.html 内的按钮,使其现在位于指令的范围内。如果这样做,您所要做的就是将ng-click="uploadAll()" 添加到属性中:

    全部上传

  2. 为您的按钮定义一个指令。然后使用$emit 在两个指令之间进行通信。

  3. 为您的按钮定义一个指令。定义一个“父”指令,它有两个孩子,按钮和您当前的模板。这样,两个子级都可以访问父级内部的范围,并且他们可以通过父级进行通信。

这里是您如何使用$emit。将您的按钮 html 定义为:

<button type="button" class="btn btn-default" ng-click="uploadAll()" button-upload>
    Upload All
</button>

现在为此添加一个指令:

app.directive('buttonUpload', ['$rootScope', 
    function($rootScope)
    {
        return {
            restrict: 'A',
            link: function(scope, element, attrs)
            {
                scope.uploadAll = function() {
                    $rootScope.$emit('UPLOAD_ALL');
                }
            }
        }
    }
]);

然后在您的fileUpload 指令中,您可以:

app.directive('fileUpload', ['$rootScope', 
    function($rootScope)
    {
        return {
            // Your restrict, templateUrl, scope
            link: function(scope, element, attrs)
            {
                // All your other code
                // remove scope.uploadAll


                // This will get called everytime $emit is broadcasted
                $rootScope.$on('UPLOAD_ALL', function(event) {
                    // Your upload code goes here
                });

            }
        }
    }
]);

这不是一个非常好的方法:您不应该真正使用$emit$broadcast。您应该考虑我的第三个选项,即拥有两个指令的父级。

【讨论】:

  • 我很想在我的模板中移动按钮,但由于它位于许多其他 html 内容的下方,因此无法移动。我的意思是,在
  • @sam113,通过其他“html”的东西,你的意思是还有其他的 HTML 标签,你没有包含在上面的标记中?我将很快发布一个示例,说明如何使用$emit
  • 是的,Kousha。我在这里将它们排除在外以避免混淆。另外,如果您能详细解释一下 $emit 是如何完成的,那就太好了。
  • 谢谢你的Kousha。我现在就试试。顺便说一句,我正在阅读一些文章并开始知道在根范围上广播不是一个好方法。任何关于它的cmets。 @DeadCalimero,如果您也可以对此发表评论,那就太好了。
  • @sam113,是的,rootScope 上的$broadcast 不好(这就是我在上面的代码中使用$emit 的原因)。不同之处在于 $emit 沿着分支向上传播,而 $broadcast 沿着分支向下传播。所以 $rootScope 上的 $emit 只会上升一级(因为 $rootScope 是顶级分支)。但是 $broadcast 会一直下降到您的最后一个范围。所以你的 $digest 周期会更长。
【解决方案2】:

在我看来,广播可以很好地解决您的问题

你可以这样做:

根控制器 -> 指令

根控制器

$scope.$broadcast('go');

指令

$scope.$on('go', function () { alert('event is clicked') });

JsFiddle

指令 -> 根控制器

根控制器:

$scope.$on('go', function () { alert('event is clicked') });

指令:

$scope.$emit('go');

** 这不一定是最优雅的解决方案,我们同意,但它会解决您的问题

【讨论】:

  • 在我看来,broadcastemit 不是他的最佳实践,因为它们并不是真正的“Angular 方式”。这个问题可以通过有一个父指令来解决,其他两个指令是它的一部分,并且它们可以通过它进行通信。甚至使用服务。
  • 另外,您需要一个$ 来进行广播和发射。一般来说,如果你确实想使用$broadcast,我建议在$rootScope 上使用$emit,因为它只会在一个分支上运行(除非你真的需要你的广播在多个分支上运行)。
  • 谢谢!我实际上犯了一个错误。是的,您建议的技术更优雅,我的技术是解决当前问题而不是设计问题。
  • 好的。那是很好的信息。因此,与其将父指令和 2 个指令作为其中的一部分,不如将按钮指令创建为子指令,将文件上传作为父指令,然后使用 $emit
  • @sam113,是的。阅读我对我的帖子的评论,了解 $emit 和 $broadcast 的区别。它们不可互换。示波器的定位对于它们的工作非常重要。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多