I am using Knockout.js to build a client-side view model. In my view model I would like to expose some functions that can be bound to elements in the page (typical MVVM model). I only want these functions to be called in response to a click event from a button, however they are been called when the view model is been constructed...
I have defined my model like this:
<script type="text/javascript">
var ViewModel = function(initialData) {
    var self = this;
    self.id = initialData;
    self.isSubscribed = ko.observable(false);
    self.name = ko.observable();
    self.SubscribeToCategory = function () {
        $.ajax({
            url: '@Url.Action("Subscribe", "Category")',
            type: 'POST',
            data: {
                categoryId: self.id
            },
            success: function () {
                self.isSubscribed(true);
            },
            failure: function () {
                self.isSubscribed(false);
            }
        });
        alert('Subscribing...');
    };
    self.UnsubscribeFromCategory = function () {
        $.ajax({
            url: '@Url.Action("Unsubscribe", "Category")',
            type: 'POST',
            data: {
                categoryId: self.id
            },
            success: function () {
                self.isSubscribed(false);
            },
            failure: function () {
                self.isSubscribed(true);
            }
        }); 
        alert('Unsubscribing...');
    };
    self.LoadCategory = function () {
        $.ajax({
            url: '@Url.Action("GetCategory", "Category")',
            type: 'POST',
            async: true,
            data: {
                categoryId: self.id
            },
            dataType: 'json',
            success: function (data) {
                self.isSubscribed(data.IsSubscribed);
                self.name(data.Name);
            }
        });
    };
    self.LoadCategory();
};
$(document).ready(function () {
    var data = '@Model';
    var viewModel = new ViewModel(data);
    ko.applyBindings(viewModel);
});
When I execute the code however, the two alerts fire automatically, but I am not expecting them to. I am using ASP MVC4, and the HTML that is using the view model is below:
<p>
    ID: <span data-bind="text: id"></span>
</p>
<div id="subscribe" data-bind="visible: isSubscribed == false">
    <button data-bind="click: SubscribeToCategory()">Subscribe</button>
</div>
<div id="unsubscribe" data-bind="visible: isSubscribed == true">
    <button data-bind="click: UnsubscribeFromCategory()">Unsubscribe</button>
</div>
<div>
    Category Name: <span data-bind="text: name"></span>
    Is Subscribed: <span data-bind="text: isSubscribed"></span>
</div>
I've looked through the tutorials online and some other knockout samples, as well as other places in my code where I have used knockout, but I cannot see why the two functions (SubscribeToCategory and UnsubscribeFromCategory) are firing on document load.
To activate Knockout, add the following line to a <script> block: ko. applyBindings(myViewModel); You can either put the script block at the bottom of your HTML document, or you can put it at the top and wrap the contents in a DOM-ready handler such as jQuery's $ function.
KnockoutJS is far from dead, and it's actually still being improved and evolved (see Technical Knockout) but newer frameworks seem a far better bet for our needs, considering activity and performance.
$root. This is the main view model object in the root context, i.e., the topmost parent context. It's usually the object that was passed to ko. applyBindings . It is equivalent to $parents[$parents.
ko. computed( evaluator [, targetObject, options] ) — This form supports the most common case of creating a computed observable. evaluator — A function that is used to evaluate the computed observable's current value. targetObject — If given, defines the value of this whenever KO invokes your callback functions.
jsfiddle
It took me a second, but ended up being a simple fix. remove the () from your data-bind="click: SubscribeToCategory()" and make both you click handlers this data-bind="click: SubscribeToCategory" and data-bind="click: UnsubscribeFromCategory"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With