99

私はこのフォームを持っています: http://jsfiddle.net/dfJeN/

ご覧のとおり、入力の名前の値は静的に設定されています。

name="username"

、フォームの検証は正常に機能します(入力から何かを追加してすべてのテキストを削除すると、テキストが表示される必要があります)。

次に、名前の値を動的に設定しようとします: http://jsfiddle.net/jNWB8/

name="{input.name}"

次に、これを検証に適用します

login.{{input.name}}.$error.required

(このパターンは ng-repeat で使用されます) しかし、フォームの検証が壊れています。ブラウザで正しく解釈されます(要素を調べると、login.username.$error.required が表示されます)。

何か案が ?

編集:コンソールにスコープを記録した後、

{{input.name}}

式は補間されません。{{input.name}} 属性としての私のフォームですが、ユーザー名はありません。

更新: 1.3.0-rc.3 name="{{input.name}}" 以降、期待どおりに動作します。#1404をご覧ください

4

9 に答える 9

177

そのようにしようとしていることをすることはできません。

あなたがやろうとしていることは、要素をフォームに動的に追加する必要があると仮定すると、ng-repeat のようなもので、ネストされたng-formを使用して、それらの個々の項目の検証を許可する必要があります。

<form name="outerForm">
<div ng-repeat="item in items">
   <ng-form name="innerForm">
      <input type="text" name="foo" ng-model="item.foo" />
      <span ng-show="innerForm.foo.$error.required">required</span>
   </ng-form>
</div>
<input type="submit" ng-disabled="outerForm.$invalid" />
</form>

残念ながら、Angular の十分に文書化された機能ではありません。

于 2013-01-17T13:04:09.520 に答える
44

ネストされた ngForm を使用すると、HTML テンプレート内から特定の InputController にアクセスできます。ただし、別のコントローラーからアクセスしたい場合は役に立ちません。

例えば

<script>
  function OuterController($scope) {
    $scope.inputName = 'dynamicName';

    $scope.doStuff = function() {
      console.log($scope.formName.dynamicName); // undefined
      console.log($scope.formName.staticName); // InputController
    }
  }
</script>

<div controller='OuterController'>
  <form name='myForm'>
    <input name='{{ inputName }}' />
    <input name='staticName' />
  </form>
  <a ng-click='doStuff()'>Click</a>
</div>

このディレクティブを使用して問題を解決します。

angular.module('test').directive('dynamicName', function($compile, $parse) {
  return {
    restrict: 'A',
    terminal: true,
    priority: 100000,
    link: function(scope, elem) {
      var name = $parse(elem.attr('dynamic-name'))(scope);
      // $interpolate() will support things like 'skill'+skill.id where parse will not
      elem.removeAttr('dynamic-name');
      elem.attr('name', name);
      $compile(elem)(scope);
    }
  };
});

これで、'name' 属性の代わりに 'dynamic-name' 属性だけが必要な場合はいつでも動的な名前を使用できます。

例えば

<script>
  function OuterController($scope) {
    $scope.inputName = 'dynamicName';

    $scope.doStuff = function() {
      console.log($scope.formName.dynamicName); // InputController
      console.log($scope.formName.staticName); // InputController
    }
  }
</script>

<div controller='OuterController'>
  <form name='myForm'>
    <input dynamic-name='inputName' />
    <input name='staticName' />
  </form>
  <a ng-click='doStuff()'>Click</a>
</div>
于 2014-01-24T16:18:45.840 に答える
16

このGithubの議論によると、この問題は AngularJS 1.3 で修正されるはずです。

一方、@caitp@Thinkscapeによって作成された一時的な解決策は次のとおりです。

// Workaround for bug #1404
// https://github.com/angular/angular.js/issues/1404
// Source: http://plnkr.co/edit/hSMzWC?p=preview
app.config(['$provide', function($provide) {
    $provide.decorator('ngModelDirective', function($delegate) {
        var ngModel = $delegate[0], controller = ngModel.controller;
        ngModel.controller = ['$scope', '$element', '$attrs', '$injector', function(scope, element, attrs, $injector) {
            var $interpolate = $injector.get('$interpolate');
            attrs.$set('name', $interpolate(attrs.name || '')(scope));
            $injector.invoke(controller, this, {
                '$scope': scope,
                '$element': element,
                '$attrs': attrs
            });
        }];
        return $delegate;
    });
    $provide.decorator('formDirective', function($delegate) {
        var form = $delegate[0], controller = form.controller;
        form.controller = ['$scope', '$element', '$attrs', '$injector', function(scope, element, attrs, $injector) {
            var $interpolate = $injector.get('$interpolate');
            attrs.$set('name', $interpolate(attrs.name || attrs.ngForm || '')(scope));
            $injector.invoke(controller, this, {
                '$scope': scope,
                '$element': element,
                '$attrs': attrs
            });
        }];
        return $delegate;
    });
}]);

JSFiddleのデモ。

于 2014-04-14T15:57:37.710 に答える
14

@EnISeeKによる素敵なもの....しかし、私はそれをよりエレガントにし、他のディレクティブの邪魔にならないようにしました:

.directive("dynamicName",[function(){
    return {
        restrict:"A",
        require: ['ngModel', '^form'],
        link:function(scope,element,attrs,ctrls){
            ctrls[0].$name = scope.$eval(attrs.dynamicName) || attrs.dynamicName;
            ctrls[1].$addControl(ctrls[0]);
        }
    };
}])
于 2014-08-17T08:50:33.897 に答える
7

EnlSeek ソリューションのほんの少しの改善

angular.module('test').directive('dynamicName', ["$parse", function($parse) {
 return {
    restrict: 'A',
    priority: 10000, 
    controller : ["$scope", "$element", "$attrs", 
           function($scope, $element, $attrs){
         var name = $parse($attrs.dynamicName)($scope);
         delete($attrs['dynamicName']);
         $element.removeAttr('data-dynamic-name');
         $element.removeAttr('dynamic-name');
          $attrs.$set("name", name);
    }]

  };
}]);

これがプランカーの試用版です。ここに詳細な説明があります

于 2014-02-21T00:31:00.703 に答える
5

@caitp および @Thinkscape ソリューションを少し拡張して、次のように動的に作成されたネストされたng-formsを許可します。

<div ng-controller="ctrl">
    <ng-form name="form">
        <input type="text" ng-model="static" name="static"/>

        <div ng-repeat="df in dynamicForms">
            <ng-form name="form{{df.id}}">
                <input type="text" ng-model="df.sub" name="sub"/>
                <div>Dirty: <span ng-bind="form{{df.id}}.$dirty"></span></div>
            </ng-form>
        </div>

        <div><button ng-click="consoleLog()">Console Log</button></div>
        <div>Dirty: <span ng-bind="form.$dirty"></span></div>
    </ng-form>      
</div>

これがJSFiddleの私のデモです。

于 2014-07-04T19:03:43.713 に答える
4

Ben Leshのソリューションを使用しましたが、うまく機能します。しかし、私が直面した問題の 1 つは、 を使用して内部フォームを追加したときに、ディレクティブを使用している場合などng-formのすべてのフォーム状態form.$valid, form.$errorが未定義になることでした。ng-submit

たとえば、これがあった場合:

<form novalidate ng-submit="saveRecord()" name="outerForm">
    <!--parts of the outer form-->
    <ng-form name="inner-form">
      <input name="someInput">
    </ng-form>
    <button type="submit">Submit</button>
</form>

そして私のコントローラーで:

$scope.saveRecord = function() {
    outerForm.$valid // this is undefined
}

そのため、フォームを送信するために通常のクリック イベントを使用する方法に戻る必要がありました。この場合、フォーム オブジェクトを渡す必要があります。

<form novalidate name="outerForm">  <!--remove the ng-submit directive-->
    <!--parts of the outer form-->
    <ng-form name="inner-form">
      <input name="someInput">
    </ng-form>
    <button type="submit" ng-click="saveRecord(outerForm)">Submit</button>
</form>

そして、改訂されたコントローラーメソッド:

$scope.saveRecord = function(outerForm) {
    outerForm.$valid // this works
}

これがなぜなのかはよくわかりませんが、誰かの役に立てば幸いです。

于 2014-09-20T19:24:08.503 に答える