0

Using jquerymobile and knockout, I am trying to create a custom binding that looks as follows

<ul data-bind="listview: observablearray">
    <li data-bind="text: text"></li>
</ul>

where the listview binding would first act like a foreach binding and then apply $(element).listview() to it (or $(element).listview('refresh') on an update).

I tried doing the following to naively imitate the foreach binding:

ko.bindingHandlers.listview = {
  init: function (element, valueAccessor) {
    var listview = $(element);
    listview.listview();
  },
  update: function (element, valueAccessor) {
    var listview = $(element);
    setTimeout(function () {
      listview.html('');
      var items = valueAccessor().list;
      var link = valueAccessor().link;
      var text = valueAccessor().text;
      var icon = valueAccessor().icon;
      $.each(ko.utils.unwrapObservable(items) || [], function (i, item) {
        var li = $('<li></li>').css({
          height: '44px'
        })
        var a;
        if (link) {
          a = $('<a href="#"></a>').click(function () {
            link(item)
          });
          li.append(a);
        }
        if (icon) {
          (a || li).append($('<img />').attr('src', icon(item)).addClass('ui-li-icon'));
        }
        if (text) {
          (a || li).append($('<span></span>').text(item[text]));
        }
        listview.append(li);
      });
      listview.listview('refresh')
    }, 0);
  }
};

Unfortunately, not only was this a poor implementation that didn't use templating, it also through an error on init:

Uncaught TypeError: Cannot read property 'jQuery19101983379740267992' of undefined

Thanks in advance!

MikO
  • 18,243
  • 12
  • 77
  • 109
Matthew James Davis
  • 12,134
  • 7
  • 61
  • 90
  • 1
    Perhaps this (http://stackoverflow.com/questions/15702996/jquery-mobile-with-knockoutjs-listview-issue/15717480#15717480) can help you... – gbs Apr 08 '13 at 18:32
  • it does, although i'm interested in the inner workings of knockout, specifically how to manually render an anonymous template – Matthew James Davis Apr 08 '13 at 18:46

2 Answers2

0

You can call internal knockout bindings from withing your bindings.

In your case this should work.

ko.bindingHandlers.listview = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var res = ko.bindingHandlers.foreach.init(element, valueAccessor()['listview']);
        $(element).listview();
        return res;
    },
    update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var res = ko.bindingHandlers.foreach.update(element, valueAccessor()['listview'], allBindingsAccessor, viewModel, bindingContext);
        $(element).listview('refresh');
        return res;
    }
};

Rendering templates on your own is quite a challenge, your are better off using the internal 'template' binding. The 'foreach' binding does so too. Look in the knockoutjs code to see how its done.

Angel Yordanov
  • 3,112
  • 1
  • 22
  • 19
0

For me the quickest and elegant way to work with dinamic jQueryMobile listview is to subscribe to models changes, something like this:

viewModel.products.subscribe(function() {
    jQuery("#productsList").listview("refresh");  
});
Dario Barilà
  • 515
  • 6
  • 5