【问题标题】:AngularJS ng-model not working on dynamically created input fieldsAngularJS ng-model 不适用于动态创建的输入字段
【发布时间】:2014-09-03 00:52:52
【问题描述】:

我已经为表单字段创建了一个动态 templateUrl,并且我正在尝试将 ng-model 附加到 ng-repeat 中。父指令和表单字段指令都可以工作并生成,但是当我使用 ng-model 时它似乎不起作用,预输出永远不会改变?在这个用例中应用 ng-model 有技巧吗?如果我只是对表单输入使用硬编码,它就可以工作。我一直在关注 AngularJS 文档中的example

表单域周围的标记:

<form role="form" ng-controller="FormController as formCtrl" novalidate>

    <div ng-repeat="field in panel.form_fields">

        <form-field field="field"></form-field>

    </div>

    <fieldset class="form-group clearfix">
        <button type="submit" class="btn btn-primary pull-right">Save Progress</button>
    </fieldset>

    <pre>form   = {{models | json}}</pre>
    <pre>master = {{master | json}}</pre>
</form>

表单域指令:

angular.module('formField.directives', [])

.directive('formField', [ '$http', '$compile', function( $http, $compile ) {

    var getTemplateUrl = function( field ) {

        var type = field.field_type;
        var templateUrl = '';

        switch( type ) {
            case 'textfield':
                templateUrl = 'components/form-field/fields/textfield.html';
                break;
            case 'email':
                templateUrl = 'components/form-field/fields/email.html';
                break;
            case 'currency':
                templateUrl = 'components/form-field/fields/currency.html';
                break;
            case 'date':
                templateUrl = 'components/form-field/fields/date.html';
                break;
            case 'dropdown':
                templateUrl = 'components/form-field/fields/dropdown.html';
                break;
            case 'textarea':
                templateUrl = 'components/form-field/fields/textarea.html';
                break;
            case 'hidden':
                templateUrl = 'components/form-field/fields/hidden.html';
                break;
            case 'password':
                templateUrl = 'components/form-field/fields/password.html';
                break;
            case 'checkbox':
                templateUrl = 'components/form-field/fields/checkbox.html';
                break;
            case 'radio':
                templateUrl = 'components/form-field/fields/radio.html';
                break;
        }

        return templateUrl;
    }

    var linker = function( scope, element ) {

        var templateUrl = getTemplateUrl( scope.field );
        $http.get( templateUrl ).success(function( data ) {
            element.html(data);
            $compile(element.contents())(scope);
        });
    }

    return {
        restrict: 'E',
        replace: true,
        scope: {
            field: '='
        },
        link: linker
    }
}]);

使用的表单域模板:

<fieldset class="form-group">

    <label for="{{field.field_name}}">{{field.field_label}}</label>
    <input type="text" 
           class="form-control"
           id="{{field.field_id}}"
           name="{{field.field_name}}"
           value="{{field.field_value}}"
           placeholder="{{field.field_prompt}}"
           ng-required="field.field_required"
           ng-disabled="field.field_disabled"
           ng-model="models[field.field_name]"> // model.test also doesn't work, and need to be able to reference the model dynamically

</fieldset>

AngularJS 文档中示例中使用的控制器:

.controller('FormController', ['$scope', function( $scope ) {

    $scope.master = {};
    $scope.models = {};

    $scope.update = function( models ) {
        console.info('Update');
        $scope.master = angular.copy( models );
    };

    $scope.submit = function() {
        console.info('Form Submitted');
    };

    $scope.cancel = function() {
        console.info('Form Cancelled');
    };

    $scope.clear = function() {
        console.info('Form Clear');
        $scope.models = {};            
    }

    $scope.reset = function() {
        console.info('Form Reset');
        $scope.models = angular.copy( $scope.master );
    };

    $scope.reset();

}]);

【问题讨论】:

  • 你能准备一个演示吗?你的指令是什么样子的
  • 能否添加“form-field”指令的声明?
  • 您正在使用隔离范围,它不知道上下文之外的models 是什么。立即查看plnkr.co/edit/HOxGGw?p=preview

标签: javascript angularjs angularjs-directive angularjs-scope angularjs-ng-model


【解决方案1】:

您的指令适用于隔离范围 (.$new(true)),这意味着您在指令内所做的更改将无法直接在外部范围内使用(除非您使用 2 路绑定等)。所以ng-model="models[field.field_name]" 指令中的models 不是父控制器范围内的models 对象。因此,您可以通过传递模型以及使用 2-way binding 来修复它。

消费时:-

 <form-field field="field" model="models[field.field_name]"></form-field>

在你的指令模板中:-

   <input type="text" 
       class="form-control"
       id="{{field.field_id}}"
       name="{{field.field_name}}"
       value="{{field.field_value}}"
       placeholder="{{field.field_prompt}}"
       ng-required="field.field_required"
       ng-disabled="field.field_disabled"
       ng-model="model">  <!-- Here just set the model on the scope 2-way B -->

并在您的指令隔离范围声明中执行:-

  scope:{field:'=', model:'='},
  //or set a reference to the object on scope holding models in the field property itself.

Plnkr

请注意,在您的指令模板中,当您指定 value="{{field.field_value}}"ng-model 时,它根本不会设置默认值。您需要在 ngModel 本身中默认它。

【讨论】:

  • 很好的答案! @mtpultz 你可能想看看这个:docs.angularjs.org/guide/scope。此外,您用于“fieldset”标签的语义有点不正确。 'fieldset' 标签应该用于对字段进行分组,所以不要为每个字段创建一个 'fieldset' 标签,也许你应该用它来保存它们
  • @Josep 这是一个很好的观点。我自己没有注意到模板中的字段集.. :)
  • 感谢@PSL,这是一个很好的解释,也感谢您指出有关默认值的问题。干杯:)
  • 嗨@Josep,我肯定会更改字段集以将字段作为一个组保存,感谢您指出这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多