goran85
goran85

Reputation: 503

Knockout JS - update viewModel with AJAX Call

there are some similar questions but didn't help me to solve my issue. I can't update my results on page / view after updating my viewModel with AJAX. I am getting valid AJAX response that updates the view if I reload the page, but not when I click btnAdvancedSearch

I have simple HTML:

    <div>
        <input type="button" id="btnAdvancedSearch" data-bind="click: refresh" />
    </div>

    <div id="resultslist1" data-bind="template: { name: 'rest-template', foreach: restaurants }">
    </div>

And I bind in on document load:

$(document).ready(function () {
     ko.applyBindings(new RestaurantsListViewModel());
});

My viewModel is like this, and in it I call refresh that is bound with button

// Overall viewmodel for this screen, along with initial state
function RestaurantsListViewModel() {
    var self = this;
    self.restaurants = ko.observableArray([]);

    var mappedRests = $.map($.parseJSON(sessionStorage.getItem('searchResults')), function (item) { return new Restaurant(item) });
    self.restaurants = mappedRests;

    self.refresh = function () {
    updateRestaurantsList(); //Method executes AJAX and saves result to session.
    var mappedRests2 = $.map($.parseJSON(sessionStorage.getItem('searchResults')), function (item) { return new Restaurant(item) });
    self.restaurants= mappedRests2;
}

}

What am I missing here?

Thanks

Upvotes: 0

Views: 1927

Answers (2)

300 baud
300 baud

Reputation: 1672

updateRestaurantsList(); //Method executes AJAX and saves result to session.

The comment after the above line indicates that this method is making an asynchronous call. Therefore, it is likely that the line after it is executing before sessionStorage has been populated. Maybe consider having updateRestaurantsList return a promise. Then you could update your code to something like this:

updateRestaurantsList().then(function() {
    var mappedRests2 = $.map($.parseJSON(sessionStorage.getItem('searchResults')), function (item) { return new Restaurant(item) });
    self.restaurants= mappedRests2;
});

This way the call to populate your mappedRests2 variable won't happen until after your updateRestaurantsList method has completed.

Edit 1

Be sure to never assign values to an observable using an equal sign.

// Overall viewmodel for this screen, along with initial state
 function RestaurantsListViewModel() {
     var self = this;
     self.restaurants = ko.observableArray([]);

     var mappedRests = $.map($.parseJSON(sessionStorage.getItem('searchResults')),     function (item) { return new Restaurant(item) });
      self.restaurants(mappedRests);

      self.refresh = function () {

    var latitude = sessionStorage.getItem('latitude');
    var longitude = sessionStorage.getItem('longitude');
    var query = '{"Accepts_Reservations":"' + $('#chkReservation').is(":checked") + '","Accepts_Cards":' + $('#chkAcceptsCards').is(":checked") + '"}';
    var searchResults = getRestaurantsAdvancedSearchAJAX(query, latitude, longitude, 40);

    searchResults.success(function (data) {
        var information = data.d;

        var mappedRests2 = $.map($.parseJSON(information), function (item) { return new Restaurant(item) });

        self.restaurants(mappedRests2);
    });

  };
};

Upvotes: 0

goran85
goran85

Reputation: 503

I have tried waiting for AJAX to finish like this:

 // Overall viewmodel for this screen, along with initial state
 function RestaurantsListViewModel() {
     var self = this;
     self.restaurants = ko.observableArray([]);

     var mappedRests = $.map($.parseJSON(sessionStorage.getItem('searchResults')),     function (item) { return new Restaurant(item) });
      self.restaurants = mappedRests;

      self.refresh = function () {

    var latitude = sessionStorage.getItem('latitude');
    var longitude = sessionStorage.getItem('longitude');
    var query = '{"Accepts_Reservations":"' + $('#chkReservation').is(":checked") + '","Accepts_Cards":' + $('#chkAcceptsCards').is(":checked") + '"}';
    var searchResults = getRestaurantsAdvancedSearchAJAX(query, latitude, longitude, 40);

    searchResults.success(function (data) {
        var information = data.d;

        var mappedRests2 = $.map($.parseJSON(information), function (item) { return new Restaurant(item) });

        self.restaurants = mappedRests2;
    });

  };
};

Edit 1

Once you have declared your observable like so:

self.restaurants = ko.observableArray([]);

When you want to update restaurants you cannot do this:

self.restaurants = mappedRests2;

Instead, you need to do this:

self.restaurants(mappedRests2);

Upvotes: 1

Related Questions