knockoutjs automatically tracks the dependencies when the values get updated. it has a single object called dependency tracker (ko.dependencydetection) which acts as an intermediate between the two parties for subscribing the dependencies.
following is the algorithm for dependency tracking.
step 1 − whenever you declare a computed observable, ko immediately invokes its evaluator function to get its initial value.
step 2 − subscription is set up to any observable that the evaluator reads. in an application, the old subscriptions which are no longer used are disposed.
step 3 − ko finally notifies the updated computed observable.
example
<!doctype html>
<html>
<head>
<title>knockoutjs how dependency tracking works</title>
<!-- cdn's-->
<script src = "https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.1.0.js"
type = "text/javascript"></script>
</head>
<body>
<div>
<form data-bind = "submit: addfruits">
<b>add fruits:</b>
<input data-bind = 'value: fruittoadd, valueupdate: "afterkeydown"'/>
<button type = "submit" data-bind = "enable: fruittoadd().length > 0">add</button>
<p><b>your fruits list:</b></p>
<select multiple = "multiple" width = "50" data-bind = "options: fruits"> </select>
</form>
</div>
<script>
var addfruit = function(fruits) {
this.fruits = ko.observablearray(fruits);
this.fruittoadd = ko.observable("");
this.addfruits = function() {
if (this.fruittoadd() != "") {
this.fruits.push(this.fruittoadd()); // adds a fruit
this.fruittoadd(""); // clears the text box
}
}.bind(this); // "this" is the view model
};
ko.applybindings(new addfruit(["apple", "orange", "banana"]));
</script>
</body>
</html>
output
let's carry out the following steps to see how the above code works −
save the above code in dependency_tracking.htm file.
open this html file in a browser.
enter any fruit name and click the add button.
controlling dependencies using peek
the computed observable can be accessed without creating a dependency, by using the peek function. it controls the observable by updating the computed property.
example
<!doctype html>
<html>
<head>
<title>knockoutjs controlling dependencies using peek</title>
<!-- cdn's-->
<script src = "https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.1.0.js"
type = "text/javascript"></script>
</head>
<body>
<div class = "logblock">
<h3>computed log</h3>
<pre class = "log" data-bind = "html: computedlog"></pre>
</div>
<script>
function appdata() {
this.firstname = ko.observable('john');
this.lastname = ko.observable('burns');
this.computedlog = ko.observable('log: ');
this.fullname = ko.computed(function () {
var value = this.firstname() + " " + this.lastname();
this.computedlog(this.computedlog.peek() + value + '; <br/>');
return value;
}, this);
this.step = ko.observable(0);
this.next = function () {
this.step(this.step() === 2 ? 0 : this.step()+1);
};
};
ko.applybindings(new appdata());
</script>
</body>
</html>
output
let's carry out the following steps to see how the above code works −
save the above code in dependency_tracking_peek.htm file.
open this html file in a browser.
observations
ignoring dependencies within a computed dependency
the ko.ignoredependencies function helps ignore those dependencies that you don't want to track within the computed dependencies. following is its syntax.
ko.ignoredependencies( callback, callbacktarget, callbackargs );
why circular dependencies aren't meaningful
if ko is evaluating a computed observable, then it will not restart an evaluation of the dependent computed observable. hence, it doesn't make sense to include cycles in your dependency chains.