Marionette.js. Drag&Drop сортировка моделей в коллекции



    Достаточно распространенная задача — поменять местами элементы в списке. Но как правило эта задача решается жуткими костылями, особенно если это Drag&Drop.
    Сейчас я расскажу вам очень простой и гибкий способ сделать это, используя Marionette.js и jQuery UI Sortable.

    Подключаем jQuery UI


    Из jQuery UI нам потребуется только часть Sortable, поэтому, экономии трафика ради, я смело снял за вас все ненужные галочки отсюда. Вам осталось только загрузить.

    Обратите внимание


    В коде ниже используется ссылка на Marionette
    var Marionette=Backbone.Marionette;
    


    Создаем шаблон поведения


    Данную функциональность мы реализуем в виде Behavior, о котором я писал ранее.
    Вот код поведения, который будет отвечать за возможность сортировки моделей внутри коллекции
    Behaviors.Sortable=Marionette.Behavior.extend({ 
    	onRender:function(){
    		var  collection=this.view.collection // Замыкаем коллекцию
    			,items=this.view.children._views // Получаем список дочерних элементов
    			,view
    			;
    		for(var v in items){
    			view=items[v]
    			view.$el.attr('data-backbone-cid',view.model.cid); // Привязываем элемент к модели по cid
    		}
    		this.$el.sortable({ // Делаем список сортируемым
    			axis: this.options.axis||false,
    			grid: this.options.grid||false,
    			containment: this.options.containment||false,
    			cursor: "move",
    			handle:this.options.handle||false,
    			revert: this.options.revert||false,
    			update: function( event, ui ) {
    				var model=collection.get(ui.item.data('backbone-cid')); 
    				// Получаем привязанную модель
    				collection.remove(model,{silent:true});
    				 // По-тихому удаляем её из коллекции
    				collection.add(model,{at:ui.item.index(),silent:true});
    				 //И также втихаря добавляем её по нужному индексу
    			}
    		});
    		
    	}
    });
    


    Что это?

    Этот шаблон поведения предназначен для CollectionView. Он дожидается события onRender, после чего привязывает каждый элемент ItemView к его модели с помощью cid.
    Потом мы разрешаем этому списку сортироваться с помощью Drag&Drop используя jQuery.

    Опции Sortable

    Для каждого вида можно передавать свой набор опций, подробнее можно прочитать в документации jQuery UI. В представленном выше коде реализованы не все возможные опции, вы можете добавить свои по желанию.

    Сортировка

    Когда один из элементов перетащили, мы удаляем привязанную к этому элементу по сid модель из коллекции и добавляем заново по нужному индексу. Флаги silent:true нужны, что бы Marionette.js не пыталась переставить все по-своему, у неё это плохо получается.

    Соединяем СollectionView и Behavior


    Теперь применим это в действии
    var IView=Marionette.ItemView.extend({// Создаем стандартный ItemView
    	template:'#item-template'
    })
    var CView=Marionette.CollectionView.extend({// Создаем CollectionView
    	itemView:IView,
    	behaviors: {// вот тут творится вся магия. 
    		Sortable:{// Применяем поведение Sortable к данному виду. 
    					//В качестве примера я передал параметр containment
    			containment:'parent' // Теперь перетаскивать элементы мы можем только внутри родительского контейнера.
    		}
    	}
    })
    


    Теперь вы с помощью одной строчки behaviors: {Sortable:{}} можете добавить возможность Drag&Drop сортировки CollectionView.

    Как сохранить это на сервер?


    Я не знаю в каком виде на сервере у вас хранится порядок сортировки, но с помощью описанного выше подхода вы сможете передать порядок в любом формате.
    Я использую MongoDB, поэтому без особых проблем с помощью сollection.toJSON() отправляю это на сервер Node.JS и сохраняю как есть.
    Можно отправить на сервер упорядоченный массив id, получить который можно с помощью
    collection.pluck('id');
    


    Вот и всё


    enjoy it works!
    Надеюсь статья вам помогла.
    Пожалуйста, пишите в комментариях о чем вам хотелось бы ещё почитать.
    • +17
    • 13,6k
    • 7
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 7
    • +4
      случайно глупость написал.
      • +5
        Немного напрягает использование jQuery UI(хотя в данный момент у самого на проектах так же работает).
        Было бы здорово обходиться без него. Можно посмотреть в сторону чего-нибудь вроде этого
        • +2
          Как правило вслед за Sortable возникает необходимость остальных «плюшек» jQuery UI, таких как Draggable и Droppable (к примеру, поместить запись блога в категорию). В таком случае, вместо подключения по отдельности таких мини-библиотек от разных авторов, целесообразно использовать именно jQuery UI.
        • +1
          Насколько усложнится это решение, если список будет не плоским, а с подпунктами?
          • +1
            Не на много усложнится. Для каждого вложенного списка надо будет создать свой вид, связать все эти виды в DOM с помощью опции connectWith и добавить обработку событии remove и recieve в sortable.
            Для того, что бы добавить модель, связанную с этим элементом, в другую коллекцию, одного cid будет уже не достаточно, нужна целая модель.
            Далее на ум сейчас приходят два способа.

            Либо можно при инициализации вида привязать модель к каждому сортируемому элементу, что бы при получении этого элемента обработчик знал что именно добавлять в свою коллекцию, то есть что-то вроде такого
                    ........................
                    for(var v in items){
                        view=items[v]
                       // Привязываем элемент к модели непосредственно
                        view.$el.data('backbone-model',view.model); 
                    }
            


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

            Первый вариант мне кажется проще.

            Если хотите, могу написать об этом, когда будет готовое решение.
            • +1
              Да, было бы интересно увидеть готовое решение. Спасибо!
          • +2
            Спасибо, хорошая статья. По Marionette, к сожалению, не так много интересных статей.

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.