Search code examples
javascriptdata-bindingknockout.jsecmascript-5

toPrecision is causing a data bind to fail to update


I am working on a UI mod for a game which uses HTML, CSS and JavaScript to render UI elements. This mod displays information on the total surface area of all the planets in a system. It achieves this through a function which calculates the total surface area, then passes this information to another function for formatting. Finally, a data bind is used to display this information in the UI.

  var formatedString = function (number) {
    var km2 = 1000000
    number = number / km2
    if (number < 1000) {
      return number.toPrecision(3)
    } else {
      return Math.floor(number)
    }
  };

  model.systemSurfaceArea = ko.computed(function () {
    var area = 0
    model.selection.system().planets().forEach(function (planet) {
      if (planet.generator && planet.generator.biom != 'gas') {
        area += 4 * Math.PI * Math.pow(planet.generator.radius, 2)
      }
    })
    return formatedString(area)
  })

  var url = 'coui://ui/mods/section_of_foreign_intelligence/section_of_foreign_intelligence.html'
  $.get(url, function (html) {
    console.log("Loaded html " + url);
    var $fi = $(html)
    $('#system-detail').append($fi)
    ko.applyBindings(model, $fi[0])
  })
<span class="system" data-bind="text: $root.systemSurfaceArea"></span>k<sup>2</sup>

I have encountered a bug whereby for some systems the data bind is not being updated. I can see through use of the console that all calculations are being performed correctly, but the value on the screen remains unchanged. I have traced this back to the use of toPrecision(3). When the value of precision is lower than 5, or when Math.floor(number) is called, the data-bind will not always update.

To provide an example: I have systems A, B and C. When I click the systems in the order A, B, C, I would expect to see the system sizes A, B, C. Yet what happens is I see A, B, B. Clicking in the order C, B, A gives me sizes C, C, A. In this instance B and C are failing, yet A is unaffected and always displays correctly.

I am at a loss as to why this might be and am hoping someone can help.

EDIT: I have found that removing the table formatting from the HTML removes the problem. I just don't understand why.

  <table>
    <tr>
      <td>
        Surface Area:
      </td>
      <td>
        <span class="system" data-bind="text: $root.systemSurfaceArea"></span>k<sup>2</sup>
      </td>
    </tr>
    <tr>
      <td>
        Threat Level:
      </td>
      <td>
        <span class="system" data-bind="text: $root.systemThreat"></span>
      </td>
    </tr>
  </table>

Solution

  • I have replaced my HTML table with divs and CSS table formatting and it has resolved my issue. I still don't understand why the HTML table broke things though, so if anyone has an answer I'll happily mark it up.

      <div class="table">
        <div class="tr">
          <div class="td">Surface Area:</div>
          <div class="td"><span class="system" data-bind="text: $root.systemSurfaceArea"></span>k<sup>2</sup></div>
        </div>
        <div class="tr">
          <div class="td">Threat Level:</div>
          <div class="td"><span class="system" data-bind="text: $root.systemThreat"></span></div>
        </div>
      </div>
    
    .table {
       display: table;
       }
    .tr { 
      display: table-row; 
    }
    .td { 
      display: table-cell; 
    }