I have a viewModel with a Title
property. I'd like to set the page title using that property. Here's what I tried already, which didn't work:
<html>
<head>
<title data-bind="text: Title"></title>
</head>
<body>
<span data-bind="text: Title"/> <!-- this displays the title properly -->
</body>
The browser title is blank/default instead of the value of my Title
property.
Try giving your html element an id
<html id="htmlTop" xmlns="http://www.w3.org/1999/xhtml">
and applying your viewModel to it
ko.applyBindings(viewModel, document.getElementById("htmlTop"));
EDIT
This works for me; I just ran this page and the title said "Hello". Double check your code for typos.
<html id="htmlTop">
<head>
<title data-bind="text: title"></title>
<script type='text/javascript' src='jquery.min.js'></script>
<script type='text/javascript' src='knockout-1.2.1.js'></script>
<script type="text/javascript">
$(function () {
var viewModel = { title: "Hello" };
ko.applyBindings(viewModel, document.getElementById("htmlTop"));
});
</script>
</head>
<body>
</body>
</html>
Screenshot:
In my eyes, this situations begs for an observable subscription.
...
<title>{FALL BACK TEXT}</title>
...
View Model
ViewModel = function() {
var self = this;
self.PageTitle = ko.observable(null);
self.PageTitle.subscribe(function(newValue){ document.title = self.PageTitle() });
//change PageTitle to see your handy work in action
self.PageTitle("Hello World!");
};
EDIT: As an amendment to my previous answer, I'd like to put forth the following. Will my previous suggestion work? Yes, it works very nicely. However, DOM manipulation within the view model itself does not "exactly" follow the MVVM paradigm. The actual "best" approach would be to create a custom binding, which sets the document title on update of a particular observable.
...
<title data-bind="htmlDocumentTitle: PageTitle()">{FALLBACK TEXT}</title>
...
View Model
ViewModel = function() {
var self = this;
self.PageTitle = ko.observable(null);
self.init = function(){
self.PageTitle("My page title from an obersvable");
};
//init the viewmodel
self.init();
};
And finally our shiny custom binding to "listen" for changes to the observable (note the use of ONLY the update action)
ko.bindingHandlers.htmlDocumentTitle = {
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var fallbackTitle = "My document title";
var title = ko.unwrap(valueAccessor());
if(!title || title == null && title == "")
title = fallbackTitle;
document.title = title;
}
};
At first glance this solution may appear less scalable, but do keep in mind that we can create "pseudo-inheritance" with Knockout View Models using "call()".
You could create a custom binding handler which sets document.title
on update, then add the binding to the body
element.
You can use knockout subscribe:
function viewModel() {
var self = this;
self.title = ko.observable(null);
self.title.subscribe(function(newTitle) {
document.title = newTitle;
})
}
var vm = new viewModel();
ko.applyBindings(vm);
vm.title('Hello page');
As per @Douglas's suggestion, my solution was to add a hidden div
somewhere in the body bound to a computed value:
<div data-bind="text: currentPageTitle()"></div>
Then, in the value computation, I set the document.title
:
self.currentPageTitle = ko.computed(function() {
document.title = self.Title();
return self.Title();
}, this);
This works perfectly for me