AngularJS表单和空/空值

8

我正在使用一个比较动态的AngularJS表单,也就是说,我能够添加输入字段等等。因此,我的做法是从一个空对象$scope.formData开始,封装所有绑定到静态和动态HTML表单元素的属性。

AngularJS代码如下:

(function() {
    var formApp = angular.module("formApp", []);
    formApp.controller("FormCtrl", function ($scope, $timeout) {
        $scope.formData = {};
        $scope.formData.subscribers = [
            { name: null, email: null }
        ];
        $scope.addSubscriber = function() {
            $scope.formData.subscribers.push({ name: null, email: null });
        };
    });
})();

AngularJS表单的HTML代码:

<body data-ng-app="formApp">
    <div data-ng-controller="FormCtrl">
        <p>
            Name of Topic: <input type="text" data-ng-model="formData.title" placeholder="enter a title" />
        </p>
        Subscribers:
        <button data-ng-click="addSubscriber()">Add subscriber</button>
        <table>
            <tr>
                <th>Name</th>
                <th>Email</th>
            </tr>
            <tr data-ng-repeat="subscriber in formData.subscribers">
                <td><input type="text" data-ng-model="subscriber.name" placeholder="enter name" /></td>
                <td><input type="text" data-ng-model="subscriber.email" placeholder="enter email" /></td>
            </tr>
        </table>
        <hr style="margin:1em 0;" />
        <p>
            <em>Debug info</em>: {{ formData }}
        </p>
    </div>
</body>

请注意最后的调试信息部分,它显示了$scope.formData对象及其内容。我对表单的实现方式有几个问题。
  • 当页面首次加载时,$scope中没有formData.title属性,但由于它绑定到标题输入文本字段,当我开始输入值时,title属性将被添加到$scope。但是,当我删除输入文本字段中的值时,formData.title属性仍然存在于$scope中,作为空字符串。我认为这可以接受,但我真的想在提交表单时清理空或null值。如果方便的话,我希望在客户端上处理它,这样服务器端代码就不必清理任何内容。
  • 通过动态的订阅者部分,我可以添加任意多行,但最终,我希望在客户端上过滤掉所有空的subscriber对象。

AngularJS是否有检测和清理$scope中的null/空值的选项,以便进一步处理,例如$http POST?

注意:我已经为这个例子设置了一个jsFiddle

4个回答

4

只需使用ngModelController$ parsers并覆写默认的HTML输入元素。

通过此实现,您可以始终控制模型值。 所以在您的情况下,当视图值为空字符串时,您可以将模型设置为null。

var inputDefinition = function () {
return {
  restrict: 'E',
  require: '?ngModel',
  link: function (scope, element, attr, ngModel) {
    if (ngModel) {
      var convertToModel = function (value) {
        return value === '' ? null : value;
      };
      ngModel.$parsers.push(convertToModel);
    }
  }
};
/**
* Overwrite default input element.
*/
formApp.directive('input', inputDefinition);

这是更新后的JSFiddle代码: https://jsfiddle.net/9sjra07q/

这个有趣的指令似乎将具有空值的属性转换为null,而不是删除/过滤掉null和空值。 - Web User

2
为了提高性能,我尽量避免使用监视器。话虽如此,这并不是一个Angular问题,而是一个JavaScript问题。由于您完全控制何时将数据传递给服务,因此我建议先清理数据。由于您的数据结构非常浅,这很简单。https://jsfiddle.net/1ua6oj5e/9/
(function() {
    var formApp = angular.module("formApp", []);
    formApp.controller("FormCtrl", function ($scope, $timeout) {

        // Remove junkiness
        var _remove = function remove(item) {
            if ($scope.formData.title === undefined || $scope.formData.title === '') {
                delete $scope.formData.title;
            }
        };


        $scope.formData = {};
        $scope.formData.subscribers = [
            { name: null, email: null }
        ];
        $scope.addSubscriber = function() {
            $scope.formData.subscribers.push({ name: null, email: null });
        };

        // Submit to test functionality
        $scope.submit = function() {

            // Remove title if empty
            _remove($scope.formData.title);

            /* Remove name and email if empty.
             * If your list of fields starts to get large you could always
             * just nest another iterator to clean things up.                 
             */

            angular.forEach($scope.formData.subscribers, function(sub) {
                _remove(sub.name);
                _remove(sub.email);
            });

        };
    });
})();

1
你说得完全正确,这是一个关于JavaScript的问题,在AngularJS的上下文中。数据结构被简化以便聚焦于手头的问题,但它是浅层次的。在理想的情况下,我希望删除所有非对象属性,这些属性为空或null,并且删除所有自身属性为空或null的对象属性。我感觉需要一些递归来满足要求。 - Web User
总的来说,对于任何层次结构的数据结构,递归是首选。 - Scott Sword

2
function replacer(key, value) {
    if (value == "" || value == null) {
       return undefined;
    }
  return value;
}

var foo = {foundation: "", model: {year: 2015, price:null}, week: 45, transport: "car", month: 7};
foo = JSON.stringify(foo, replacer);
foo =JSON.parse(foo);
console.log(foo);

这很不错。唯一的缺点是,在 model: {year:null, price:null} 的情况下,最终结果将包括一个空对象 model:{},而不是完全从 foo 中删除 model。但我会记住这种方法,用于其他场景。谢谢。 - Web User

1

在formData上添加了Watcher

$scope.$watch('formData',function(n,o){
      if(typeof $scope.formData.title !== 'undefined' && $scope.formData.title === "" ){
        delete $scope.formData.title;
      }
},true);

更新的 jsfiddle: https://jsfiddle.net/1ua6oj5e/6/

对于所有动态字段,您应该使用 Angular 表单验证,您可以参考这里:https://docs.angularjs.org/guide/forms


考虑到我的实际表单中静态和动态字段的数量,我担心这个$watch函数的实现会变得非常庞大。而且性能可能会成为一个问题。我回应了另一个答案(来自@Swordfish0321),这在本质上是一个JS问题,而不是AngularJS问题。如果我可以遍历$scope对象并删除所有既为空又为null的非对象属性以及所有属性都为空或为null的对象属性,那么这将满足我的要求。 - Web User

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接