2012-01-27 20 views
11

Mam mały problem z próbą uzyskania interfejsu użytkownika jQuery i nokautu do współpracy. Zasadniczo chcę stworzyć akordeon z przedmiotami dodawanymi z nokautu przez foreach (lub szablon).knockout.js i jQueryUI do utworzenia menu akordeonu

Kod podstawowy jest następujący:

<div id="accordion"> 
    <div data-bind="foreach: items"> 
     <h3><a href="#" data-bind="text: text"></a></h3> 
     <div><a class="linkField" href="#" data-bind="text: link"></a></div> 
    </div> 
</div> 

nic specjalnego tu ... Problem polega na tym, że jeśli zrobię coś takiego:

$('#accordion').accordion(); 

Akordeon zostanie utworzona, ale wewnętrzna div będzie selektorem nagłówka (pierwsze dziecko, domyślnie), więc efekt nie jest pożądany.

Mocowanie rzeczy z tym:

$('#accordion').accordion({ header: 'h3' }); 

wydaje się działać lepiej, ale faktycznie tworzy 2 akordeony, a nie jeden z odcinków 2 ... dziwne.

Próbowałem zbadać szablony nokautów i używając "afterRender", aby ponownie zharmonizować div, ale bezskutecznie ... wydaje się ponownie renderować tylko pierwsze łącze jako akordeon, a nie drugie. Prawdopodobnie jest tak ze względu na moją początkującą znajomość jquery UI.

Czy masz pojęcie, jak sprawić, aby wszystko działało razem?

Odpowiedz

13

Pozwolił bym z niestandardowymi powiązaniami dla takiej funkcjonalności.

Podobnie jak RP Niemeyer na przykładzie jQuery Accordion wiązania knockoutjs http://jsfiddle.net/rniemeyer/MfegM/

+3

Yup - to jakiś poważny accordioning. – PhillipKregg

+0

Jest to interesujące i odpowiada na to, o co pytałem, chociaż wydaje się nieco odrażające:/ Prawdopodobnie powinienem zajrzeć do niestandardowych wiązań, aby lepiej zrozumieć. Dzięki za link! – Tallmaris

+0

Moim zdaniem niestandardowe wiązania są niezbędne do zrozumienia nokautu i używania – AlfeG

1

Czy istnieje jakikolwiek powód, dlaczego nie można zastosować widget akordeon do wewnętrznych div tutaj? Na przykład:

<div id="accordion" data-bind="foreach: items"> 
    <h3><a href="#" data-bind="text: text"></a></h3> 
    <div><a class="linkField" href="#" data-bind="text: link"></a></div> 
</div> 
6

Próbowałem zintegrować nokaut i akordeon jQuery UI i później Bootstrap składany akordeonie. W obu przypadkach zadziałało, ale okazało się, że muszę zaimplementować kilka obejść, aby wszystko poprawnie wyświetlić, zwłaszcza gdy dynamicznie dodajemy elementy przez nokaut. Wymienione widżety nie zawsze są świadome tego, co się dzieje w związku z nokautem, a rzeczy mogą zostać popsute (wysokości div niesłusznie obliczone itp.). Zwłaszcza w przypadku akordeonu JQuery ma tendencję do przepisywania html według własnego uznania, co może być prawdziwym bólem.

Postanowiłem więc zrobić własny widget na akordeon przy użyciu JQuery i Knockout. Zobacz ten działający przykład: http://jsfiddle.net/matt_friedman/KXgPN/

Oczywiście przy użyciu różnych znaczników i css można to dostosować do potrzeb.

Fajną rzeczą jest to, że jest całkowicie oparte na danych i nie ma żadnych założeń dotyczących układu poza tym, co zdecydujesz się użyć. Zauważysz, że znaczniki nie są proste. To tylko przykład. To ma być dostosowane.

Markup:

<div data-bind="foreach:groups" id="menu"> 
    <div class="header" data-bind="text:name, accordion: openState, click: toggle">&nbsp;</div> 
    <div class="items" data-bind="foreach:items"> 
     <div data-bind="text:name">&nbsp;</div> 
    </div> 
</div> 

Javascript:

ko.bindingHandlers.accordion = { 

    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 
     $(element).next().hide(); 
    }, 
    update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 

     var slideUpTime = 300; 
     var slideDownTime = 400; 

     var openState = ko.utils.unwrapObservable(valueAccessor()); 
     var focussed = openState.focussed; 
     var shouldOpen = openState.shouldOpen; 

     /* 
     * This following says that if this group is the one that has 
     * been clicked upon (gains focus) find the other groups and 
     * set them to unfocussed and close them. 
     */ 
     if (focussed) { 

      var clickedGroup = viewModel; 

      $.each(bindingContext.$root.groups(), function (idx, group) { 
       if (clickedGroup != group) { 
        group.openState({focussed: false, shouldOpen: false}); 
       } 
      }); 
     } 

     var dropDown = $(element).next(); 

     if (focussed && shouldOpen) { 
      dropDown.slideDown(slideDownTime); 
     } else if (focussed && !shouldOpen) { 
      dropDown.slideUp(slideUpTime); 
     } else if (!focussed && !shouldOpen) { 
      dropDown.slideUp(slideUpTime); 
     } 
    } 
}; 

function ViewModel() { 

    var self = this; 
    self.groups = ko.observableArray([]); 

    function Group(id, name) { 

     var self = this; 
     self.id = id; 
     self.name = name; 

     self.openState = ko.observable({focussed: false, shouldOpen: false}); 

     self.items = ko.observableArray([]); 

     self.toggle = function (group, event) { 
      var shouldOpen = group.openState().shouldOpen; 
      self.openState({focussed: true, shouldOpen: !shouldOpen}); 
     } 
    } 

    function Item(id, name) { 
     var self = this; 
     self.id = id; 
     self.name = name; 
    } 

    var g1 = new Group(1, "Group 1"); 
    var g2 = new Group(2, "Group 2"); 
    var g3 = new Group(3, "Group 3"); 

    g1.items.push(new Item(1, "Item 1")); 
    g1.items.push(new Item(2, "Item 2")); 

    g2.items.push(new Item(3, "Item 3")); 
    g2.items.push(new Item(4, "Item 4")); 
    g2.items.push(new Item(5, "Item 5")); 

    g3.items.push(new Item(6, "Item 6")); 

    self.groups.push(g1); 
    self.groups.push(g2); 
    self.groups.push(g3); 
} 

ko.applyBindings(new ViewModel()); 
+0

Naprawdę ładne. Dzięki za to. Zmodyfikowałem go nieznacznie, aby zapewnić użyteczną nawigację za pomocą klawiatury dla moich użytkowników. (Przynajmniej bardziej przydatna nawigacja za pomocą klawiatury niż większość rozwiązań opartych na jQuery zapewnia!) –

+0

Dziękuję za to. Skończyło się również na tym użyciu. Byłoby wspaniale, gdyby istniał sposób na uczynienie go nieco bardziej ogólnym. Może później się z tym pobiorę. – Quickhorn

0

Można spróbować to go szablonu, podobny do tego:

<div id="accordion" data-bind="myAccordion: { },template: { name: 'task-template', foreach: ¨Tasks, afterAdd: function(elem){$(elem).trigger('valueChanged');} }"></div> 

<script type="text/html" id="task-template"> 
    <div data-bind="attr: {'id': 'Task' + TaskId}, click: $root.SelectedTask" class="group"> 
     <h3><b><span data-bind="text: TaskId"></span>: <input name="TaskName" data-bind="value: TaskName"/></b></h3> 
     <p> 
      <label for="Description" >Description:</label><textarea name="Description" data-bind="value: Description"></textarea> 
      </p> 
    </div> 
</script> 

"Zadania()" jest ko. obserwowalneArray z wypełnionym zadaniem, z atrybutami "TaskId", "TaskName", "Description", "SelectedTask" zadeklarowane czerwony jako ko.observable();

"myAccordion" jest

ko.bindingHandlers.myAccordion = { 
    init: function (element, valueAccessor) { 
     var options = valueAccessor(); 
     $(element).accordion(options); 
     $(element).bind("valueChanged", function() { 
      ko.bindingHandlers.myAccordion.update(element, valueAccessor); 
     }); 
     ... 
} 
0

Co zrobiłem było, ponieważ moje dane są ładowane z AJAX i pokazywał "Loading" spinner, ja załączeniu akordeonie do ajaxStop tak:

$(document).ajaxStart(function(){$("#cargando").dialog("open");}).ajaxStop(function(){$("#cargando").dialog("close");$("#acordion").accordion({heightStyle: "content"});}); 

Działa doskonale.

1

Podjęłam próbę zaakceptowanego rozwiązania i zadziałało. Po prostu musiał zrobić trochę zmian, ponieważ byłem coraz następujący błąd

Uncaught Error: cannot call methods on accordion prior to initialization; attempted to call method 'destroy' 

prostu musiałem dodać następne i to działało

if(typeof $(element).data("ui-accordion") != "undefined"){ 
$(element).accordion("destroy").accordion(options); 
} 

Szczegółowe informacje można znaleźć Knockout accordion bindings break

Powiązane problemy