0

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

<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父级的属性而不是特定值。我认为 using{ssn: "="}会起作用,但是我必须更新控制器的特定属性,而不是将其设置为指令属性,这会使指令不灵活。显然$parent也不推荐使用。

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

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

4

3 回答 3

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因为 Angular 中有一些错误处理特性:

var value = this.value;
scope.$apply(function () {
    scope.maskValue = value;
});
于 2013-09-26T14:40:37.813 回答
1

我知道你已经得到了问题的答案,但我认为值得一提的是,由于你似乎正在做一些验证,你可以使用 Angular 的内置功能来做到这一点,并且仍然能够使用ng-model. 这是一个例子:

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();
      });
    }
  };
});

该指令使用NgModelControllerng-model控制视图的更新方式。在这个人为的示例中,当元素失去焦点并且验证函数返回 false 时,它​​将简单地呈现 ########。但是当控件再次获得焦点时,它将呈现其真实值,以便用户可以更改它。请注意,绑定到控件的范围的属性保持不变,而其视图会根据元素状态(有效或无效)相应地更改。您可以在此处查看一个工作示例。

于 2013-09-26T15:46:13.653 回答
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>
于 2013-09-26T14:38:35.130 回答