Sreekumar P
Sreekumar P

Reputation: 6050

How to Change viewmodel's data after binding a knockout template to a custom component

I have a static template binding to a custom component in KnockoutJS. The ViewModel data is initialized and is working fine (getting John Smith in output).

$(document).ready(function() {
  var viewModel = function() {
    this.name = ko.observable('John Smith');
  }
  var viewModelObject = new viewModel();

  ko.components.register('my-component', {
    viewModel: viewModel,
    template: 'Name: <input data-bind="value: name" /> '
  });

  viewModelObject.name('Smith John');
  ko.applyBindings(viewModelObject);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div>
  <my-component></my-component>
</div>

JSFiddle: http://jsfiddle.net/17cmjptL/1/

Here, I am trying to change the value in my ViewModel. I know there is know use of passing the viewModelObject to the ko.applyBindings method. But just tried.

Can anybody help on, how to change viewmodel data without rebinding. ?

ie. I want to get the output as Smith John.

Upvotes: 0

Views: 1004

Answers (1)

Kyeotic
Kyeotic

Reputation: 19847

I think you misunderstand how components are intended to be used. Components are a way to get custom elements with their own internal behavior. You interact with components via their parameters, not by directly controlling the components viewmodel.

First, let's look at what is going on with your code. You correctly create a constructor function for your component viewmodel, and register it to your component. This function will be run every time a component is instantiated: each component will get its own instance of this object.

Then you construct your own instance of this viewmodel, set its name, and bind it. Knockout creates an instance of your component because a custom element exists, but no parameters are on it. Your constructor function is run, getting the default name, and this is bound to an input. The viewmodel you called applyBindings with is not used for anything, because the component got its own instance of the viewmodel.

What you want to do is create a viewmodel that passes a name to your component via params. Then you can control this viewmodel, which will in turn affect your component. It might look something like this

var componentVm = function (params) {
    this.name = params.name;
}

ko.components.register('my-component', {
    viewModel: componentVm,
    template: 'Name: <input data-bind="value: name" /> '
});

var vm = {
    name: ko.observable("John Smith"),
    updateName: function() {
         this.name("Smith John");   
    }
};
ko.applyBindings(vm);

<div>
    <my-component params="name: name"></my-component>
    <button data-bind="click: updateName">Update</button>
</div>

Here is a fiddle you can play with.

Upvotes: 1

Related Questions