Alrighty - I have been stuck fixing some legacy bugs in a project, and it's using Knockout.js. I am very unfamiliar with this library, so please excuse my ignorance.

So I have a dialog template that contains this block of HTML:

        <ul class="nav">
            <li class="active">
                <a href="#add" data-toggle="tab">Add New</a>
            </li>
            <li>
                <a href="#chooseExisting" data-toggle="tab" data-bind="text: console.log($data)"></a>
            </li>
            <!-- ko if: shouldShowMoreInfo() -->
                <li data-bind="text: console.log(shouldShowMoreInfo())">More Info</li>
            <!-- /ko -->

            // using this as a test
            <li data-bind="text: testMessage()"></li>
        </ul>

And this is the view model:

        var viewModel = {
            tabs: ko.observableArray([
                {
                    name: "Add New",
                    value: '[href="#add"]'
                },
                {
                    name: "Choose Existing",
                    value: '[href="#chooseExisting"]'
                },
            ]),
            activeTab: ko.observable(),
            shouldShowMoreInfo: ko.observable(),
            testMessage: ko.observable()
        };

        viewModel.activeTab(viewModel.tabs()[0].value);
        viewModel.shouldShowMoreInfo(false);
        viewModel.testMessage('test message');

        return viewModel;

The problem is, is that the data-bind="text: console.log($data)" in the template successfully logs out the view model, and all of its properties. I can also console log out specific property values. However, if I were to try to use them in an if or hidden statement, nothing happens.

For example in the template - you will notice I am trying to conditionally rendered the More Info tab with an if statement, however, the if statement does nothing. I can successfully log out shouldShowMoreInfo() and it will evaluate to false. I would expect the if statement to not render the <li> as result. Furthermore, the test message I am trying to render via data-bind="text" does not work, but testMessage is reachable in a console log.

I am a little confused here - it appears that the template has access to the view model, I just cannot do anything with the view model properties outside of being able to successfully console.log them.

1

There are 1 best solutions below

0
Sam On

I believe you're missing the core call to ko.applyBindings(viewModel[, domElement])

Where the 2nd parameter is optional if you want your entire dom to be bound.

The reason why you can indeed get the javascript values in the console is because you can do that always, not only when using knockout, but you need to actually call the binding to boot up the two-way binding between the view and the viewmodel.

var viewModel = {
  tabs: ko.observableArray([{
      name: "Add New",
      value: '[href="#add"]'
    },
    {
      name: "Choose Existing",
      value: '[href="#chooseExisting"]'
    },
  ]),
  activeTab: ko.observable(),
  shouldShowMoreInfo: ko.observable(),
  testMessage: ko.observable()
};

viewModel.activeTab(viewModel.tabs()[0].value);
viewModel.shouldShowMoreInfo(false);
viewModel.testMessage('test message');

ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.1/knockout-latest.js" integrity="sha512-2AL/VEauKkZqQU9BHgnv48OhXcJPx9vdzxN1JrKDVc4FPU/MEE/BZ6d9l0mP7VmvLsjtYwqiYQpDskK9dG8KBA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

<ul class="nav">
  <li class="active">
    <a href="#add" data-toggle="tab">Add New</a>
  </li>
  <li>
    <a href="#chooseExisting" data-toggle="tab" data-bind="text: $data"></a>
  </li>
  <!-- ko if: shouldShowMoreInfo() -->
  <li data-bind="text: shouldShowMoreInfo()">More Info</li>
  <!-- /ko -->

  // using this as a test
  <li data-bind="text: testMessage()"></li>
</ul>


<button data-bind="click: () => shouldShowMoreInfo(!shouldShowMoreInfo())">
toggle
</button>