简体   繁体   中英

Accept decimal places in KO numeric extension

I have implemented the extender shown in the Knockout live 1 example - https://knockoutjs.com/documentation/extenders.html

ko.extenders.precision = function (target, precision) {
  //create a writable computed observable to intercept writes to our observable
  var result = ko
    .pureComputed({
      read: target, //always return the original observables value
      write: function (newValue) {
        var current = target(),
          roundingMultiplier = Math.pow(10, precision),
          newValueAsNum = isNaN(newValue) ? 0 : +newValue,
          valueToWrite =
            Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier;

        //only write if it changed
        if (valueToWrite !== current) {
          target(valueToWrite);
        } else {
          //if the rounded value is the same, but a different value was written, force a notification for the current field
          if (newValue !== current) {
            target.notifySubscribers(valueToWrite);
          }
        }
      },
    })
    .extend({ notify: "always" });

  //initialize with current value to make sure it is rounded appropriately
  result(target());

  //return the new computed observable
  return result;
};

The view model is as follows:

model.gwaioDifficultySettings = {
  minionMod: ko.observable(0).extend({
    precision: 3,
    rateLimit: { timeout: 500, method: "notifyWhenChangesStop" },
  }),
};

And it's accessible through an HTML input field:

  <div>
    <input
      type="number"
      style="width: 50px; padding-bottom: 0px;"
      data-bind="textInput: model.gwaioDifficultySettings.minionMod"
    />
    <span style="margin-left: 6px;"></span>
    <loc>Minion Modifier</loc>
    <span
      class="info_tip"
      data-bind="tooltip: '!LOC:Mandatory Minions + Star Distance * Minion Modifier = number of additional enemy Commanders.'"
      >?</span
    >
  </div>

However, I've had to add rateLimit: { timeout: 500, method: "notifyWhenChangesStop" } , else I find that the field will remove the decimal point once the value is an integer, and then it will prevent any attempts to enter the decimal point again.

This doesn't appear to be the case in the live example, and I'm wondering where I've gone wrong, or if it's simply due to the environment I'm working in with Knockout 3 and Chromium 28.

I added some code from https://gist.github.com/gnab/7579584 to my extender:

        if (_.isString(newValue)) {
          newValue = newValue.replace(",", ".");

          newValue = parseFloat(newValue);
          if (!isNaN(newValue)) {
            target(newValue);
          }
        }

This results in:

ko.extenders.precision = function (target, precision) {
  //create a writable computed observable to intercept writes to our observable
  var result = ko
    .pureComputed({
      read: target, //always return the original observables value
      write: function (newValue) {
        if (_.isString(newValue)) {
          newValue = newValue.replace(",", ".");

          newValue = parseFloat(newValue);
          if (!isNaN(newValue)) {
            target(newValue);
          }
        }
        var current = target(),
          roundingMultiplier = Math.pow(10, precision),
          newValueAsNum = isNaN(newValue) ? 0 : +newValue,
          valueToWrite =
            Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier;

        //only write if it changed
        if (valueToWrite !== current) {
          target(valueToWrite);
        } else {
          //if the rounded value is the same, but a different value was written, force a notification for the current field
          if (newValue !== current) {
            target.notifySubscribers(valueToWrite);
          }
        }
      },
    })
    .extend({ notify: "always" });

  //initialize with current value to make sure it is rounded appropriately
  result(target());

  //return the new computed observable
  return result;
};

In all my tests so far this seems to perform as required. It will leave a hanging decimal point visible if one is entered, but this doesn't appear to have any negative consequences.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM