Search code examples
asp.net-mvcknockout.jsdurandal

Durandal App - Not reflecting changes in view-model


EDIT:- I have uploaded complete code for project at github.

Following is my view-model:

define(["ko",
        "service/dataService",
    'service/logger',
        'durandal/system'],
function (ko, svc, logger, system) {
    var that = this,
    results = ko.observableArray(),
    query = ko.observable();

    var SearchProduct = {
        activate: activate,
        title: 'Search',
        search: search,
        results: results,
        query: query
    };

    return SearchProduct;

    function activate() {}

    function search() {
        svc.searchProduct(query()).then(function (data) {
            results([]);results(data);
        }).fail(function (jqXHR, textStatus) {
            var msg = 'Error searching item: ' + textStatus;
            logger.logError(msg, jqXHR, system.getModuleId(svc), true);
        });;
    }
});
  1. First thing is that in search function, when I call query(), it returns undefined.
  2. Second when I search and add new items to results with following line:

    results(data);//data is array of 10 items

the changes are not reflected in following html template:

<form class="navbar-form pull-right" role="search" data-bind="submit: search">
    <div class="form-group">
            <input type="text" class="form-control" placeholder="Search" 
                    data-bind='text: query, valueUpdate: "afterkeydown"'>
    </div>
    <button type="submit" class="btn btn-default">
        <span class="glyphicon glyphicon-search"></span>&nbsp;Search
    </button>
</form>

<section data-bind="foreach: results">
    <div class="row">
        <div class="col-md-4 pull-left">
            <label data-bind="text: name"></label><br/>
            <label data-bind="text:category"></label>
        </div>
        <div class="col-md-7 pull-right">
            <label data-bind="text:shortDescription"></label>
        </div>
    </div>
</section>

the section is bound using foreach: results. When after the change is applied (list of items added to observable) and I come to page after navigating from some other page, the following line correctly reflects the count:

<span data-bind="text: results().length"></span>&nbsp;items found

What am I doing wrong?

EDIT:- One part of puzzle is resolved

If I use results() instead of results, the binding with list works!!!

<section data-bind="foreach: results()">

EDIT 3:- *Created simple cshtml view and used viewmodel there with ko.applyBindings method. It works this way. Seems I am missing some piece of drundal wiring*


Solution

  • You have multiple problems with your current code:

    • Durandal 2.0.0 is using now Knockout through requrejs. (The documentation is yet everywhere updated. See the samples as a reference) so there is no need to explicitly reference Knockout because it can lead to strange errors like yours. And Durandal uses ko with the name knockoutout. So change your main.js:

      requirejs.config({
          paths: {
           //...      
           'knockout': "../Scripts/knockout-2.3.0",  
      });
      

      And remove the line: define('knockout', [], function () { return ko; });

    • your this handling contains some errors in your viewmodel so you have created properties on the global window object instead of declaring them as private fields. So instead of that you need to use var:

      var results = ko.observableArray([]);
      var query = ko.observable('');
      

      And in your search method you can just reference them without any "prefix":

      return dataService.searchProduct(query()).then(function (data) {
         results([]);
         results(data);
      })
      

    I have sent you a pull request.