Is there a way to set the page title by data-bindi

2019-01-19 10:31发布

问题:

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.

回答1:

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:



回答2:

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()".



回答3:

You could create a custom binding handler which sets document.title on update, then add the binding to the body element.



回答4:

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');


回答5:

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