简体   繁体   中英

Knockout.js, Conditional Observable that Depends on Observable?

Bit of a noob to KOjs and STOF here, have a question,

I have an observable(s), their data is a number 0,1,2, or 3. I would like other observables to hold data that is conditionally set by this data.

example

this.isText = ko.observable(data.isText);
this.formatted.isText = ko.computed(function() {
    var it = self.isText();
    if (it == '0') {
      return 'No';
    }
    else if (it == '1') {
      return 'Yes'
    }
    else {
      return 'Not Specified'
    }
  });

My example snippet does not function as expected.

What is the proper way to achieve holding a formatted text version of the observable isText ?


How the object is created,

function ListItem(data) {
    this.isText = ko.observable(data.isText);
    this.formatted.isText = ko.computed(function() {
        var it = self.isText();
        if (it == '0') {
            return 'No';
        }
        else if (it == '1') {
            return 'Yes'
        }
        else {
            return 'Not Specified'
        }
    });
}

this.loadList = function(data) {
    // console.log(data);
    $.getJSON('someLoader.php', {
      checklistID: data.id,
      checklistRev: data.rev
    }, function(json, textStatus) {
      if (textStatus == 'success') {
        for (var i = 0; i < json.length; i++) {
          model.formData.push(new ListItem(json[i]));
        }
      }
      else {
        console.log('Error Competing Request');
      }
    });
  }

The HTML,

<td colspan="1">
    <select class="form-control" data-bind="visible: status().edit, value: isText()">
        <option value="1">Yes</option>
        <option value="0">No</option>
    </select>
    <span data-bind="text: formated.isText(), visible: !status().edit()"></span>
</td>

Everything as a whole works observables get properly declared there are no errors, on first load everything looks ok. If the isText() observable gets updated however the formatted.isText() does not update to reflect the change. if I do a console log in the terminal, of isText() the value is correct depending on if it has been updated. So on initial load if it was 1 and it was updated to 0 it retains the value 0.

I guess your example doesn't work because this.formatted is undefined. To get around this, you can (and should) use another variable name instead of trying to nest your variable:

this.formattedText = ko.computed(function() {
  var it = self.isText();
  if (it == '0') {
    return 'No';
  }
  else if (it == '1') {
    return 'Yes'
  }
  else {
    return 'Not Specified'
  }
});

I think what you're trying to do is attach a computed to its parent observable. This is a technique I've seen used often by RNiemeyer to keep cleaner code especially when serializing a viewmodel. If so then I think what you want to do is swap the order of "isText" and "formatted" in formatted.isText .

As Thibaut Remy's answer already hinted at, you can't attach a computed to nothing, and since "formatted" isn't a thing already you're basically saying undefined.isText = ko.computed(...) Instead you should be attaching the computed to the existing observable: this.isText.formatted = ko.computed(...) , and calling it similarly in your bindings: <span data-bind="text: isText.formatted(), visible: !status().edit()"></span> .

Here's a jsfiddle

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