Пользователь
0,0
рейтинг
22 апреля 2014 в 01:19

Разработка → 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!
Надеюсь статья вам помогла.
Пожалуйста, пишите в комментариях о чем вам хотелось бы ещё почитать.
Дмитрий @pharrell
карма
10,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (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, к сожалению, не так много интересных статей.

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