从HTML5 localstorage json读取,无法在highcharts-ng中识别

时间:2014-06-28 14:36:46

标签: javascript html5 angularjs highcharts local-storage

我有一个奇怪的问题,我可以把它放在分数上,这样你就可以更好地理解。

  • 请在浏览器中打开此小提琴Demo 1,如您所见,我正在使用highchart-ng https://github.com/pablojim/highcharts-ng angular指令来创建图表。这很好。

  • 现在,请在新标签Demo 2中打开此链接,我刚刚使用了HTML5 localStorage。

    我正在做的是

  • 首先检查localStorage'图表中的图表数据,如果存在则使用它,否则

  • 从硬编码的json变量$ scope.highchartsNG中绘制图表。

我的意思是:

if(JSON.parse(localStorage.getItem('chart'))){
        console.log('FROM CACHE');
        $scope.highchartsNG = JSON.parse(localStorage.getItem('chart'));
}else{
  $scope.highchartsNG = {
            options: {
             ...
             ...
}

为了清除localStorage,我提供了按钮

<input type='button' onclick='javascript:localStorage.clear();' value='clear localStorage'  />

点击后,我正在使用localStorage.clear();

清除localStorage

问题是当我从localstorage读取时,图表x轴和y轴标签的变化不同,但是如何?

请考虑以下步骤:

  1. 当您点击按钮&#39;清除localStorage&#39;,然后运行小提琴,您将获得正常的图表。 (这是正确的)好的,之后我将数据存储在

    localStorage.setItem(&#39; chart&#39;,JSON.stringify($ scope.highchartsNG));

  2. 现在
      2.再次当你运行小提琴时,它进入if块并从localstorage获取数据,然后图表x轴改变。为什么

2 个答案:

答案 0 :(得分:0)

您看到不同结果的原因是JSON无法序列化功能(除其他外) 因此,当您将对象存储在localStorage中时,所有引用函数的属性(例如格式化程序)都会丢失。


<强>更新

为了它的乐趣,我实现了一个简单的&#34;序列化器&#34;能够字符串化/解析简单的匿名函数(就像你的配置中使用的那样)。


您可以看到它的实际效果 here (并找到此 updated fiddle 中的代码)。


这不是一个通用的,一刀切的,生产就绪的解决方案,但它似乎适用于您的具体情况。
以下是其工作原理的快速概述:

  1. 当&#34;字符串化&#34;时,它首先遍历对象并将每个函数转换为字符串(使用其toString()方法)。 (当天无用的提示:当没有使用内联数组表示法时,这是Angular用于识别注入的依赖项的内容。)
    然后它使用JSON.stringify来实际对字符串进行字符串化。

  2. 在解析时,它首先像往常一样解析字符串(使用JSON.parse),然后遍历生成的对象,检测与RegExp匹配的字符串属性(旨在匹配匿名函数),最后转换那些字符串化函数到实际函数。


  3. 以下是代码:

    .factory('JSONwithFn', function () {
        var fnRE = /^[\s\r\n]*function[\s\r\n]*\([^\)]*\)[\s\r\n]*\{[\s\S]*\}[\s\r\n]*$/i;
    
        function strToFn(str) {
            var args = str.substring(str.indexOf('(') + 1, str.indexOf(')')).
            split(',').
            map(function (arg) {
                return arg.trim();
            });
            var fnBody = str.substring(str.indexOf('{') + 1, str.lastIndexOf('}')).
            trim();
            args.push(fnBody);
            return Function.apply(null, args);
        }
    
        function parseFns(obj) {
            var retObj;
    
            switch (Object.prototype.toString.call(obj)) {
                case '[object Undefined]':
                case '[object Null]':
                case '[object Boolean]':
                case '[object Number]':
                case '[object Function]':
                    retObj = obj;
                    break;
                case '[object String]':
                    retObj = fnRE.test(obj) ? strToFn(obj) : obj;
                    break;
                case '[object Array]':
                    retObj = obj.map(function (value) {
                        return parseFns(value);
                    });
                    break;
                case '[object Object]':
                    retObj = {};
                    Object.keys(obj).forEach(function (key) {
                        var value = obj[key];
                        retObj[key] = parseFns(value);
                    });
                    break;
                default:
                    break;
            }
    
            return retObj;
        };
    
        function stringifyFns(obj) {
            var retObj;
    
            switch (Object.prototype.toString.call(obj)) {
                case '[object Undefined]':
                case '[object Null]':
                case '[object Boolean]':
                case '[object Number]':
                case '[object String]':
                    retObj = obj;
                    break;
                case '[object Function]':
                    retObj = obj.toString();
                    break;
                case '[object Array]':
                    retObj = obj.map(function (value) {
                        return stringifyFns(value);
                    });
                    break;
                case '[object Object]':
                    retObj = {};
                    Object.keys(obj).forEach(function (key) {
                        var value = obj[key];
                        retObj[key] = stringifyFns(value);
                    });
                    break;
                default:
                    break;
            }
    
            return retObj;
        }
    
        return {
            stringify: function (obj) {
                var obj2 = stringifyFns(obj);
                return JSON.stringify(obj2);
            },
            parse: function (str) {
                var obj = JSON.parse(str);
                return parseFns(obj);
            }
        };
    });
    

    如何使用:

    只需将其注入您的控制器(或其他),然后使用JSNOwithFn.stringify/parse代替JSON.stringify/parse 您的代码中无需更改任何其他内容 它会起作用:))

答案 1 :(得分:0)

就像ExpertSystem所说的那样,JSON.stringify在序列化时会抛出你的格式化函数。

根据您要执行的操作,您可以将格式化程序功能单独存储在控制器中,并在从localstorage加载图表选项后重新分配。

控制器的顶部:

$scope.xAxisFormatter = function(){
    return 'Week ' + this.value;
}

您的图表选项:

<snip...>
xAxis: {
          tickInterval: 1,
          allowDecimals: false,
          labels: {
             formatter: $scope.xAxisFormatter
                   }                    
        },
<snip...>

从localstorage加载时:

$scope.highchartsNG = JSON.parse(localStorage.getItem('chart'));
$scope.highchartsNG.options.xAxis.labels.formatter = $scope.xAxisFormatter;