angularjs - 指令中的动态回调

hea*_*low 4 javascript jquery angularjs

我正在尝试用angularjs创建一个指令,但我发现了一个问题.

这是指令的js代码

angular.module('xxxFileUploader', [])
    .directive('xxxFileUploader', function() {
        return {
            restrict: 'E',
            templateUrl: 'fileUploader.html',
            scope: {
                onChange: '='
            },
            link: function(scope, element, attrs) {
                element.find('input[type="file"]').change(function() {
                    var input = this;
                    if (input.files && input.files[0]) {
                        scope.file = input.files[0];
                        scope.onChange(input.files[0]);
                });
            }
        };
    });
Run Code Online (Sandbox Code Playgroud)

指令模板

<span style="position:relative;">
    <a class='btn btn-primary' href='javascript:;'>
        Choose File...
    </a>
    <input type="file" 
           name="{{field.name}}"
           style='position:absolute;z-index:2;top:0;left:0;filter: alpha(opacity=0);opacity:0;background-color:transparent;color:transparent;' 
           />
    &nbsp;
    <span class='label label-info'>{{file.name}}</span>
</span>
Run Code Online (Sandbox Code Playgroud)

我使用该指令的一段html文件

<xxx-file-uploader on-change="loadFile(field.name)" ></xxx-file-uploader>
Run Code Online (Sandbox Code Playgroud)

和我的控制器的相关部分

$scope.loadFile = function(fieldName) {
    return function(file) {
        // do things with both fieldName and file...
    };
};
Run Code Online (Sandbox Code Playgroud)

此代码应该只定制类型文件的输入外观,并在上载文件时执行回调.

我的问题来自于此刻我需要使用为每个fileUploader动态构建的更改回调.正如您所看到的,回调是使用在链接时已知的参数fieldName和在"执行时"已知的参数文件构建的.

使用此代码,我得到了AngularJS"Error:10 $ digest()迭代次数.中止!"因为(我认为)一次又一次地生成函数,并且摘要不匹配.

穷人解决方案是将fieldName作为另一个范围变量传递.另一个可能是将函数作为字符串(@)传递并在需要时构建回调.

关于如何在不改变界面的情况下使该指令工作的任何建议?我对angularjs指令很新(这是我的第一个!)所以如果你看到代码中有任何错误,请指出它.

谢谢.

首先编辑:

正如我所建议的那样,我试图改变指令的范围

scope: {
    onChange: '='
},
Run Code Online (Sandbox Code Playgroud)

scope: {
    onChange: '&'
},
Run Code Online (Sandbox Code Playgroud)

我改变了回拨电话

scope.onChange(input.files[0]);
Run Code Online (Sandbox Code Playgroud)

scope.onChange()(input.files[0]);
Run Code Online (Sandbox Code Playgroud)

现在它有效,但我对结果并不完全满意.

看起来需要调用onChange函数来获取我的"真实"回调.在这种情况下有没有办法隐式执行它?

我的意思是如果我写的话

<xxx-file-uploader on-change="loadFile(field.name)" ></xxx-file-uploader>
Run Code Online (Sandbox Code Playgroud)

它应该理解执行该功能

如果相反我写

<xxx-file-uploader on-change="doSomething" ></xxx-file-uploader>
Run Code Online (Sandbox Code Playgroud)

它应该认识到doSomething是我希望它执行的"真正的"回调(使用file参数).

Nik*_*los 6

您使用的方式onChange: '='和功能不正确.以下解决方案可以稍微改变指令的接口,但我认为重命名onChange可以onChangeFactory更好地反映其预期用途.onChange但是,如果您不介意小的不一致,则可以保留该名称.


loadFile()自己传递给:

<xxx-file-uploader on-change-factory="loadFile(fname)" ></xxx-file-uploader>
Run Code Online (Sandbox Code Playgroud)

修改指令以使用函数绑定:

scope: {
    onChangeFactory: "&"
}
Run Code Online (Sandbox Code Playgroud)

Call the factory and get the actual callback in link():

        link: function(scope, element, attrs) {
            // HOW ARE YOU GETTING FIELDNAME???
            var onChange = scope.onChangeFactory({fname: FIELDNAME});
            element.find('input[type="file"]').change(function() {
                var input = this;
                if (input.files && input.files[0]) {
                    scope.file = input.files[0];
                    onChange(input.files[0]); // <--- NOTE CHANGE HERE TOO
                }
            });
        }
Run Code Online (Sandbox Code Playgroud)

Do pay attention on the way of calling onChangeFactory() from inside the directive! I guess there will be some gaps (e.g. the filename), but I believe this is a good starting point.