动态添加必需属性到select元素

时间:2013-09-05 22:48:56

标签: asp.net-mvc angularjs data-annotations

我正在尝试连接适配器以启用ASP.Net MVC为客户端验证发出的标记在AngularJS中工作,并且我遇到了一个有趣的障碍。如果我通过指令编译函数动态添加required属性:

var myApp = angular.module('myApp', []).directive('valRequired', function() {
    return {
        compile: function (element) {

            element.attr('required', 'required');

            return function() { /* other custom logic here */ }
        }
    };
});

select元素不会根据需要进行验证。在动态添加属性(jsFiddle)时,它似乎只是一个问题。

澄清:我想按原样使用MVC的@Html.TextBoxFor(...)。对于基于DataAnnotations的模型,它发出的data-val-*属性包含有关运行哪些验证以及错误消息应该是什么的信息。我不是在寻找帮助连接错误消息,我只需要能够连接一个告诉inputselect等的指令来使用required验证

2 个答案:

答案 0 :(得分:1)

让我先说这个并不漂亮,但它确实有效。我尝试了不同的方法来使本机指令工作,但无济于事。看起来这个指令执行时已经太晚了。

这将查找您的data-val-required属性并向元素添加验证。

它会触发所有相同的内容,因此myForm.mySelect.$valid仍可以myForm.mySelect.$error.required

运行

http://jsfiddle.net/TheSharpieOne/knc8p/

var myApp = angular.module('myApp', []).directive('valRequired', function () {
    return {
        require: 'ngModel',
        restrict: 'A',
        link: function (scope, elm, attr, ctrl) {
            if (!ctrl || !attr.valRequired) return;
            attr.required = true; // force truthy in case we are on non input element

            var validator = function (value) {
                if (attr.required && (value == '' || value === false)) {
                    ctrl.$setValidity('required', false);
                    return;
                } else {
                    ctrl.$setValidity('required', true);
                    return value;
                }
            };

            ctrl.$formatters.push(validator);
            ctrl.$parsers.unshift(validator);

            attr.$observe('required', function () {
                validator(ctrl.$viewValue);
            });
        }
    };
});


function MyCtrl($scope, $http) {
    $scope.model = {
        property: ''
    };
}

答案 1 :(得分:0)

<强>更新 我想到了一个更好的方法来回答这个问题。旧答案低于新答案。


您可以获得对AngularJS所需指令的引用,并将其应用于您自己的指令。下面是一个代码示例:

var myApp = angular.module('myApp', []).directive('valRequired', function(requiredDirective) {
    var newDirective = {},
        angularDirective = requiredDirective[0]; //This assumes angular's required directive is the first one

    //Copy over all other properties of the angular directive
    angular.extend(newDirective, angularDirective);

    //Change the name of our directive back to valRequired
    newDirective.name = 'valRequired';

    //Provide our own logic in the linking function
    newDirective.link = function(scope, element, attr, ctrl){
        //Super call
        angularDirective.link.apply(this, arguments);
        if(attr.valRequired === 'required'){
            attr.$set('ngRequired', 'true');
        } else {
            attr.$set('ngRequired', 'false');
        }
    }

    return newDirective;
});

<input data-val-required="required" ng-model="foo" />

OLD ANSWER

使用jQuery或jQLite的attr()方法不会更改AngularJs' Attributes object。 Attributes对象是指令用作其逻辑值的值。

您还需要包含ng-required属性,尽管您不需要将任何角度表达式绑定到它。这个问题可以帮到你: Html5 data-* with asp.net mvc TextboxFor html attributes

原因是我们需要强制angular将指令应用于此节点。在模板的编译阶段之后更新属性不会通知angular将新指令应用于节点。

这应该有效:

var myApp = angular.module('myApp', []).directive('valRequired', function() {
    return {
        priority : 101, //The priority needs to run higher than 100 to get around angularjs' default priority for ngRequired
        link: function (scope, element, attr) {

            if(attr.valRequired === 'true'){
                attr.$set('ngRequired', 'true');
            } else {
                attr.$set('ngRequired', 'false');
            }
        }
    };
});

<input ng-required data-val-required="true" ng-model="foo" />