2

I was wondering if there was a way to have knockout check to see if data is null before it tries to put it into an observable?

Right now I do this:

if (!data.Filename) {
    this.FileName = ko.observable("");
}
else {
    this.FileName = ko.observable(data.Filename);
}

Otherwise a null value in the data will cause the entire property not to show up. Is there a way to use extenders or something that I can add a null check to without having to do this with every property? My data has nulls in random places that I can't control and I don't want the property not to show up because one row in the dataset has a null value for that property.

Seems like there should be a better way to do this.

Jeroen
  • 60,696
  • 40
  • 206
  • 339
Barry Franklin
  • 1,781
  • 1
  • 27
  • 45
  • 1
    What do you mean by: not show up? Can you show us some html with the bindings? Or maybe a working example on jsfiddle – Steen Tøttrup Feb 01 '16 at 18:43
  • When the data comes back from the server it has a property "Filename", when I map it to my observablearray, the "Filename" property doesn't get mapped and does not appear in whatever it is bound to. – Barry Franklin Feb 01 '16 at 20:06

2 Answers2

3

heh

There are a number of ways to do this. What I would do is

var self = this;
self.fileName = ko.observable(data.Filename);
self.fileNameComputed = ko.computed(function(){
       return self.fileName() || ""
});

Then, in your mark up reference the computed instead if the observable.

QBM5
  • 2,778
  • 2
  • 17
  • 24
  • 2
    Please consider using pureComputed instead in your examples, unless the question is about a older version of knockout – Steen Tøttrup Feb 01 '16 at 18:58
  • :) I am still stuck on version 2.0, so thats what I am familiar with – QBM5 Feb 01 '16 at 19:03
  • This works for several reasons... most of all it is the simplest, and another because it keeps self.Filename as either null or data, which I use for a conditional... – Barry Franklin Feb 01 '16 at 20:18
1

In Javascript there are other patterns available to do this.

The first, and simplest, is akin to the ?? operator in C#:

function ViewModel(data)  {
  data = data || {};
  this.Filename .observable(data.Filename || "");
}

The || operator will return the left operand unless it is falsy, then it'll fall back to the second argument. My example above will:

  1. Make sure data itself is "at least" an empty object (where .Filename would be undefined);
  2. Make sure that the input to ko.observable(...) is "at least" the empty string.

A second option would be to use default options. An example that utilizes jQuery to merge input data and default options:

var defaultData = {
  Filename: "enter-a-file" // could also be empty string of course!
};

function ViewModel(data)  {
  var dto = $.extend({}, defaultData, data);
  this.Filename = ko.observable(dto.Filename);
}

This will "fold" data into defaultData, and fold that result into an empty, fresh object, making sure the dto variable holds the merged result. The rest of your function can then safely assume a fully populated input variable.

The third and final option I'll mention is a remix of QBM5's answer, but I agree with the commenter's there that if you can use a pureComputed (which, in your example, is perfectly fine), you probably should:

function ViewModel(data)  {
  var self = this;
  data = data || {};
  this.Filename = ko.observable(data.Filename);
  this.FilenameText = ko.pureComputed(function() {
    return self.Filename() || "";
  });
}

PS. You didn't have the underlying issue you mention because you spell FileName and Filename with different capitalization on this and data respectively, didn't you? ;-)

Community
  • 1
  • 1
Jeroen
  • 60,696
  • 40
  • 206
  • 339
  • No, no underlying issue that I'm aware of. The data comes in as data.Filename and I use this(self).FileName as the observable - doesn't really do anything. I've done it for a bunch of other things and it doesn't seem to matter. – Barry Franklin Feb 01 '16 at 20:22