Search code examples
javascriptjqueryknockout.jsknockout-3.0

How to append json and display result using ajax (Observable array)


Whenever i click that Add button it should fetch json data using ajax and should append that to my Observable arrray and in html also i want to append that.

Here is my code

    function ProductViewModel() {
      var self = this;
      self.ProductList = ko.observableArray([]);

      self.GetProducts = function (){
        $.ajax({
          type: "POST",
          dataType: "json",
          url: 'data.json',
          //my json data is 
          //{"1":{"name":"user","productname":"hello"},"2":{"name":"user2","productname":"hello2"}}

          
          success: function (data) {
            console.log(self.ProductList());
              self.ProductList($.map(data, function (product) {
                 return new ProductDetailsViewModel(product);
            }));
          }
        });
      }
     self.GetProducts();
    }

    function ProductDetailsViewModel(data){
      var self = this;
      self.Name= ko.observable(data.name);
      self.PrdouctName= ko.observable(data.productname);
    }

    ko.applyBindings(new ProductViewModel());
  <script
  src="https://code.jquery.com/jquery-2.2.4.min.js"
  integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
  crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js" charset="utf-8"></script>


  <h1 data-bind="foreach:ProductList">
     <div data-bind="text:Name"></div>
     <div data-bind="text:PrdouctName"></div>
  </h1>

Thanks in advance!


Solution

  • Do NOT user your current solution like:

    $.map(data, function (product){
                   self.ProductList.push(new ProductDetailsViewModel(product));
                 })
    

    Just because it works does not mean that it is ok. You should $.map when you transform data to output them in a different sequence. In your case you should use $.each, as you want to push "each" item in the array.

    Both map and each work similarly, in the sense that they will iterate an array and perform a callback on the items, but semantic-wise you should always use the proper method to denote your actual intentions.

    If i were you i would do something like this:

    ko.utils.arrayForEach(data, function(p) {
           self.ProductList.push(new ProductDetailsViewModel(p));
    });
    

    Two concepts to note:

    a) Learn and use knockouts utility functions, they come in hand and outperform jquery's alternatives ( from what i see/know)

    b)You should also mind how you update your list, depending on the size of the items you are adding. If you are adding a small amount of items on each callback the above should be enough. On the other hand if performance starts to become a trouble you can work on the underlying array and at the end of your data insertion you can trigger a knockout-update!

    This would work like so:

    var underlyingArray = self.ProductList();
    ko.utils.arrayForEach(data, function(p) {
           underlyingArray.push(new ProductDetailsViewModel(p));
    });
    self.ProductList.valueHasMutated();