Использование сортируемого с 2 деревьями KnockoutJS

0

Можно ли использовать нокаут-сортировку с деревьями-нокаутами, чтобы можно было перетаскивать предметы из одного дерева в другое?

Я пытался адаптировать пример от RP Niemeyer, но я просто не могу заставить его работать.

Я могу перетаскивать элементы с обоих деревьев, но это не позволит мне отказаться от них. Я добавил свойство connectWith в качестве параметра в сортируемый плагин, но он не работает.

Вот что я имею до сих пор:

JS:

$(function () {
    $(".availableItemsContainer .node").sortable({ connectWith: ".groupedItemsContainer" });

    $(".groupedItemsContainer .node").sortable({ connectWith: ".availableItemsContainer" });
});

ko.bindingHandlers.flash = {
    init: function (element) {
        $(element).hide();
    },
    update: function (element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        if (value) {
            $(element).stop().hide().text(value).fadeIn(function () {
                clearTimeout($(element).data("timeout"));
                $(element).data("timeout", setTimeout(function () {
                    $(element).fadeOut();
                    valueAccessor()(null);
                }, 3000));
            });
        }
    },
    timeout: null
};

ko.bindingHandlers.droppable = {
    init: function(element, valueAccessor) {
        var dropHandler = valueAccessor() || {};

        $(element).droppable({
            drop: function(event, ui) {
                var item = ko.utils.domData.get(ui.draggable[0], "ko_dragItem");

                if (item) {
                    item = item.clone ? item.clone() : item;
                    dropHandler.call(this, item, event, ui);
                }
            }
        });
    }
};

var DGViewModel = function () {
    var self = this;

    self.tree1 = {
        id: 'groupedItems',
        remember: true,
        children: [
            {
                name: "Annabelle",
                id: '1',
                isOpen: true,
                children: [
                    { name: "Arnie", cssClass: 'page', id: '5', children: [] },
                    { name: "Anders", cssClass: 'page', id: '6', children: [] },
                    { name: "Apple", cssClass: 'page', id: '7', children: [] }
                ]
            },
            {
                name: "Bertie",
                id: '2',
                children: [
                    { name: "Boutros-Boutros", cssClass: 'page', id: '8', children: [] },
                    { name: "Brianna", cssClass: 'page', id: '9', children: [] },
                    { name: "Barbie", cssClass: 'page', id: '10', children: [] },
                    { name: "Bee-bop", id: '4', children: [] }
                ]
            },
            { name: "Charles", id: '3', children: [] }
        ],
        dragHolder: ko.observable(undefined),
        handlers: {
            addNode: function(parent, type, name, onSuccess) {
                nextId = nextId + 1;
                onSuccess({ id: nextId, parent: parent, name: name, cssClass: type });
            }
        },
        logTo: '#log1',
        defaults: {
            'folder': {
                name: 'New Folder',
                childType: 'page'
            },
            'page': {
                name: 'New Page',
                isDraggable: true,
                isDropTarget: false,
                canAddChildren: false
            }
        },
        contextMenu: {
            contextMenus:
            [
                {
                    name: 'foldercontext',
                    width: 190,
                    items: [
                        {
                            text: 'Delete',
                            run: function(dataItem) {
                                dataItem.deleteSelf();
                            }
                        },
                        {
                            text: 'Rename',
                            run: function(dataItem) {
                                dataItem.isRenaming(true);
                            }
                        },
                        { separator: true },
                        {
                            text: 'New',
                            items: [
                                {
                                    text: 'Page',
                                    iconCssClass: 'page',
                                    run: function(dataItem) {
                                        dataItem.addChild({ type: 'page' });
                                    }
                                },
                                {
                                    text: 'Folder',
                                    iconCssClass: 'folder',
                                    run: function(dataItem) {
                                        dataItem.addChild({ type: 'folder' });
                                    }
                                }
                            ]
                        }
                    ]
                },
                {
                    name: 'pagecontext',
                    width: 190,
                    items: [
                        {
                            text: 'Delete',
                            run: function(dataItem) {
                                dataItem.deleteSelf();
                            }
                        },
                        {
                            text: 'Rename',
                            run: function(dataItem) {
                                dataItem.isRenaming(true);
                            }
                        }
                    ]
                }
            ],
            build: function(event, dataItem) {
                dataItem.selectNode();
                var type = dataItem.type();
                if (type == 'folder') {
                    return { name: 'foldercontext' };
                } else {
                    return { name: 'pagecontext' };
                }
            }
        }
    };

    self.tree2 = {
        id: 'availableItems',
        remember: true,
        children: [
            { name: "Test1", id: '300', cssClass: 'page', children: [] },
            { name: "Test2", id: '301', cssClass: 'page', children: [] },
            { name: "Test3", id: '302', cssClass: 'page', children: [] },
            { name: "Test4", id: '303', cssClass: 'page', children: [] }
        ],
        dragHolder: ko.observable(undefined),
        handlers: {
            addNode: function(parent, type, name, onSuccess) {
                nextId = nextId + 1;
                onSuccess({ id: nextId, parent: parent, name: name, cssClass: type });
            }
        },
        logTo: '#log1',
        defaults: {
            'folder': {
                name: 'New Folder',
                childType: 'page'
            },
            'page': {
                name: 'New Page',
                isDraggable: true,
                isDropTarget: false,
                canAddChildren: false
            }
        },
        contextMenu: {
            contextMenus:
            [
                {
                    name: 'foldercontext',
                    width: 190,
                    items: [
                        {
                            text: 'Delete',
                            run: function(dataItem) {
                                dataItem.deleteSelf();
                            }
                        },
                        {
                            text: 'Rename',
                            run: function(dataItem) {
                                dataItem.isRenaming(true);
                            }
                        },
                        { separator: true },
                        {
                            text: 'New',
                            items: [
                                {
                                    text: 'Page',
                                    iconCssClass: 'page',
                                    run: function(dataItem) {
                                        dataItem.addChild({ type: 'page' });
                                    }
                                },
                                {
                                    text: 'Folder',
                                    iconCssClass: 'folder',
                                    run: function(dataItem) {
                                        dataItem.addChild({ type: 'folder' });
                                    }
                                }
                            ]
                        }
                    ]
                },
                {
                    name: 'pagecontext',
                    width: 190,
                    items: [
                        {
                            text: 'Delete',
                            run: function(dataItem) {
                                dataItem.deleteSelf();
                            }
                        },
                        {
                            text: 'Rename',
                            run: function(dataItem) {
                                dataItem.isRenaming(true);
                            }
                        }
                    ]
                }
            ],
            build: function(event, dataItem) {
                dataItem.selectNode();
                var type = dataItem.type();
                if (type == 'folder') {
                    return { name: 'foldercontext' };
                } else {
                    return { name: 'pagecontext' };
                }
            }
        }
    };
};

var vm = new DGViewModel();

var nextId = 20;
vm.treeViewModel1 = new ko.tree.viewModel(vm.tree1);
vm.treeViewModel2 = new ko.tree.viewModel(vm.tree2);

ko.bindingHandlers.sortable.beforeMove = vm.verifyAssignments;
ko.bindingHandlers.sortable.afterMove = vm.updateLastAction;

ko.applyBindings(vm);

HTML:

<div id="availableItemsTreeViewWrapper">
    <div class="container">
        <div class="availableItemsContainer">
            <div data-bind="tree : treeViewModel2"></div>
        </div>
        <div class="availableItemsContextMenuContainer">
            <div style="padding: 10px;">
                <a href="#" id="add" data-bind="click : function() { treeViewModel2.addNode(); }">Add</a>
                <a href="#" id="delete" data-bind="click : treeViewModel2.deleteNode">Delete</a>
                <a href="#" id="delete" data-bind="click : treeViewModel2.renameNode">Rename</a>
            </div>
            <div id="log2" class="logger">
            </div>
        </div>
    </div>
</div>

<div class="mainWrapper">
    <div id="groupedItemsTreeViewWrapper">
        <div class="container">
            <div class="groupedItemsContainer">
                <div data-bind="tree : treeViewModel1"></div>
            </div>
            <div class="groupedItemsContextMenuContainer">
                <div style="padding: 10px;">
                    <a href="#" id="add" data-bind="click : function() { treeViewModel1.addNode(); }">Add</a>
                    <a href="#" id="delete" data-bind="click : treeViewModel1.deleteNode">Delete</a>
                    <a href="#" id="delete" data-bind="click : treeViewModel1.renameNode">Rename</a>
                </div>
                <div id="log1" class="logger">
                </div>
            </div>
        </div>
    </div>
</div>

Есть ли что-то, что я делаю неправильно?

Заранее большое спасибо!

Теги:
treeview
knockout.js
knockout-sortable

1 ответ

0

Я сделал это, не используя решение, которое вы делаете. То, что я делал, поддерживало все взаимодействия ui одинаково, а затем обрабатывало все в событиях. Таким образом, у меня было упорядоченное привязку (ko.bindingHandlers.sortable) с атрибутом value, поддерживающим мои параметры. В сортируемом привязке у меня будет что-то вроде:

ko.bindingHandlers.sortable = {
    init: function (element, valueAccessor) {    
        options = valueAccessor();
        $(element).sortable({
            connectWith: options.connectWith || {},
            items: options.items || {},
            update: options.update || {}
        });
    }
};

а затем в обновлении я обрабатываю добавление его из одного списка в другой. Таким образом, вы заносите его в свой список (на данный момент это только в DOM), и обновление ловит его (или останавливается, в зависимости от того, что вам нужно). Обновление пожаров в первом списке И второй список, остановка - это только второй список.) Здесь вы удаляете его из первого списка (либо явно, либо используя ko.contextFor для узла dom), а затем вставляете его во второй список. На этом этапе вам придется удалить элемент из ui, и это так же просто, как ui.item.remove(). Если вы храните эту информацию в базе данных (в любом случае), вам нужно будет сохранить последовательность, поскольку они просто вернутся в том порядке, в котором они были созданы, независимо от того, что.

Этот способ - хороший способ просто работать с jquery ui, но он действительно не интегрируется. Вы позволяете jquery ui делать свою работу, а затем обновлять модель на основе конечного результата.

-

Поэтому в html то, что вы собираетесь делать, это использовать привязку, о которой я говорил выше. Для этого вы привяжете оба своих списка так:

<div id="list1" data-bind="sortable: { connectWith: '#list2', update: updateListFunction, items: '.myItems' }, foreach: list1.items">
    <div class="myItems"></div>
</div>
<div id="list2" data-bind="sortable: { connectWith: '#list1', update: updateListFunction, items: '.myItems' }, foreach: list2.items">
    <div class="myItems"></div>
</div>

а затем updateListFunction будет что-то в вашей модели контекстного просмотра, которая выглядит так:

self.updateListFuntion = function() {
    //makes sure it only updates on the list to which the sorting applied, since it fires twice
    if (this === ui.item.parent()[0]){    
         //do your updating here, using the method in the second paragraph 
         //ko.contextFor(ui.item) will give you the original item to get it out of the list and move it into the next
         //a lot of the stuff that going to happen here is array math and is a whole 'nother can of worms!
    }
}
  • 0
    Большое спасибо за ваш ответ, Мэгги. Я пытался реализовать то, что вы описали, но я не знаю, с чего начать. Не могли бы вы подробнее рассказать о том, что мне нужно сделать, пожалуйста? Я вроде новичок в запросе / jquery, так что я не уверен точно, что делать и где делать это точно. К вашему сведению, я изменил это: $ (". AvailableItemsContainer .node"). Sortable (); $ (". groupedItemsContainer .node"). sortable (); Я также добавил код, который вы разместили.
  • 0
    позвольте мне отредактировать, как может выглядеть HTML, и дайте мне знать, помогает это или нет!
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню