Search code examples
knockout.jsmeta-tags

How can I use data-bind for meta content in the header?


I have a list of items on a page, that when selected will take the user to that specific item page. Each page needs a meta tag with the item name and number. The page that is generated for each item is dynamic. I have been trying to use the Knockout bindings with no luck.

<meta name="DocumentType" content="ITEM">
<meta name="Number" data-bind="text: itemNumber">
<meta name="Name" data-bind="text: itemName">

In the rest of the page, I have been using data binding successfully using a view model and applyBindings. I have included the itemName and itemNumber to the view model, so they will return results. At this point, how can I data-bind the data to my meta tags?

I have tried to follow the documentation for Knockout using the attr tag: http://knockoutjs.com/documentation/attr-binding.html

I have also tried to do what was done for binding to the html title here: Is there a way to set the page title by data-binding using Knockout.js?

I haven't had any luck with those. I could be doing them wrong, but any help is appreciated.


Solution

  • I solved this problem by applying the data bindings on the head element or you could also apply it on the html element as Chris Knoll mentioned in a previous answer.

    Then proceeded to add the "text" binding to the title element:

    <title data-bind="text: title"></title>
    

    To bind a value to the content attribute of a meta tag a I created a custom binding:

    // extra custom binding to bind content attribute of meta element
    ko.bindingHandlers.metaContent = {
        update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
            // This will be called once when the binding is first applied to an element,
            // and again whenever any observables/computeds that are accessed change
            // Update the DOM element based on the supplied values here.
            let contentAttribute = 'content';
            if (contentAttribute in element) {
                let value = valueAccessor();
                let valueUnwrapped = ko.unwrap(value);
    
                if (valueUnwrapped)
                    element.content = valueUnwrapped;
            }
        }
    };
    

    The meta element with data binding for the content attribute using the custom binding:

    <meta name="description" data-bind="metaContent: description" />
    

    For completeness my viewmodel:

    export class Head {
        public title: KnockoutObservable<string> = ko.observable("My title");        
        public description: KnockoutObservable<string> = ko.observable("My description");
    
        constructor() {            
            ko.applyBindings(this, $("head")[0]);
        }
    }