Home > Mobile >  How to get all css classes from html, through knockoutjs
How to get all css classes from html, through knockoutjs

Time:12-02

Im having a problem with selecting all classes with accordion and bringing them into knckoutjs to operate with them.

Following this link: https://wpbeaches.com/create-expandcollapse-faq-accordion-collapse-click/ I managed to create nice expandable objects (rectangles), but they are "dead" because Im using knockotjs, and not JS. So my question is how to make it to work? First step is that I cant select all accordion classes for some reason..here is my code:

define(['viewmodels/shell', 'durandal/services/logger', 'mediator-js', 'knockout', 'toastr'],
    function (shell, logger, mediator, ko, toastr) {
        var vm = {
            shell: shell,
            activate: activate,
            mediator: mediator
        }
            
        function activate() {
            var acc = jQuery.getElementsByClassName("accordion");
            var panel = document.getElementsByClassName('panel');

            for (var i = 0; i < acc.length; i  ) {
                acc[i].onclick = function () {
                    var setClasses = !this.classList.contains('active');
                    setClass(acc, 'active', 'remove');
                    setClass(panel, 'show', 'remove');

                    if (setClasses) {
                        this.classList.toggle("active");
                        this.nextElementSibling.classList.toggle("show");
                    }
                }
            }

            function setClass(els, className, fnName) {
                for (var i = 0; i < els.length; i  ) {
                    els[i].classList[fnName](className);
                }
            }
            return true;
        }

        return vm;
    });

What Im trying actually is to copy js part from the link above to my solution and make it work (expand each rectangle..)

CodePudding user response:

It's not quite clear to me what you're trying to do, but the telltale signs in your code indicate that you're tryting to do the wrong thing.

This is the most minimal accordion type of functionality I can think of using Knockout and (for convenience) jQuery, taking the questions and answers straight from the sample page you provided.

You can always get more sophisticated by adding animations and whatnot. But ultimately, it's about managing a single CSS class across a list of elements.

ko.bindingHandlers.cssExclusive = {
  init: (element, valueAccessor) => {
    ko.applyBindingsToNode(element, {
      click: () => {
        var config = ko.unwrap(valueAccessor());
        $(element).closest(config.within).children().not(element).removeClass(config.class);
        $(element).toggleClass(config.class);
      }
    });
  }
};

const data = {
  sections: [
    {name: "FAQs", items: [
      {q: "What currency is the course charged in?", a: "The course is charged in Australian dollars."},
      {q: "What if the course doesn’t help me?", a: "If it doesn't help you I'll refund the purchase price in full."},
      {q: "When will the webinars take place?", a: "Depending on the mix of countries and time zones for people attending the webinars, I will pick a time that works best for most participants. All webinars will be recorded so you can listen to them again. The private Facebook group will obviously be available 24/7 and I’ll be monitoring and contributing to the discussion regularly."},
      {q: "What is the self-directed mentoring program?", a: "The self-directed mentoring program is designed to help you set-up and run an effective mentee-mentor relationship as part of the course."},
    ]}
  ]
};

ko.applyBindings(data);
.accordion {
  cursor: pointer;
}
.panel {
  display: none;
}
.accordion.active {
  color: blue;
}
.accordion.active   .panel {
  display: block;
  color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<div data-bind="foreach: sections">
  <h3 data-bind="text: name"></h3>
  <div data-bind="foreach: items">
    <p class="accordion" data-bind="cssExclusive: {class: 'active', within: 'div'}">
      <span data-bind="text: 'Q'   ($index()   1)   '.'"></span>
      <span data-bind="text: q"></span>
    </p>
    <div class="panel">A. <span data-bind="text: a"></span></div>
  </div>
</div>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

I can't say how you would integrate that into your sample code, but maybe you can draw some inspiration from it.

The core functionality is toggling a CSS class on an element on click. For this, I've made a bare-bones custom binding that applies the click binding to the all questions. The click binding takes care of toggling the active class on the clicked question, and removing it from all others in the same container.

This does not even require things like "expanded" observables on the view model, as it keeps its state purely through CSS classes in the DOM.

  • Related