1

In my knockout bound view I am not getting all values.

This is my script file:

var ViewModel = function () {
    var self = this;
    self.games = ko.observableArray();
    self.error = ko.observable();
    self.detail = ko.observable();

    var gamesUri = '/api/games/';

    self.getGameDetail = function (item) {
        ajaxHelper(gamesUri + item.Id, 'GET').done(function (data) {
            self.detail(data);
        });
        console.log(self.detail);
    };
    function ajaxHelper(uri, method, data) {
        self.error('');
        return $.ajax({
            type: method,
            url: uri,
            dataType: 'json',
            contentType: 'application/json',
            data: data ? JSON.stringify(data) : null
        }).fail(function (jqXHR, textStatus, errorThrown) {
            self.error(errorThrown);
        });
    }

    function getAllGames() {
        ajaxHelper(gamesUri, 'GET').done(function (data) {
            self.games(data);
        });
    }

    getAllGames();
};

ko.applyBindings(new ViewModel());

This is my view:

<div class="row">
    <div class="col-md-4">
    <div class="panel panel-default">
        <div class="panel-heading">
            <h2 class="panel-title">Games</h2>
        </div>
        <div class="panel-body">
            <ul class="list-unstyled" data-bind="foreach: games">
                <li>
                    <strong><span data-bind="text: DeveloperName"></span>:<span data-bind="text: Title"></span></strong>
                    <small><a href="#" data-bind="click: $parent.getGameDetail">Details</a></small>
                </li>
            </ul>
        </div>
    </div>
        <div class="alert alert-danger" data-bind="visible: error"><p data-bind="text: error"></p></div>
    </div>

    <div class="col-md-4">
       <div class="panel panel-default">
           <div class="panel-heading"><h2 class="panel-title">Details</h2></div>
       </div>
        <table class="table">
            <tr><td>Developer</td><td data-bind="text: detail().DeveloperName"></td></tr> //Only this value is displayed
            <tr><td>Title</td><td data-bind="text: detail().Title"></td></tr>
            <tr><td>Price</td><td data-bind="text: detail().Price"></td></tr>
            <tr><td>Genre</td><td data-bind="text: detail().Genre"></td></tr>
            <tr><td>Year</td><td data-bind="text: detail().Year"></td></tr>
        </table>
    </div>

    <div class="col-md-4">

    </div>
</div>

The problem is it only displays DeveloperName in the view. Title, Price, Genre and Year are not dispayed in the view. I tried many things but I don't know where the error is.

JotaBe
  • 38,030
  • 8
  • 98
  • 117
Noxious Reptile
  • 838
  • 1
  • 7
  • 24

1 Answers1

0

There are two approaches.

The easiest one is to use the with or template binding. The technique is similar, but I'll show an example with the with binding:

<table class="table" data-bind="with: details">
   <tr><td>Developer</td><td data-bind="text: DeveloperName"></td></tr>
   <tr><td>Title</td><td data-bind="text: Title"></td></tr>
   <tr><td>Price</td><td data-bind="text: Price"></td></tr>
   <tr><td>Genre</td><td data-bind="text: Genre"></td></tr>
   <tr><td>Year</td><td data-bind="text: Year"></td></tr>
</table>

With this technique, whenever you change the object inside the details observable, the new values are applied to the children elements inside the elment which has the with binding. In this case all the elements inside the table element. Besides, the syntax is shorter and more clear. NOTE: you must can use $parent, $parents[] or $root if you need to bind something outside the object bound with with.

The hardest one, which is only neccessary if your viewmodel is more complex and has, for example, computed observables, you need to create an object whose properties are also observables. In this case you bind this object once, and, on the next occasions, you update the innser obervable properties, instead of changing the object itself.

For your example, you must create an object which has all its properties, like DeveloperName, Title, Price, etc. defined as observables. Then you must map the values recovered by AJAX to this properties, which you can do by hand, doing details().DeveloperName(newDetails.DeveloperName), and so on, or using the ko.mapping plugin.

Important note: if you use this technique you must keep the original details bound object, and update its properties. If you substitute the details object itself with a new one, the binding will be lost, and will stop working as desired.

Another note: you cannot use cleanNodes for what you think. Please, see this Q&A.

Community
  • 1
  • 1
JotaBe
  • 38,030
  • 8
  • 98
  • 117