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

これを行うにはいくつかの方法があります。

ディレクティブをすでに作成した方法を考慮すると、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);
}

これはそれを行う1つの方法です。ディレクティブを再設計できる場合は、次のより良い方法があります。

もう1つの方法は、おそらく推奨されますが、ディレクティブに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 に答える