How to have both visible and template binding for Knockout.js

2.8k views Asked by At

What is the right way to have different bindings on the same target in Knockout.

These didn't seem to work:

<div data-bind="template: { name: 'voucher-template', foreach: voucher }" data-bind="visible: showVoucher"></div>

or

<div data-bind="template: { name: 'voucher-template', foreach: voucher }, visible: showVoucher"></div>

Full Test code:

<script>

        function VoucherViewModel() {
            this.voucher = [
            {
                VoucherNumber: "100000",
                VoucherImage: "someurl",
                VoucherExpiry: "20/3/12",
                VoucherRedeemed: true,
                VoucherDesc: "ddwqdwqdwqd",
                VoucherPuchaseDate: "20/12/11",
                VoucherPrice: "50"
            }, 
            {
                VoucherNumber: "200000",
                VoucherImage: "someurl",
                VoucherExpiry: "20/3/12",
                VoucherRedeemed: true,
                VoucherDesc: "ddwqdwqdwqd",
                VoucherPuchaseDate: "20/12/11",
                VoucherPrice: "50"
            }]
        };

        var viewModel = {
            showVoucher: ko.observable(true)
        };

        $(function () {

            //VIEWMODEL
            ko.applyBindings(viewModel);

            //TEMPLATES
            ko.applyBindings(new VoucherViewModel());

        });
    </script>






<div data-bind="template: { name: 'voucher-template', foreach: voucher }, visible: showVoucher"></div>        
<script type="text/html" id="voucher-template">
<h3 data-bind="text: VoucherNumber"></h3>
</script>
3

There are 3 answers

2
bcm On BEST ANSWER

Seems like the double ko.applyBindings is causing an issue.

This worked:

$(function () {

            var viewModel = {
                showVoucher: ko.observable(true),
                voucher: ko.observableArray([
                    {
                        VoucherNumber: "100000",
                        VoucherImage: "someurl",
                        VoucherExpiry: "20/3/12",
                        VoucherRedeemed: true,
                        VoucherDesc: "ddwqdwqdwqd",
                        VoucherPuchaseDate: "20/12/11",
                        VoucherPrice: "50"
                    },
                    {
                        VoucherNumber: "200000",
                        VoucherImage: "someurl",
                        VoucherExpiry: "20/3/12",
                        VoucherRedeemed: true,
                        VoucherDesc: "ddwqdwqdwqd",
                        VoucherPuchaseDate: "20/12/11",
                        VoucherPrice: "50"
                    }
                ])
            };

            //VIEWMODEL
            ko.applyBindings(viewModel);    


        });

If there is a better way to write this, please let me know.

Edited version below, also trying out mapping:

<script>

        function getVoucherData() {
            //some ajax call;

            return data = { "voucher" : [{
                VoucherTitle: "Offer title 1",
                VoucherNumber: "100000",
                VoucherImage: "someurl",
                VoucherExpiry: "20/3/12",
                VoucherRedeemed: true,
                VoucherDesc: "ddwqdwqdwqd",
                VoucherPuchaseDate: "20/12/11",
                VoucherPrice: "50"
            },
            {
                VoucherTitle: "Offer title 2",
                VoucherNumber: "200000",
                VoucherImage: "someurl",
                VoucherExpiry: "20/3/12",
                VoucherRedeemed: true,
                VoucherDesc: "ddwqdwqdwqd",
                VoucherPuchaseDate: "20/12/11",
                VoucherPrice: "50"
            }]
            };
        }

        function initViewModel() {
            var viewModel = {};

           // PAGE SETUP
           viewModel.showVoucher = ko.observable(true);
           viewModel.showMyAccount = ko.observable(false);

           // GET VOUCHER
           var voucherData = getVoucherData();
           voucherData.voucher.sort(function (left, right) {
                return left.VoucherNumber > right.VoucherNumber
           });
           viewModel.voucher = ko.mapping.fromJS(voucherData.voucher);

           // START
           ko.applyBindings(viewModel);
       }

       $(function () {
           initViewModel();        
       });
    </script>
0
soniiic On

This is what I would recommend and as far as I understand it is best practise. This is because you set a structure on the viewModel within the function rather than appending later which is easier to read.

$(function () {
    function MyViewModel() {
        // data
        this.showVoucher = ko.observable(true);
        this.showMyAccount = ko.observable(false);
        this.voucher = ko.observableArray([]);
    }

    window.activeViewModel = new MyViewModel();
    ko.applyBindings(window.activeViewModel);

    // GET VOUCHERS
    var voucherData = getVoucherData();
    window.activeViewModel.voucher(voucherData.voucher)
});
3
RP Niemeyer On

You specify multiple bindings in Knockout by separating them with a comma (it is essentially a JavaScript object literal) in the same data-bind attribute. So, you will want to do:

data-bind="bindingOne: valueOne, bindingTwo: { valueTwo: 'two' }, bindingThree: valueThree"