Handsontable RuleJS缺少递归解析

时间:2016-01-20 10:03:46

标签: javascript angularjs handsontable

我使用了Handsontable(see it on GitHub)的RuleJS插件,它对基本公式很有用,但似乎缺乏递归解析。

我已经制作了一个包含两个详细示例的代码段,请查看:



$(document).ready(function () {
  var container1 = $('#example1');
  var container2 = $('#example2');
  
  container1.handsontable({
    data: [[1, '=A2'], ['=B2', '=5 * 2']],
    colHeaders: true,
    rowHeaders: true,
    formulas: true,
    minSpareRows: 1
  });
  
  container2.handsontable({
    data: [[1, '=A2', 3], ['=C1 * B2', '=5 + 1', 3]], 
    colHeaders: true,
    rowHeaders: true,
    formulas: true,
    minSpareRows: 1
  });
});

<!DOCTYPE html>
<html>
<head>
    <script src="http://handsontable.github.io/handsontable-ruleJS/lib/jquery/jquery-1.10.2.js"></script>
    <script src="http://handsontable.github.io/handsontable-ruleJS/lib/handsontable/handsontable.full.js"></script>
    <link rel="stylesheet" media="screen" href="http://handsontable.github.io/handsontable-ruleJS/lib/handsontable/handsontable.full.css">
    <script src="http://handsontable.github.io/handsontable-ruleJS/lib/RuleJS/lib/lodash/lodash.js"></script>
    <script src="http://handsontable.github.io/handsontable-ruleJS/lib/RuleJS/lib/underscore.string/underscore.string.js"></script>
    <script src="http://handsontable.github.io/handsontable-ruleJS/lib/RuleJS/lib/moment/moment.js"></script>
    <script src="http://handsontable.github.io/handsontable-ruleJS/lib/RuleJS/lib/numeral/numeral.js"></script>
    <script src="http://handsontable.github.io/handsontable-ruleJS/lib/RuleJS/lib/numericjs/numeric.js"></script>
    <script src="http://handsontable.github.io/handsontable-ruleJS/lib/RuleJS/lib/js-md5/md5.js"></script>
    <script src="http://handsontable.github.io/handsontable-ruleJS/lib/RuleJS/lib/jstat/jstat.js"></script>
    <script src="http://handsontable.github.io/handsontable-ruleJS/lib/RuleJS/lib/formulajs/formula.js"></script>
    <script src="http://handsontable.github.io/handsontable-ruleJS/lib/RuleJS/js/parser.js"></script>
    <script src="http://handsontable.github.io/handsontable-ruleJS/lib/RuleJS/js/ruleJS.js"></script>
    <script src="http://handsontable.github.io/handsontable-ruleJS/lib/handsontable/handsontable.formula.js"></script>
    <link rel="stylesheet" media="screen" href="http://handsontable.github.io/handsontable-ruleJS/css/samples.css">

    <style type="text/css">
        body {background: white; margin: 20px;}
        h2 {margin: 20px 0;}
    </style>
</head>
<body>
  <h2>Bugs in handsontable-ruleJS</h2>

  <p>Both cases seem to come from the same problem, but they both worth seeing.</p>
  <p>Here B1 displays the value of B2 <b>before</b> its interpretation where it should display "<b>10</b>". Just like it misses some recursive processing. Focusing the cell will show its real value "<b>=A2</b>" which will next be interpreted correctly.</p>
  <div id="example1" class="handsontable"></div>

  <p>This one is interesting, because when the cell "<b>A2</b>" tries to calculate "<b>C1 * B2</b>" it does "<b>3 * =5 + 1"</b> instead of "<b>3 * 6</b>", which obviously fails.</p>
  <div id="example2" class="handsontable"></div>
  <p>The only way to correct it is to edit "<b>C1</b>" (even without changing its value).</p>
</body>
</html>
  
&#13;
&#13;
&#13;

如果您更喜欢JSFiddle,here you go

最好的问候。

修改:使用嵌入代码段并进入全屏时,您可能看不到第一个错误,因为它似乎触发了表的刷新。使用JSFiddle可以获得更好的结果。

编辑2(求助):好的,我想我已修补了它,you can find the result here。当Stackoverflow允许我这样做时,我会发布一个完整的答案。任何反馈仍然是受欢迎的,我确信有更好的方法可以做到这一点,但至少它现在似乎有效。

2 个答案:

答案 0 :(得分:1)

可在此处找到工作代码:http://jsfiddle.net/71o23gp0/8/

重要的是取代:

var custom = {
      cellValue: instance.getDataAtCell
};

通过

var custom = {
        cellValue: function(row, col){
          var value = instance.getDataAtCell(row, col);
          if (value && value[0] === '=') {
              var formula = value.substr(1).toUpperCase();
              var cellId = instance.plugin.utils.translateCellCoords({
                  row: row,
                  col: col
              });
              var item = instance.plugin.matrix.getItem(cellId);

              if (!item) {
                  item = instance.plugin.matrix.addItem({
                      id: cellId,
                      formula: formula
                  });
              } else {
                  item = instance.plugin.matrix.updateItem({
                      id: cellId,
                      formula: formula
                  });
              }
              var formulaResult = instance.plugin.parse(formula, {
                  row: row,
                  col: col,
                  id: cellId
              });
              value = formulaResult.result || '#ERROR';
              formulasResults[cellId] = value;
              instance.plugin.matrix.updateItem(item, {
                  formula: formula,
                  value: formulaResult.result,
                  error: formulaResult.error
              });
          }
          return value;
      }
    };

它不是简单地返回单元格的值,而是检查它是否为公式,如果是,则解析它。因为在解析公式时,RuleJS会调用此方法,所以这会使分辨率递归。然后缓存结果以获得更好的性能。

源代码中还有其他一些小修改,但我在每次修改之前和之后都在小提琴中添加了注释。

答案 1 :(得分:0)

在这个问题的答案https://stackoverflow.com/a/35528447/489865之后,我进一步修补了一下。工作代码可以在http://jsfiddle.net/ufL1vts5/找到。

重要的变化是存储在formulasResults[]而不只是&#34;结果&#34;而是由instance.plugin.parse()返回的整个对象,以便按照以下方式拾取公式的单元格突出显示:

// parse formula
var newValue = instance.plugin.parse(formula, {row: row, col: col, id: cellId});
// cache result
formulasResults[cellId] = newValue;

我的修改包括:

  1. 将整个instance.plugin.parse()对象存储在formulasResults[]中, 以便应用formula / formula-error CSS样式。 [注意 这不是完美的:它会选择&#34;计算&#34;配方风格 正确,但有时应该只有formula-error样式 得到formula风格---但足以满足我的需要。]

  2. 添加了formula&amp; formula-error CSS样式(来自提供 handsontable.formula.css)进入JSFiddle示例,以便那个单元格 可以看到突出显示。

  3. 增加了2个额外的例子:一个来自 handsontable formula returning #NEED_UPDATE, 显示它也有效,并且提供的示例中有一个 handsontable-ruleJS 位于https://github.com/handsontable/handsontable-ruleJS/blob/master/index.html

  4. 删除了新添加的beforeRender挂钩 instance.removeHook('beforeRender', beforeRender);中的this.init = function ()

  5. 更改了handsontable.formula.js中的一些代码布局,以便它 最小化与提供的差异 的 handsontable-ruleJS