0
votes

I have a 'flat' array with 3 items:

[{"title":"welcome","file":"default.aspx","category":"finance"},
{"title":"test2","file":"test2.aspx","category":"finance"},
{"title":"test1","file":"test1.aspx","category":"housing"}]

The objective is to transform this into a nested observableArray with 2 items:

[{"category":"finance","content":[
    {"title":"welcome","file":"default.aspx","category":"finance"},     
    {"title":"test2","file":"test2.aspx","category":"finance"}]},
{"category":"housing","content":[
    {"title":"test1","file":"test1.aspx","category":"housing"}]}]

http://www.knockmeout.net/2011/04/utility-functions-in-knockoutjs.html helped me to extract unique categories in two steps:

 self.getcategories = ko.computed(function () {
                        var categories = ko.utils.arrayMap(self.pages(), function (item) {
                            return item.category();
                        });
                        return categories.sort();
                    });


self.uniqueCategories = ko.dependentObservable(function() {
                        return ko.utils.arrayGetDistinctValues(self.self.getcategories()).sort();
                    });

//uniqueCategories: ["finance","housing"]

However I can't figure out how to create the nested array. I got as far as this:

self.createCategories = ko.computed(function () {
                         ko.utils.arrayForEach(self.uniqueCategories(), function (item) {
                            var content = getCategoryContent(item);

                            var c = new category(item, content);
                            self.Categories.push(c);
                        });

                        return true;
                    });



                    function getCategoryContent(whichcategory) {
                        return ko.utils.arrayFilter(self.pages(), function (page) {
                            return page.category() === whichcategory;

                        });
                    }

It results however in 5 category items (finance 4x, housing 1x) where I expect just 2.

1
Copied your code into a jsFiddle and it works as expected. You did have a typo in your sample arrayGetDistinctValues(self.self.getcategories()) but wouldn't cause the issue you describe. What version of KO ? - Robert Slaney

1 Answers

0
votes

Your computed function createCategories is probably being invoked more than once. e.g. if you are adding items to your pages() array one at a time, this will trigger the createCategories function each time you add an item.

Normally you would make the categories array and return it from a computed function. Currently you are adding to the Categories observable array without clearing it each time.

An easy fix would be to clear out the Categories array at the top of the createCategories function. This would leave you in the odd situation of having to call createCategories at least once to set up the dependencies, but after that it would work automatically when the data changed.

Another option would be create an array and return it from the createCategories functions, then you could just rename the function to Categories and not have an observable array. This would be the way I would normally use computed functions.

On more option would be to just do the work as normal JavaScript functions (rather than computed) and just call createCategories manually when you change the original array (e.g. when you get a result back from your server).