2014-01-21 2 views
3

Я пытаюсь динамически создавать и фильтровать мобильную группу управления jquery, содержащую флажки с использованием привязки нокаута. Основная идея заключается в том, что пользователь выбирает параметр, который фильтрует список флажков в контрольной группе. Я видел подобные вопросы здесь, но все они кажутся одноразовыми, где когда-то привязанные ko и усиленные jqm, они остаются неизменными. У меня такое поведение работает, проблема возникает, когда базовый viewModel изменяется, а ko обновляет список флажков в группе управления. Полную демонстрацию поведения можно найти на jsfiddle здесь: http://jsfiddle.net/hkrauss2/JAvLk/15/Динамическая группа управления флажком с использованием jQuery mobile и нокаутом

Я вижу, что проблема связана с тем, что jqm создает оболочку div при увеличении контрольной группы. Затем Ko добавляет новые элементы над оберткой div при обновлении DOM. В основном я спрашиваю, разрешил ли кто-либо эту проблему, а также если кто-то думает, что я прошу проблемы, интегрируя эти две библиотеки? Спасибо всем заранее.

Вот Html:

<div id="home" data-role="page"> 
<div data-role="header"> 
    <h2>Knockout Test</h2> 
</div> 
<div data-role="content"> 
    <ul id="parent-view" data-role="listview" data-inset="true" data-bind="foreach: parentCategories"> 
     <li><a href="#list" data-transition="slide" data-bind="text: description, click: $parent.OnClick"></a></li> 
    </ul> 
    <p> 
     To reproduce the issue select Restaurants, come back and select Nightlife or Bars 
    </p> 
</div> 
</div> 
<div id="list" data-role="page"> 
<div data-role="header"> 
    <h2>Knockout Test</h2> 
    <a data-rel="back" data-icon="carat-l" data-iconpos="notext">Back</a> 
</div> 
<div data-role="content"> 
    <form> 
     <div id="child-view" data-role="controlgroup" data-bind="foreach: childCategories, jqmRefreshControlGroup: childCategories"> 
      <input type="checkbox" name="checkbox-v-2a" data-bind="attr: {id: 'categoryId' + id}" /> 
      <label data-bind="text: description, attr: {for: 'categoryId' + id}" /> 
     </div> 
    </form> 
</div> 
</div> 

И основной JavaScript. Обратите внимание, что здесь нет двух внешних js-файлов. Один устанавливает $.mobile.autoInitializePage = false; на событие mobileinit. Другая информация вводится в виде массива JSON, который используется для инициализации свойства Categories в AppViewModel.

// Custom binding to handle jqm refresh 
ko.bindingHandlers.jqmRefreshControlGroup = { 
    update: function (element, valueAccessor) { 
    ko.utils.unwrapObservable(valueAccessor()); 
    try { 
     $(element).controlgroup("refresh"); 
    } catch (ex) { } 
    } 
} 
function GetView(name) { 
    return $(name).get(0); 
} 

// Define the AppViewModel 
var AppViewModel = function() { 
    var self = this; 

    self.currentParentId = ko.observable(0); 
    self.Categories = ko.observableArray(Categories); // Categories comes from sampledata.js 

    self.parentCategories = ko.computed(function() { 
    return ko.utils.arrayFilter(self.Categories(), function (item) { 
     return item.parentId == 0; 
    }); 
    }); 

    self.childCategories = ko.computed(function() { 
    return ko.utils.arrayFilter(self.Categories(), function (item) { 
     return item.parentId == self.currentParentId(); 
    }); 
    }); 

    self.OnClick = function (viewModel, $event) { 
    self.currentParentId(viewModel.id); 
    return true; 
    }; 
}; 

// Create the AppViewModel 
var viewModel = new AppViewModel(); 

// Apply bindings and initialize jqm 
$(function() { 
    ko.applyBindings(viewModel, GetView('#parent-view')); 
    ko.applyBindings(viewModel, GetView('#child-view')); 
    $.mobile.initializePage(); 
}); 

ответ

1

Update

Мой старый раствор оборачивает каждый элемент в ui-controlgroup-controls DIV, который добавляет ненужную разметку. Тем не менее, элемент является неотъемлемой частью.

$(element).enhanceWithin().controlgroup("refresh"); /* line 16 in fiddle */ 

Новое решение является более динамичным, чтобы поддерживать чистую разметку без каких-либо дополнительных оберток:

  • Первый шаг: После controlgroup создается controlgroupcreate (событие), добавьте data-bind к его Контейнер.controlgroup("container")

  • Второй этап: Добавить checkbox состоит из input и label. В то же время, для каждого элемента, добавить data-bind

  • Третий шаг: Нанести привязок ko.applyBindings().

Статическая структура controlgroup должна быть основной, он не должен содержать каких-либо элементов статически. Если установлен флажок, каждый динамически созданный checkbox будет обернут в дополнительный .ui-checkbox div.

<div id="child-view" data-role="controlgroup"> 
    <!-- nothing here --> 
</div> 

JS

$(document).on("controlgroupcreate", "#child-view", function (e) { 
    $(this) 
     .controlgroup("container") 
     .attr("data-bind", "foreach: childCategories, jqmRefreshControlGroup: childCategories") 
     .append($('<input type="checkbox" name="checkbox" />') 
     .attr("data-bind", "attr: {id: 'categoryId' + id}")) 
     .append($('<label />') 
     .attr("data-bind", "text: description, attr: {for: 'categoryId' + id}")); 
    ko.applyBindings(viewModel, GetView('#child-view')); 
}); 

Demo


Старый решение

Начиная с версии jQuery Mobile 1.4, элементы должны быть добавлены в .controlgroup("container") не до $("[data-role=controlgroup]").

Во-первых, вам нужно обернуть внутренние элементы из controlgroup в DIV с классом ui-controlgroup-controls, который действует как controlgroup контейнера.

<div id="child-view" data-role="controlgroup" data-bind="foreach: childCategories, jqmRefreshControlGroup: childCategories"> 
    <div class="ui-controlgroup-controls"> 
    <input type="checkbox" name="checkbox-v-2a" data-bind="attr: {id: 'categoryId' + id}" /> 
    <label data-bind="text: description, attr: {for: 'categoryId' + id}" /> 
    </div> 
</div> 

Второй шаг, вы должны улучшить элементы, вставленные в controlgroup контейнер, используя .enhanceWithin().

$(element).enhanceWithin().controlgroup("refresh"); /* line 16 in fiddle */ 

Demo

+1

Фантастический! Спасибо – hkrauss2

+0

@ user3175121 добро пожаловать. Это исправление, но я работаю над лучшим решением, проверяя это http://jsfiddle.net/Palestinian/Q44Fy/. В моем ответе каждый флажок завернут в _ui-controlgroup-control_, который я не хочу быть. Я хочу, чтобы один div обернул все элементы внутри. – Omar

1

ответ Омара выше работ очень хорошо. Как он упоминает в комментариях, однако он обертывает каждую комбинацию ввода/метки в свой собственный div. Это, кажется, не влияет ни на что визуально или функционально, но есть другой способ, описанный ниже. В основном для привязки списка используется синтаксис потока без контейнера.

Новый Html

<div id="child-view" data-role="controlgroup"> 
    <!-- ko foreach: childCategories, jqmRefreshControlGroup: childCategories, forElement: '#child-view' --> 
    <input type="checkbox" name="checkbox-v-2a" data-bind="attr: {id: 'categoryId' + id}"></input> 
    <label data-bind="text: description, attr: {for: 'categoryId' + id}"></label> 
    <!-- /ko --> 
</div> 

Использование containerless синтаксис означает, что мы потеряем ссылку на controlgroup DIV в пользовательской привязки обработчика. Чтобы получить это, я добавил id как '# child-view' в пользовательскую привязку с именем forElement. Магия все еще происходит в пользовательском обработчике привязки, и предложение Омара в отношении предложения остается секретным ингредиентом. Примечание. Мне нужно было изменить список аргументов, чтобы включить все аргументы, переданные ko.

ko.bindingHandlers.jqmRefreshControlGroup = { 
update: function (element, valueAccessor, allBindings, viewModel, bindingContext) { 
    ko.utils.unwrapObservable(valueAccessor()); 
    try { 
     $(allBindings.get('forElement')).enhanceWithin().controlgroup("refresh"); 
    } catch (ex) { } 
    } 
} 

Конечная нота: Чтобы использовать пользовательский обработчик на виртуальном элементе ко должен быть уведомлен, что это нормально. Ниже приводятся обновленные отчеты о запуске:

// Apply bindings and initialize jqm 
$(function() { 
    ko.virtualElements.allowedBindings.jqmRefreshControlGroup = true; // This line added 
    ko.applyBindings(viewModel, GetView('#parent-view')); 
    ko.applyBindings(viewModel, GetView('#child-view')); 
    $.mobile.initializePage(); 
}); 
+0

Я нашел другой способ, я не знаю, дружелюбен ли он. Динамически добавьте 'data-bind = 'foreach: childCategories, jqmRefreshControlGroup: childCategories" 'to' .controlgroup ("container") 'на' controlgroupcreate' событие, а затем 'ko.applyBindings (viewModel, GetView (' # child-view ')); '. Проверьте последний блок кода в этой скрипке http://jsfiddle.net/Palestinian/y94c2/ – Omar

+0

Спасибо Омару - почти год поздно с моей стороны, но ... это мысль, которая считается;) – hkrauss2

Смежные вопросы