Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

KO Computed not updating UI

I am still fairly new to knockout and I am trying to display and hide bootstrap tabs using knockout.

basically I have a computed observable:

self.isActive = ko.computed(function () {
            var selected = ko.utils.arrayFirst(self.padParticipant(), function (item) {
                return item.ParticipationStatus == 'Active';
            });
            return selected !== null ? true : false;
        });

to update these tabs:

<ul class="nav nav-tabs" id="padTabs">
        <li data-bind="fadeVisible: !isActive()"><a href="#joinPad">Join PAD</a></li>
       <li class="active"><a href="#history">History</a></li>
       <li data-bind="fadeVisible: isActive()"><a href="#update">Update Subscription</a></li>
</ul>

The computed is working correctly in the sense that when I refresh the page the correct tabs are hidden, but I need it to work without refreshing.

like image 453
ThreadedLemon Avatar asked Jan 14 '23 20:01

ThreadedLemon


1 Answers

The issue has to do with understanding what is happening in the Knockout framework when you use computed observables in addition to the rules of observable arrays. First let's look at a note about observable arrays:

Key point: An observableArray tracks which objects are in the array not the state of those objects

Simply putting an object into an observableArray doesn’t make all of that object’s properties themselves observable. Of course, you can make those properties observable if you wish, but that’s an independent choice. An observableArray just tracks which objects it holds, and notifies listeners when objects are added or removed.

This is the same cautionary mistake you are making in this line of code, since this isn't an observable, rather just a property of an object in the array,: return item.ParticipationStatus == 'Active';

Furthermore, we need to understand how a computed observable operates:

  1. Whenever you declare a computed observable, KO immediately invokes its evaluator function to get its initial value.

  2. While your evaluator function is running, KO keeps a log of any observables (or computed observables) that your evaluator reads the value of.

  3. When your evaluator is finished, KO sets up subscriptions to each of the observables (or computed observables) that you’ve touched. The subscription callback is set to cause your evaluator to run again, looping the whole process back to step 1 (disposing of any old subscriptions that no longer apply).

  4. KO notifies any subscribers about the new value of your computed observable.

So when you made your computed observable, the only subscription that was created to watch for changes was one to the observable array self.padParticipant().

Since the UI change of state is dependent upon the ParticipationStatus changing, this means this property needs to be an observable element within each object in the array, otherwise when it's state changes, there will be no way for the computed to be aware of that change and update the UI.

like image 50
Matthew Cox Avatar answered Jan 19 '23 10:01

Matthew Cox