2
votes

In a function that takes a generator, that may be a plain JS Array or an ko.observableArray, how can I use the observableArray with minimal overhead?

This is what the code currently looks like:

function (itemGenerator) { // returns observableArray or JS array
  var allItems = ko.observable();

  // triggered after user interaction
  var itemsFromGenerator = itemGenerator();
  if (ko.isObservable(itemsFromGenerator)) {
    allItems(itemsFromGenerator());

    itemsFromGenerator.subscribe(newValue => {
      allItems(newValue)
    });
  } else {
    allItems(children);
  }
}

Is there any way to replace allItems with the observableArray if itemsFromGenerator is an observableArray? So that I don't have to subscribe to further changes "manually" and have to copies of the data around.

(This is used in a TreeView implementation, where I only want to generate the items array when a node is expanded.)

2

2 Answers

1
votes

Just have allItems contain the observable array, then you have the outside observable to track when the observable array is replaced. No subscriptions are needed.

function (itemGenerator) { // returns observableArray or JS array
  var allItems = ko.observable();

  // triggered after user interaction
  var itemsFromGenerator = itemGenerator();
  if (ko.isObservable(itemsFromGenerator)) {
    allItems(itemsFromGenerator);
  } else {
    allItems(ko.observableArray(itemsFromGenerator));
  }
}

This answer is based on the information you have given. I still don't know why you need to maintain the reference to itemsFromGenerator unless it is somehow independently referenced outside of this function. I also don't know when the code under // triggered after user interaction is actually called. Finally, I don't know where/how these items in the array are used.

1
votes

If I got it right, you could use ko.utils.unwrapObservable() (see good explanation):

You should use ko.utils.unwrapObservable in cases where you don't know if you have been given an observable or not.

Code should be like this:

function ViewModel(itemGenerator) {
    var self = this;
    this.itemsFromGenerator = ko.observableArray();
    this.generate = function() {
        self.itemsFromGenerator(ko.utils.unwrapObservable(itemGenerator()));                                       
    };
}

Where generate is your trigger to run items generator. See the demo. In generator function you can switch between plain array and observable array.