5
\$\begingroup\$

I'm working with Knockout3 in a Chromium 40 environment (ES5).

I have a series of preset difficulty options, and a player has an option to switch to custom difficulty and tweak the options. When they tweak an option the save button lights up and the player cannot proceed to start the game until they save their settings. If they switch away from custom difficulty to a preset all changes are marked as saved so that they can proceed.

To track whether there has been a change I am using ko.computed, and it all looks as follows:

model.gwaioDifficultySettings = {
  shuffleSpawns: ko.observable(true),
  easierStart: ko.observable(false),
  tougherCommanders: ko.observable(false),
  factionTech: ko.observable(false),
  customDifficulty: ko.observable(false),
  goForKill: ko.observable(false),
  microType: ko.observableArray([0, 1, 2]),
  microTypeDescription: ko.observable({
    0: "!LOC:No",
    1: "!LOC:Basic",
    2: "!LOC:Advanced",
  }),
  microTypeChosen: ko.observable(0),
  getmicroTypeDescription: function (value) {
    return loc(model.gwaioDifficultySettings.microTypeDescription()[value]);
  },
  mandatoryMinions: ko.observable(0).extend({
    precision: 3,
  }),
  minionMod: ko.observable(0).extend({
    precision: 3,
  }),
  priorityScoutMetalSpots: ko.observable(false),
  useEasierSystemTemplate: ko.observable(false),
  factoryBuildDelayMin: ko.observable(0).extend({
    precision: 0,
  }),
  factoryBuildDelayMax: ko.observable(0).extend({
    precision: 0,
  }),
  unableToExpandDelay: ko.observable(0).extend({
    precision: 0,
  }),
  enableCommanderDangerResponses: ko.observable(false),
  perExpansionDelay: ko.observable(0).extend({
    precision: 0,
  }),
  personalityTags: ko.observableArray([
    "Default",
    "Tutorial",
    "SlowerExpansion",
    "PreventsWaste",
  ]),
  personalityTagsDescription: ko.observable({
    Default: "!LOC:Default",
    Tutorial: "!LOC:Lobotomy",
    SlowerExpansion: "!LOC:Slower Expansion",
    PreventsWaste: "!LOC:Prevent Waste",
  }),
  personalityTagsChosen: ko.observableArray([]),
  getpersonalityTagsDescription: function (value) {
    return loc(
      model.gwaioDifficultySettings.personalityTagsDescription()[value]
    );
  },
  econBase: ko.observable(0).extend({
    precision: 3,
  }),
  econRatePerDist: ko.observable(0).extend({
    precision: 3,
  }),
  maxBasicFabbers: ko.observable(0).extend({
    precision: 0,
  }),
  maxAdvancedFabbers: ko.observable(0).extend({
    precision: 0,
  }),
  startingLocationEvaluationRadius: ko.observable(0).extend({
    precision: 0,
  }),
  ffaChance: ko.observable(0).extend({
    precision: 0,
  }),
  bossCommanders: ko.observable(0).extend({
    precision: 0,
  }),
  landAnywhereChance: ko.observable(0).extend({
    precision: 0,
  }),
  suddenDeathChance: ko.observable(0).extend({
    precision: 0,
  }),
  bountyModeChance: ko.observable(0).extend({
    precision: 0,
  }),
  bountyModeValue: ko.observable(0).extend({
    precision: 3,
  }),
  unsavedChanges: ko.observable(false),
  newGalaxyNeeded: ko.observable(false).extend({ notify: "always" }),
};

ko.computed(function () {
  if (model.gwaioDifficultySettings.customDifficulty()) {
    model.gwaioDifficultySettings.bossCommanders();
    model.gwaioDifficultySettings.bountyModeChance();
    model.gwaioDifficultySettings.bountyModeValue();
    model.gwaioDifficultySettings.microTypeChosen();
    model.gwaioDifficultySettings.personalityTagsChosen();
    model.gwaioDifficultySettings.econBase();
    model.gwaioDifficultySettings.econRatePerDist();
    model.gwaioDifficultySettings.enableCommanderDangerResponses();
    model.gwaioDifficultySettings.factoryBuildDelayMax();
    model.gwaioDifficultySettings.factoryBuildDelayMin();
    model.gwaioDifficultySettings.ffaChance();
    model.gwaioDifficultySettings.goForKill();
    model.gwaioDifficultySettings.landAnywhereChance();
    model.gwaioDifficultySettings.mandatoryMinions();
    model.gwaioDifficultySettings.maxAdvancedFabbers();
    model.gwaioDifficultySettings.maxBasicFabbers();
    model.gwaioDifficultySettings.minionMod();
    model.gwaioDifficultySettings.perExpansionDelay();
    model.gwaioDifficultySettings.priorityScoutMetalSpots();
    model.gwaioDifficultySettings.startingLocationEvaluationRadius();
    model.gwaioDifficultySettings.suddenDeathChance();
    model.gwaioDifficultySettings.unableToExpandDelay();
    model.gwaioDifficultySettings.useEasierSystemTemplate();
    model.gwaioDifficultySettings.unsavedChanges(true);
  }
});

// Prevent simply switching to GW-CUSTOM causing unsaved changes to become true
model.gwaioDifficultySettings.customDifficulty.subscribe(function () {
  model.gwaioDifficultySettings.unsavedChanges(false);
});

This all seems to work rather well, except that switching to custom difficulty causes unsavedChanges to become true, when in reality the desired behaviour is that changes to fields like shuffleSpawns cause it to become true, but only when customDifficulty is true. I'm using a subscription to customDifficulty to workaround this, but given my inexperience with Knockout I'm wondering if there's a better way to achieve the desired result? I can replace the subscription with:

ko.computed(function () {
  model.gwaioDifficultySettings.customDifficulty();
  model.gwaioDifficultySettings.unsavedChanges(false);
});

This achieves the same thing, but I've no idea if that's consider better, worse, or irrelevant.

I have seen commentary on dirtyFlag extenders, and was wondering if that's the route I should have gone down, or if my current method is acceptable.

\$\endgroup\$
  • 4
    \$\begingroup\$ Fair enough. I've expanded the question to include the full view model \$\endgroup\$ – Quitch Jul 15 at 11:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.