andrey.shedko
andrey.shedko

Reputation: 3238

Knockout.js click binding strange behavior

I got some click binding, that must pass binding context value to the self function for further processing and this value has been passing successfully but function firing on page load instead of click. So, here is ViewModel:

<script src="../Scripts/knockout.mapping-latest.js"></script>
    <script>
        function UserStatusViewModel() {
            var self = this;
            self.clients = ko.observableArray();
            $.getJSON("/api/users", self.clients);
            self.updatestatus = function () {
                $.getJSON("/api/users", function (data) {
                    ko.mapping.fromJS(data, {}, self.clients);
                });
            }
            //Here I'm getting correct data fom click binding context, but this happend on page load, not on click
            self.modal = function (un) {
                localStorage.clear();
                localStorage.setItem("speakto", un);
                window.location.replace("http://somehost/operator/dialog");
            }
        };
        $(function () {
            var vm = new UserStatusViewModel();
            ko.applyBindings(vm, document.getElementById('users'));
            var chat = $.connection.chatHub;
            chat.client.addChatMessage = function (name, message) {
                vm.updatestatus();
            };
            chat.client.updateStatus = function () {
                vm.updatestatus();
            }
            chat.server.userStatus = function () {
                vm.updatestatus();
            }
            $.connection.hub.start().done(function () {
            });
        });
    </script>

And HTML markup:

<div data-bind="foreach: clients" id="users">
    <div class="dialogs">
        <div class="speech">
            <div class="online">
                <img alt="" data-bind="visible: ko.utils.unwrapObservable(IsOnline) == true" src="../img/online.png">
                <img alt="" data-bind="visible: ko.utils.unwrapObservable(IsOnline) == false" src="../img/offline.png">
            </div>
            <div class="ava">
                <img alt="" data-bind="attr: { src: ko.utils.unwrapObservable(AvaUrl) }">
            </div>
            <div class="name" data-bind="text: ko.utils.unwrapObservable(UserName), click: $root.modal(UserName)"></div>
            <%--<div class="dateok" data-bind="text: $data.Timer"></div>--%>
            <div class="text" data-bind="text: ko.utils.unwrapObservable(LastMessage)"></div>
        </div>
    </div>
</div>  

P.S. Sorry guys, I did changed click binding syntax too fast, current is newest and the one I'm talking about.

Upvotes: 1

Views: 289

Answers (2)

TSV
TSV

Reputation: 7641

let viewModel in JS is defined as:

viewModel = {
    clickHandler: function(model, e) { alert(JSON.stringify(model)); }
}

then you can bind it the following way in markup:

data-bind="click: clickHandler"

if you click it, the $data will be passed as "model" argument of the handler

It is described at the knockout docs

Upvotes: 0

nemesv
nemesv

Reputation: 139748

Your click binding click: $root.modal(UserName) is wrong because you are not passing in a function but the result of the function. So KO will execute your function once when it processes the binding and not when your element is clicked.

You need to use bind or wrap it into a new function if you want to pass in additional arguments to a click handler:

<div class="name" data-bind="text: ko.utils.unwrapObservable(UserName), 
                                   click: $root.modal.bind($data, UserName)"></div>

Or

<div class="name" data-bind="text: ko.utils.unwrapObservable(UserName), 
                            click: function() { $root.modal(UserName) }"></div>

Note: you don't need the ko.utils.unwrapObservable(UserName) in text binding just write text: UserName

However because your UserName is observable you need to handle it in your modal function:

self.modal = function (un) {
    localStorage.clear();
    localStorage.setItem("speakto", ko.utils.unwrapObservable(un));
    window.location.replace("http://somehost/operator/dialog");
}

Or make sure that the click binding passes in the value with click: $root.modal.bind($data, ko.utils.unwrapObservable(UserName))

Note: since KO 2.3 there is shorthand for ko.utils.unwrapObservable and you can just write ko.unwrap

Upvotes: 3

Related Questions