简体   繁体   中英

Meta items with bootstrap-sortable

With knockout you can produce a row of bootstrap nav-tabs like this

<ul class="nav nav-tabs question-container" data-bind="foreach: Questions">
  <li role="presentation" data-bind="css: { active: $index() === 0 }">
    <a data-toggle="tab" 
       data-bind="attr: { href: '#q' + QuestionId() }">, text: Caption"></a>
  </li>
</ul>

With bootstrap-sortable you can make the tabs sortable simply by changing the binding. A limitation clearly documented is that you can't use the sortable binding with virtual elements because it depends on being defined on a single container element.

Suppose I wanted to add a tab "Add a new question" presenting various options for what to create, after the manner of the add-new tabs used in Chrome, Internet Explorer, Firefox and Microsoft Excel.

If I weren't trying to make the tabs sortable, I'd do this:

<ul class="nav nav-tabs question-container">
  <!-- ko foreach: Questions-->
  <li role="presentation" data-bind="css: { active: $index() === 0 }">
    <a data-toggle="tab" 
       data-bind="attr: { href: '#q' + QuestionId() }, text: Caption"></a>
  </li>
  <!-- /ko -->
  <li role="presentation" data-bind="css: { active: Questions().length === 0 }">
    <a data-toggle="tab" href="#addQuestion">
    <i class="fa fa-plus"></i>Add a new question</a>
  </li>
</ul>

By adding a marker class "sortable-item" to the <LI> in the template, we can trivially exclude the meta item by defining item: ".sortable-item" in the bootstrap-sortable options. But it still won't fly, because you can't use virtual elements with bootstrap-sortable.

Does anyone know how to add meta items to a collection managed by bootstrap-sortable?

There are four ways this problem can be approached.

  1. Don't use bootstrap-sortable, apply jQuery-UI sortable explicitly and ise sort update events to update the backing store collection.
  2. Use bootstrap and inject the meta items after binding completes.
  3. Modify bootstrap to support the notion of a meta-items template in addition to the binding template.
  4. Modify bootstrap to use the immediate parent of a virtual node. There is always a parent, even if it's BODY.

Personally I favour option four, because it doesn't change how bootstrap-sortable is applied, it simply removes a limitation. No breaking changes.

Option three is nearly as good but it increases the conceptual complexity and makes the learning curve steeper.

Option two sucks big rocks. It screws up separation of concerns.

Option one, which is what I actually did, sucks even bigger rocks. Not only does it pollute the view model with UI behaviour, it's complicated to do, depends on poorly documented and obscure knockout internal utilities and it's just plain ugly. Everything about it is a justification for the existence of bootstrap-sortable.


In answer to this comment:

The "add question" button is not a question, therefore it should not be part of the list of questions

It's not a list of questions, it's the UI for a set of operations that can be performed on a list of questions. Most of them are "display item X for editing" but one of them is "create a new item". Also present are controls for deleting items and for re-ordering them.

I find it hilariously ironic that anyone would claim this is not an obvious UI design while using a web browser - a ubiquitous example of this exact design

It doesn't seem like there is currently a better story than the workaround I mention in the question. The ideal solution would be for me or someone else to write a knockout binding. Most of the code in bootstrap-sortable seems to have to do with templating the rather nifty table it generates, but I think the required lessons are there.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM