Jollyguy
Jollyguy

Reputation: 345

How to create nested observable arrays?

I am developing an app using HTML5, Knockouk and Jquery.

The UI presents a list of Orders. At first it will show 5 orders, and when a user clicks on a "Show More" button, the next 5 orders will show.

When an Order is clicked, I will show all the activities that are related to that Order and I will be showing the first 10 activites and so on when the user clicks on the "More" button.

I have created a small example based on the requirements. I have created the first step, but I'm not able to create step 2. I am unsure how to create a nested observable array. I have added a sample, which is working for step but not for the second step.

<h1>Using Observable Arrays<br /></h1>

<div id="divActivites">
    <!-- ko foreach: Activities -->
        <div data-bind="click:$root.showDesc, attr:{'name':name,'id':id}">
            <td><span data-bind="text:name"></span></td>
            <td><span data-bind="text:id"></span></td>
        </div>
    <!-- /ko -->
    <input type="button" value="Show More" data-bind="click:addData" />
</div>
<div id="divActDec" data-bind="with:selectedData ">
    <span data-bind="text:id"></span><br />
    <span data-bind="text:name"></span><br />
    <span data-bind="text:randomStringDesc()"></span>

</div>

<script type="text/javascript">
function ActivityListModel() {
      var self = this;
      var total = ko.observable();
      self.Activities = ko.observableArray([]);
      self.selectedData = ko.observable();

      total = 0;

      self.addData = function () {
          var addtoArray = 5;

          var finalVal = total + addtoArray;

          for (var i = total+1; i <= finalVal; i++) {
              self.Activities.push(
              {
                  name: randomString(),
                  id: i
              }
              )
          }

          total = finalVal;
      }

      self.showDesc = function (ActivitiesDesc) {
          $("#divActivites").hide();
          $("#divActDec").show();
          self.selectedData(ActivitiesDesc);
      }
  }

  function ActivitiesDesc(data) {
      var activitydesc = this;
      activitydesc.name = data.name;
      activitydesc.actid = data.id;
  }

  function randomString() {
      var value = "";
      var letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
      for (var i = 0; i < 10; i++) {
          value += letters.charAt(Math.floor(Math.random() * letters.length));
      }
      return value;
  }

  function randomStringDesc() {
      var value = "";
      var letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
      for (var i = 0; i < 150; i++) {
          value += letters.charAt(Math.floor(Math.random() * letters.length));
      }
      return value;
  }

  ko.applyBindings(new ActivityListModel());
</script>

Can someone tell me how to create ActivitiesDesc object as an observable array?

Thanks, Jollyguy

Upvotes: 0

Views: 329

Answers (1)

Tanner
Tanner

Reputation: 22733

Here's a working version of what I think you're after:

Working JS Fiddle

Firstly I nested the details section into the foreach block and created an observable to control it's visibility showDesc and the click binding was modified to call toggleDesc, which switches the visibility on or off:

<!-- ko foreach: Activities -->
<div data-bind="click:$root.toggleDesc, attr:{'name':name,'id':id}">
    <div>Name: <span data-bind="text:name"></span>

    </div>
    <div>Id: <span data-bind="text:id"></span>

    </div>
</div>
<!-- added this block with a visible binding -->
<div id="divActDec" data-bind="visible: showDesc" 
                    style="border: 1px solid #000;">
     <h1>Details:</h1>
     ID: <span data-bind="text:id"></span><br />
     Name: <span data-bind="text:name"></span><br />
     Desc: <span data-bind="text:randomStringDesc()"></span>

</div>
<!-- /ko -->

In the JS, you will see a new observable per Activity that looks like this:

showDesc: ko.observable(false)

This is set to false by default. Then there is the method to toggle the description when you click an item:

self.toggleDesc = function (item) {
    item.showDesc(!item.showDesc());
}

Full JS

function ActivityListModel() {
    var self = this;
    var total = ko.observable();
    self.Activities = ko.observableArray([]);
    self.selectedData = ko.observable();

    total = 0;

    self.addData = function () {
        var addtoArray = 5;

        var finalVal = total + addtoArray;

        for (var i = total + 1; i <= finalVal; i++) {
            self.Activities.push({
                name: randomString(),
                id: i,
                showDesc: ko.observable(false)
            })
        }

        total = finalVal;
    }

    self.toggleDesc = function (item) {
        item.showDesc(!item.showDesc());
    }
}

function ActivitiesDesc(data) {
    var activitydesc = this;
    activitydesc.name = data.name;
    activitydesc.actid = data.id;
}

function randomString() {
    var value = "";
    var letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    for (var i = 0; i < 10; i++) {
        value += letters.charAt(Math.floor(Math.random() * letters.length));
    }
    return value;
}

function randomStringDesc() {
    var value = "";
    var letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    for (var i = 0; i < 150; i++) {
        value += letters.charAt(Math.floor(Math.random() * letters.length));
    }
    return value;
}

ko.applyBindings(new ActivityListModel());

Update:

I've updated the sample to nest an observableArray in to the top level array. I have renamed the top level array to be Orders, which now contains an array of activities:

Updated JS Fiddle:

The for loop now looks like this:

    for (var i = total + 1; i <= finalVal; i++) {
        self.Orders.push({
            name: randomString(),
            id: i,
            showDesc: ko.observable(false),
            activities: ko.observableArray([{
                "name": "Description 1",
                "actid": 123
            }, {
                "name": "Description 2",
                "actid": 456
            }])
        })

Upvotes: 1

Related Questions