Search code examples
knockout.jsknockout-componentsknockout-es5-plugin

Cannot write to an observable received as param inside of knockoutjs component


KO components receives a reference of observable when we passes it as params. As componentes receives it as a reference you can write to this observable and it will reflect on your viewmodel; But, when you using ko-es5 plugin (super awesome) your KO component instead of receive also a reference to your observable receives some kind of computeObservable, and we cant write to it. is this a unexpected behaviour ?

try it using only knockout

http://jsfiddle.net/kapuca/k0fw8w18/

<voting params="votes: votes"></voting>

<template id="voting-tpl">
    <button data-bind="click: increment ">Up</button>
    <div data-bind="text: votes"></div>
</template>

ko.components.register('voting', {
    viewModel: function(params) {
        var self        = this;
        self.votes      = params.votes;

        self.increment  = function(){
            self.votes( self.votes() + 1 );
        };

        return self;
    },
    template: { element: 'voting-tpl' }
});

function Vm(){
    this.votes = ko.observable(5);
    return this;
}

ko.applyBindings(new Vm() );

try it using knockout + ko-es5 plugin

http://jsfiddle.net/kapuca/jwea6zaL/

<voting params="votes: votes"></voting>

<template id="voting-tpl">
    <button data-bind="click: increment ">Up</button>
    <div data-bind="text: votes"></div>
</template>

ko.components.register('voting', {
    viewModel: function(params) {
        var self        = this;
        self.votes      = params.votes;

        self.increment  = function(){
            self.votes( self.votes + 1 );
        };

        return ko.track(self);
    },
    template: { element: 'voting-tpl' }
});

function Vm(){
    this.votes = 5;
    return ko.track(this);
}

ko.applyBindings(new Vm() );

Solution

  • I haven't used the es5 plugin but looking at the documentation you can access the underlying observable with ko.getObservable(viewModel, 'propertyName'). So if you change your component to pass the underlying observable in its parameter that seems to bypass whatever weirdness is going on.

    <voting params="votes: ko.getObservable($data, 'votes')"></voting>
    

    You'll also want to change your increment function to use the es5 assignment instead of calling votes like a function self.votes( self.votes + 1 ); => self.votes += 1;