在指令中使用controller属性/方法

时间:2013-09-26 13:44:57

标签: javascript angularjs angularjs-directive

我有各种输入(包括稍后将解释的指令),例如:

<input mask-value="ssn" validate="checkSsn"/>
<input mask-value="pin" validate="checkPin"/>

这些属性位于控制器中:

app.controller("Ctrl", ['$scope', function ($scope) {
    $scope.ssn = "";
    $scope.pin = "";

    $scope.checkSsn = function () { /* validate $scope.ssn */ };
    $scope.checkPin = function () { /* validate $scope.pin */ };
}]);

最后,maskValue指令:

app.directive("maskValue", function () {
    return function (scope, element, attrs) {
        /* does some focus/blur magic and string replacement */
        scope[attrs.maskValue] = this.value;
        scope[attrs.validate]();
    };
});

这有效,但似乎是对我滥用Angular。相反,使用隔离范围更有意义,如:

    scope: {validate: "&"}

然后我可以使用scope.validate()代替scope[attrs.validate]()然而,隔离范围我无法更新控制器中的相应值。使用{maskValue: "="}不起作用,因为这会尝试更新父项的maskValue属性而不是特定值。我认为使用{ssn: "="}会起作用,但是我必须更新控制器的特定属性,而不是将其设置为指令属性,这将使指令不灵活。显然也不建议使用$parent

如何在隔离范围指令内动态访问控制器的属性?

编辑:我无法在输入中使用ng-model=ssn等,因为在mask-value中的焦点/模糊事件期间,输入的实际值会发生变化。例如,它可能变为*****####,但我需要在某处存储实际值#########,并且控制器似乎是合适的位置,因为控制器稍后会出于其他原因使用它。

3 个答案:

答案 0 :(得分:2)

<div ng-app=foo>
  <div ng-controller=Ctrl>
  {{ssn}}
  <input mask-value="ssn" validate="checkSsn()">

app = angular.module("foo", []);

app.controller("Ctrl", ['$scope', function ($scope) {
    $scope.ssn = "";
    $scope.checkSsn = function () { console.log($scope.ssn); };
}]);

app.directive("maskValue", function () {
    return {
        scope: {
            validate: "&",
            maskValue: "="
        },
        link: function (scope, element, attrs) {
            element.bind("change", function () {
                scope.maskValue = this.value;
                scope.$apply();
                scope.validate();
            });
        },
    };
});

http://jsfiddle.net/bfDqy/

编辑:

他们说最好将要评估的表达式作为参数传递给$apply,因为在Anguular中有一些错误处理特性:

var value = this.value;
scope.$apply(function () {
    scope.maskValue = value;
});

答案 1 :(得分:1)

我知道你已经得到了问题的答案,但我认为值得一提的是,既然你似乎正在做一些验证,你可以使用Angular的内置功能来做到这一点,但仍然可以使用{ {1}}。这是一个例子:

ng-model

此指令使用NgModelController以便与app.directive("maskValue", function ($parse) { return { restrict: 'A', require: 'ngModel', link: function (scope, element, attrs, ngModel) { if (!ngModel) return; var validator = $parse(attrs.validator)(scope); ngModel.$render = function() { var hasFocus = document.activeElement == element[0]; if (ngModel.$valid || hasFocus) element.val(ngModel.$modelValue) else element.val('#######'); }; element.bind('blur', function() { ngModel.$setValidity('maskValue', validator(this.value)) ngModel.$render(); }); element.bind('focus', function() { ngModel.$render(); }); } }; }); 一起控制视图的更新方式。在这个人为的例子中,当元素失去焦点并且验证函数返回false时,它将简单地呈现########。但是当控件再次聚焦时,它将呈现其真正的价值,以便用户可以更改它。请注意,绑定到控件的作用域的属性保持不变,而其视图相应地更改为元素状态(有效或无效)。您可以看到一个有效的示例here

答案 2 :(得分:0)

我很抱歉,为什么不这样做呢:

app = angular.module("foo", []);

app.controller("Ctrl", ['$scope', function ($scope) {
    $scope.ssn = "";
    $scope.validate = function () { console.log($scope.ssn); };
}]);

app.directive("maskValue", function () {
    return {
        link: function (scope, element, attrs) {
            element.bind("change", function () {  
                scope.validate();
            });
        },
    };
});

和HTML一样:

<div ng-app=foo>
    <div ng-controller=Ctrl>
        <input ng-model="ssn" mask-value />
    </div>
</div>