【问题标题】:AngularJS: textarea bind to JSON object shows "object-object"AngularJS:textarea绑定到JSON对象显示“对象对象”
【发布时间】:2013-07-27 10:51:59
【问题描述】:

我对 AngularJS 还很陌生。

我正在尝试将一个对象绑定到一个文本区域。

HTML:

<textarea rows="5" cols="10" ng-model="menuItem.preset"></textarea>

型号:

{
    "kind": "title",
    "label": "ADD_TITLE",
    "iconSrc": "textTitle.png",
    "experimentInclude": "",
    "experimentExclude": "three",
    "preset": {
        "compType": "richTitle",
        "styleId": "txtNew"
    }
}

结果:

如何显示 JSON 字符串化(然后再次将其另存为对象)?

【问题讨论】:

    标签: angularjs


    【解决方案1】:

    您需要一个自定义指令,将输入解析为对象,并将对象分别显示为字符串:

    类似:

    angular.module('yourApp').directive('jsonText', function() {
        return {
            restrict: 'A',
            require: 'ngModel',
            link: function(scope, element, attr, ngModel) {            
              function into(input) {
                return JSON.parse(input);
              }
              function out(data) {
                return JSON.stringify(data);
              }
              ngModel.$parsers.push(into);
              ngModel.$formatters.push(out);
    
            }
        };
    });
    
    <textarea json-text rows="5" cols="10" ng-model="menuItem.preset"></textarea>
    

    小提琴:http://jsfiddle.net/HzYQn/

    【讨论】:

    • @Jason 那个小提琴不是我的解决方案(也许你忘了保存它)但这里有一个:jsfiddle.net/HzYQn
    • 为了漂亮的打印使用return JSON.stringify(data, undefined, 2);
    • 对于 2 路数据绑定,我必须添加 scope.$watch(attr.ngModel, function(newValue) {element[0].value = out(newValue); }, true);
    • 不过,这会引发一个错误并显示在控制台中。
    • @efeder 它只发生在 jsfiddle 上还是在其 sanbox 之外?
    【解决方案2】:

    我刚刚研究了我认为最“正确”的方法,因为我的https://github.com/vorburger/MUI.js 需要它...所以here is a Plonker 使用我的解决方案。它基于 & 本质上是相关 Q How to do two-way filtering in angular.js? 的一个特殊情况(即应用程序)。另外的转折是模型更新也应该更改文本框.. 这就是 $watch / $setViewValue / $render 的作用。

    var app = angular.module('app', []);
    
    app.directive('jsonText', function() {
      return {
        restrict: 'A', // only activate on element attribute
        require: 'ngModel', // get a hold of NgModelController
        link: function(scope, element, attrs, ngModelCtrl) {
    
          var lastValid;
    
          // push() if faster than unshift(), and avail. in IE8 and earlier (unshift isn't)
          ngModelCtrl.$parsers.push(fromUser);
          ngModelCtrl.$formatters.push(toUser);
    
          // clear any invalid changes on blur
          element.bind('blur', function() {
            element.val(toUser(scope.$eval(attrs.ngModel)));
          });
    
          // $watch(attrs.ngModel) wouldn't work if this directive created a new scope;
          // see https://stackoverflow.com/questions/14693052/watch-ngmodel-from-inside-directive-using-isolate-scope how to do it then
          scope.$watch(attrs.ngModel, function(newValue, oldValue) {
            lastValid = lastValid || newValue;
    
            if (newValue != oldValue) {
              ngModelCtrl.$setViewValue(toUser(newValue));
    
              // TODO avoid this causing the focus of the input to be lost..
              ngModelCtrl.$render();
            }
          }, true); // MUST use objectEquality (true) here, for some reason..
    
          function fromUser(text) {
            // Beware: trim() is not available in old browsers
            if (!text || text.trim() === '') {
              return {};
            } else {
              try {
                lastValid = angular.fromJson(text);
                ngModelCtrl.$setValidity('invalidJson', true);
              } catch (e) {
                ngModelCtrl.$setValidity('invalidJson', false);
              }
              return lastValid;
            }
          }
    
          function toUser(object) {
            // better than JSON.stringify(), because it formats + filters $$hashKey etc.
            return angular.toJson(object, true);
          }
        }
      };
    });
    
    
    app.controller('Ctrl', ['$scope',
      function($scope) {
        $scope.model = {};
        $scope.model.data = {
          "kind": "title",
          "label": "ADD_TITLE",
          "iconSrc": "textTitle.png",
          "experimentInclude": "",
          "experimentExclude": "three",
          "preset": {
            "compType": "richTitle",
            "styleId": "txtNew"
          }
        };
      }
    ]);
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
    <div ng-app="app" class="container">
      <div ng-controller="Ctrl" class="row">
        <textarea json-text ng-model='model.data' rows="15"></textarea>
        <p>{{ model.data }}</p>
      </div>
    </div>

    【讨论】:

    • 谢谢,这是我更新后的指令:jsfiddle.net/tnunamak/cea3k
    • 如果您使用复制/粘贴有效的 json 来更新 textarea,这将不起作用。
    【解决方案3】:

    尝试使用 json 过滤器

    <textarea rows="5" cols="10" >
       {{ menuItem.preset | json }}
    </textarea>
    

    【讨论】:

    • 这不会将值绑定回范围
    【解决方案4】:

    这是我们带有有效性检查的 JSON 指令:

    app.directive('jsonInput', function () {
      'use strict';
      return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, elem, attr, ctrl) {
            ctrl.$parsers.unshift(function(input) {
              try {
                var obj = JSON.parse(input);
                ctrl.$setValidity('jsonInput', true);
                return obj;
              } catch (e) {
                ctrl.$setValidity('jsonInput', false);
                return null;
              }
            });
            ctrl.$formatters.unshift(function(data) {
              if (data == null) {
                ctrl.$setValidity('jsonInput', false);
                return "";
              }
              try {
                var str = JSON.stringify(data);
                ctrl.$setValidity('jsonInput', true);
                return str;
              } catch (e) {
              ctrl.$setValidity('codeme', false);
                  return "";
              }
            });
        }
      };
    
    });
    

    当用户输入无效的 JSON 时,模型为空。当模型包含循环引用或为空时,用户将看到一个空字符串(“”)并且输入无效。

    享受吧。

    【讨论】:

    【解决方案5】:

    你也可以在你的模型上定义 toString 方法:

      $scope.menuItem.preset.toString = function(){
            return JSON.stringify(this);
        }
    

    http://jsfiddle.net/ceJ4w/19/

    然后用watch同步回来

    http://jsfiddle.net/ceJ4w/20/

    但它看起来更像是肮脏的黑客而不是解决方案

    【讨论】:

    • 伙计,它会自动为你保存 :-)
    • 伙计,你是对的。我们可以使用 $watch 将其保留为对象(更新答案)
    【解决方案6】:

    使用 ng-change 事件是不是太乱了?

    <textarea ng-model="textmainboardJSON" ng-change="updateMainboard()"
    

    http://jsfiddle.net/gsw9Q/3/

    【讨论】:

      【解决方案7】:

      您可以分两步完成:

      【讨论】:

      【解决方案8】:

      试试这个。它在我的情况下有效

      &lt;textarea rows="5" cols="10" &gt;{{menuItem.preset}}&lt;/textarea&gt;

      【讨论】:

        【解决方案9】:

        我有简单的方法将数组数据绑定到 angularjs 中的文本区域。当有两个数组并且您需要并行显示它们时。此外,您也可以在 jsfiddle 上获得它。

        http://jsfiddle.net/Ahsan_Aftab/bc7hd258/18/

        <!DOCTYPE html>
            <html>
            <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js">
            <body>
        
            <div ng-app="myApp" ng-controller="myCtrl">
        
        
                    <textarea ng-model="TextAreacodeGroups" style="width:52%;height:200px;" columns="25" id="code_groups">
        
                {{CodeGroupsFun()}}
        
               </textarea>
        
            </div>
        
        <script>
        
            var app = angular.module('myApp', []);
        
            app.controller('myCtrl', function($scope) {
                var combined;
                var array1=['01','02','03','04'];
                var array2= ['Students','Teachers','Managers','Operators'];
        
             $scope.CodeGroupsFun = function () {
        
             $scope.TextAreacodeGroups =
              combined = array1.map(function (e, i) {
               return '\n' + array1[i] + '     -     ' + array2[i];
                            });
                        };
            });
        
        </script>    
            </body>
            </html>
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-08-30
          • 1970-01-01
          • 1970-01-01
          • 2013-03-18
          • 1970-01-01
          相关资源
          最近更新 更多