0
votes

I'm shifting to Knockout from JQuery bindings to make UI synchronization with data easier. I am fairly new to knockout but to keep things tidy I'm using knockout with Requirejs.

So in one of my modules I tried to use templates to change the information bar and bound the template name to a computed observable. But the computed observable is not updating the template name in the UI.

<div data-bind="template: { name: baseData.printListTemplate }"></div>

<script type="text/html" id="inPrintList">
    <span>
        <span>In </span>
        <a href="#" class="managePrintList">Print List</a>
    </span>

    <a href="#" data-bind="click: switchInPrintList">sw</a>
</script>

<script type="text/html" id="notInPrintList">
    <span>
        <span>Add to </span>
        <a href="#" class="managePrintList">Print List</a>
    </span>

    <a href="#" data-bind="click: switchInPrintList">sw</a>
</script>

Above is my html code and Knockout templates.

Following code is my Knockout module

Inside the baseData I have printListTemplate computed observable returning the templatename to use for print list indicator.

switchInPrintList changes the inPrintList observable and after the change ko.computed function runs and it returns the correct string but the UI is not updated after these.

define(['knockout', 'Modules/utils', 'Modules/Shared/kodialog'],
    function (ko, utils, kodialog) {

        var baseData = function (data) {
            var self = this;

            self.inPrintList = ko.observable(false);

            ko.mapping.fromJS(data, {}, self);

            self.printListTemplate = ko.computed(function () {
                if (self.inPrintList())
                    return "inPrintList";
                else
                    return "notInPrintList";
            }, this);
        }

        var baseDataMapping = {
            create: function (options) {
                return new baseData(options.data);
            }
        }

        return function player() {
            var self = this;

            var utils = new utils();

            self.baseData = new baseData();

            self.dialog = new kodialog();

            self.renderMP = function (contentId) {
                self.dialog.openDialog();
                $.ajax({
                    type: "GET",
                    url: "/Home/mpdata",
                    dataType: 'json',
                    crossDomain: true,
                    data: { contentid: contentId },
                    success: function (jsonResult) {
                        self.baseData = ko.mapping.fromJS(jsonResult, baseDataMapping);
                        self.dialog.rendered(true);
                    }
                });
            }
            self.switchInPrintList = function () {
                if (self.baseData.inPrintList())
                    self.baseData.inPrintList(false);
                else
                    self.baseData.inPrintList(true);
            }
        }
    });
1
Seems fine to me. Here is a fiddle with your code in it, working. - Joe Daley
Well i guess the mapping plugin ruins the bindings. Any thoughts why? - Azadrum
I removed baseDataMapping and set the server data manually and it works fine now as your fiddle example suggests. - Azadrum
@Azadrum, have you solved the issue? - Ilya Luzyanin
@Ilya Luzyanin, well kindda solved... when i got rid of mapping and done the binding manually it worked. I tried your solution too but it was the same. I think i need some more time to understand how knockout bindings work so i bypassed the issue to make things move. - Azadrum

1 Answers

1
votes

I think the problem is that you're reassigning baseData in your success callback, when you need only to update it's properties accordingly. For this case there is another overload of ko.mapping.fromJS() method, which takes the third parameter as update target which properties should be updated. See documentation, "specifying update target".

So try to rewrite your success callback like this:

success: function (jsonResult) {
    ko.mapping.fromJS(jsonResult, baseDataMapping, self.baseData);
    self.dialog.rendered(true);
}