Search code examples
typescriptdata-bindingknockout.jsjavascript-databindingknockout-3.4

Knockout binding fontawesome class


Exmaple of posted code

Hello,

I have a problem with binding CSS class of font-awesome into an tag.

HTML:

    <div class="flex-no-shrink">
        <div class="btn-group">
            <div data-bind="foreach: toolbarButtons">
                <button type="button" class="btn btn-xs btn-primary" data-bind="enable: enabled, visible: visible, click: onClick">
                   <i class="fa" data-bind="css: { class: icon }"></i>
                    <!-- <i class="fa fa-plus"></i> -->
                </button>
                  <button type="button" class="btn btn-xs btn-primary" data-bind="enable: enabled, visible: visible, click: onClick">
                     <i class="fa fa-plus"></i>
                </button>
            </div>
        </div>
    </div>

TS:

interface IToolbarButton {
    enabled: KnockoutComputed<boolean>;
    visible: KnockoutComputed<boolean>;
    icon: string;
    onClick();
}

export abstract class ViewModel {
       toolbarButtons: IToolbarButton[];

   constructor(){
   this.loadDefaultToolbar();
   }
   loadDefaultToolbar(): void {
        this.toolbarButtons = [];
        //add button
        this.toolbarButtons.push({
            enabled: knockout.pureComputed(() => true/*some internal logic*/),
            icon: 'fa fa-plus',//this is what I want to place inside <i> tag
            onClick: () => {/*some internal logic*/},
            visible: knockout.pureComputed(() => true/*some internal logic*/)
        });
        //other default buttons...
        }
};

ko.applyBindings(new ViewModel());

What is a correct way to bind in mine situation?

Exmaple of posted code

I tried base binding like text or just css: { icon } but they now work also.

Thank you for your time and help 😉


Solution

  • The css binding has two forms:

    1. One which accepts an object with classes as property names and values as boolean expressions:

      css: {className: booleanExpression}
      

      ...where className is the name of the class to include if booleanExpression is true (it will be left out if booleanExpression is false).

    2. One which lets you specify the class name(s) to include as a string:

      css: stringExpression
      

    You've sort of tried to combine the two syntaxes; you want the second one. Unlike (mis)using the attr binding, this respects other classes added to the element. This feature of the css binding is documented here and can be found in the source here.

    Live Example:

    ko.applyBindings({
      someClassName: "two",
    })
    .one { background: yellow; }
    .two { color: red; }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
    <div class="one" data-bind="css: someClassName">
      My type is red because the view model added a class name!
    </div>

    If you'd like to see/compare more examples, please leave a comment.