【问题标题】:AngularJS form and null/empty valuesAngularJS 表单和空/空值
【发布时间】:2015-06-25 20:34:13
【问题描述】:

我正在使用一个有点动态的 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 输入文本字段,当我开始输入值时,title 属性被添加到$scope。但是,当我删除输入文本字段中的值时,formData.title 属性仍然作为空字符串存在于$scope 中。我想这没关系,但我真的想在提交表单时清理空值或空值。如果这样做很容易,我想在客户端执行此操作,因此服务器端代码不必清理任何内容。
  • 使用动态 Subscribers 部分,我可以继续添加任意数量的行,但最终,我想过滤掉客户端上的所有空 subscriber 对象一边。

AngularJS 是否有任何选项可以在进一步处理之前检测和清除$scope 中的空值/空值,例如$http POST?

注意我为此示例设置了jsFiddle

【问题讨论】:

    标签: javascript html angularjs angularjs-scope


    【解决方案1】:

    只需使用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 和空值。
    【解决方案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。但是对于其他情况,我会牢记这种方法。谢谢。
    【解决方案3】:

    出于性能原因,我尽量避免使用观察者。话虽如此,这确实不是一个 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);
                });
    
            };
        });
    })();
    

    【讨论】:

    • 你是绝对正确的,这是一个 JavaScript 问题,在 AngularJS 上下文中。数据结构被简化以专注于手头的问题,但它很肤浅。在理想情况下,我想删除所有为空或为空的非对象属性,以及所有自身属性为空或为空的对象属性。我感觉到需要一些递归来满足要求。
    • 总的来说,对于任何分层数据结构,递归都是首选。
    【解决方案4】:

    在 formData 上添加了 Watcher,

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

    更新小提琴:https://jsfiddle.net/1ua6oj5e/6/

    对于您应该使用角度表单验证的所有动态字段,您应该看到:https://docs.angularjs.org/guide/forms

    【讨论】:

    • 考虑到我实际表单中静态和动态字段的数量,我担心这个$watch 函数实现会变得多大。性能可能是一个问题。我回应了另一个答案(来自@Swordfish0321),这在本质上是一个 JS 问题,而不是 AngularJS 问题。如果我可以遍历 $scope 对象并删除所有为空或 null 的非对象属性,以及所有自身属性为空或 null 的对象属性,这将满足我的要求。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-24
    • 1970-01-01
    • 2017-04-03
    • 2016-07-24
    • 1970-01-01
    • 2014-07-04
    相关资源
    最近更新 更多