• This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn more.

Drag and drop re-ordering in 1.3?

Myke623

Active member
#1
Has anyone tried using the drag and drop functionality in xenForo 1.3 for re-ordering elements in a list, and can provide an overview of how it works?

Otherwise, I'll attempt to unravel how it's used in the MultiQuote feature.
 

Myke623

Active member
#3
Hmm, I'm not having any luck.

The difference in what I'm trying to achieve and MultiQuote, is that I already have my list of things ($categoryList) in a table. So rather than rely on user inputs to construct the list, I simply grab it from my model and pass it to my view. The template for this view is as follows:

Code:
<xen:title>Categories</xen:title>

<xen:require js="js/sortable/jquery.sortable.min.js" />

<form class="section" id="CategoriesForm">
    <h3 class="subHeading">Drag Categories to rearrange order</h3>
    <ol class="overlayScroll Sortable">
        <xen:foreach loop="$categoryList" key="$catId" value="$category">
            <li draggable="true" class="CategoryItem">
                <input type="hidden" name="catId[]" value="{$catId}" class="CategoryId" />
                {$category.title}
            </li>
        </xen:foreach>
    </ol>
    <div class="sectionFooter">
        <a class="button OverlayCloser JsOnly">{xen:phrase cancel}</a>
        <a class="button primary OverlayCloser AutoFocus"
            href="{xen:link addon/categories}"
            data-inputs="#CategoriesForm input.CategoryId">Save Order</a>
    </div>
</form>
With this, I was just hoping to drag the <LI> elements around and observe the effect in Chrome's element inspector. However, while I can drag an <LI> element, the cursor instantly turns into the circle-with-diagonal-line icon, meaning "you can't drag this here". As such, I'm unable to change the list order.

I used the MultiQuote template as the starting point, and culled the bits which I thought weren't relevant to my more generic purpose. Ignoring the Save Order button for the moment, is there anything obvious I've missed?
 

Chris D

XenForo developer
Staff member
#4
I believe you're missing this relevant code in discussion.js:

Code:
    XenForo.Sortable = function($container)
    {
        $container.sortable(
        {
            forcePlaceholderSize: true

        }).bind(
            {
                'sortupdate': function(e) {},
                'dragstart' : function(e)
                {
                    console.log('drag start, %o', e.target);
                },
                'dragend' : function(e) { console.log('drag end'); }
            }
        );
    };

    XenForo.register('.Sortable', 'XenForo.Sortable');
This binds events to the .Sortable elements and additionally activates some of the Sortable settings.

You will need to include something similar.
 

Myke623

Active member
#6
Last question (hopefully) to complete the puzzle: How can I get my re-ordered list passed to the Controller?

I figure I need to add a new class to the "Save Order" button, and register the corresponding new js function to do something with the data-inputs, but I'm at a bit of a loss.
 

Chris D

XenForo developer
Staff member
#7
The elements will already be in the correct order when passed to the controller.

With that in mind, the simplest thing to do is to loop through them with a numeric key, or assign your own incremental value when you loop, e.g:

PHP:
$categories = array();

$categoryIds = $this->_input->filterSingle('catId', XenForo_Input::UINT, array('array' => true);
foreach ($categoryIds AS $key => $categoryId)
{
    $categories[] = array(
        'category_id' => $categoryId,
        'display_order' => $key // 0, 1, 2, 3, 4, etc.
    );
}
OR

PHP:
$categories = array();

$i = 0;

$categoryIds = $this->_input->filterSingle('catId', XenForo_Input::UINT, array('array' => true);
foreach ($categoryIds AS $categoryId)
{
    $i++;

    $categories[] = array(
        'category_id' => $categoryId,
        'display_order' => $i * 10 // 10, 20, 30, 40, etc.
    );
}
Something like that, anyway. Depends exactly what you're trying to achieve.