2

我已经搜索了我的方式,但无法弄清楚这一点。我制作了一个指令manyToOneSelect(自定义组件),它从服务器加载项目,将它们显示给用户并让用户选择一个。这很好用,但我不知道如果用户没有选择任何项目,如何防止表单被提交,即如何使表单无效。

以下几乎是指令:

angular.module('myApp.directives').
    directive('manyToOneSelect', function(entityService) {
        return {
            restrict:'E',
            templateUrl:'partials/control/n21select.html',
            scope:{
                entityName:'@',
                entityField:'@',
                bindVariable:'='
            },
            compile:function (tElement, tAttrs, transclude) {
                return function (scope, element, attrs) {
                    var inner = element.children("#n21select");
                    scope.entities = [];
                    scope.$watch('entityName', function ($new, $old) {
                        entityService.getList(scope.entityName, function (data) {
                            scope.entities = data;
                        }, []);
                    }, true);
                    scope.lookup = function(uuid) {
                        for(var i in scope.entities) {
                            if(scope.entities[i].uuid == uuid) {
                                return scope.entities[i];
                            }}}}}}});

这是相应的部分partials/control/n21select.html

<select ng-hide="disable" ng-options="entity.uuid as entity[entityField] for entity in entities" ng-model="bindVariable" required></select>
<span ng-show="disable">{{lookup(bindVariable)[entityField]}}</span>

这是我使用指令的方式:

<form ng-href="#/" ng-submit="save()">
<many-to-one-select entity-name="customer" entity-field="name"
    bind-variable="entity.customerUuid"></many-to-one-select>
...

我的问题似乎缺乏策略,而不是“没有完全让它发挥作用”,因此您在我上面发布的代码中看不到任何尝试。让这成为一个相当开放的问题:如何做到这一点?:) 非常感谢!

4

1 回答 1

1

有几种方法可以做到这一点。

考虑到您已经如何构建指令,一种方法是为表单本身添加一个范围属性。就像是:

scope: {
   form: '='
}

然后你会像这样传递你的表单元素:

<form name="myForm" ng-submit="whatever()">
   <my-directive-name form="myForm"></my-directive-name>
</form>

在您希望使表单无效的情况下,您只需对其调用 $setValidity :

link: function(scope, elem, attr) {
  if(somethingIsWrong) scope.form.$setValidity('reason', false);
}

这是一种方法,如果您可以重新设计指令,这是一种更好的方法:

另一种可能是首选的方法是让您的指令需要 ngModel。然后,您将对验证进行更精细的控制,因为 ngModel 的控制器将被传入,您可以使用它来使表单和表单上的单个字段无效:

   app.directive('bettererWay', function() {
      return {
         require: 'ngModel',
         restrict: 'E',
         link: function(scope, elem, attr, ngModel) {
             if(somethingIsBad()) ngModel.$setValidity('somethingIsBad', false);
         }
      };
   });

简而言之,这就是你的做法。希望这能让你朝着正确的方向开始。


编辑:无论有效性如何,提交的奇怪问题(在评论中)

这显然是 Angular 试图遵守 HTML 规范引起的问题。

从他们的代码中的评论大约。第 214 行

* To prevent double execution of the handler, use only one of ngSubmit or ngClick directives. This
 * is because of the following form submission rules coming from the html spec:
 *
 * - If a form has only one input field then hitting enter in this field triggers form submit
 * (`ngSubmit`)
 * - if a form has has 2+ input fields and no buttons or input[type=submit] then hitting enter
 * doesn't trigger submit
 * - if a form has one or more input fields and one or more buttons or input[type=submit] then
 * hitting enter in any of the input fields will trigger the click handler on the *first* button or
 * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)

因此,鉴于上述情况,将指令绑定到页面上隐藏类型的输入元素而不是它自己的元素可能是一个好主意。如果表单上有多个元素,则无效性会阻止提交就好了。

于 2013-02-25T04:48:08.177 回答