JQuery UI sortable - як дізнатися нову позицію елементів

дізнатися

Доброго дня, шановні читачі блогу LifeExample в цій статті буде показаний процес створення сортованих елементів за допомогою jQuery UI sortable, як сортувати елементи, відправляти оновлені дані на сервер через AJAX і обробляти їх за допомогою алгоритму визначального видалених елементів і місця їх видалення.

Якщо ви потрапили на цю сторінку, значить ви швидше за все розумієте щось такеjQuery UI sortable, але про всяк випадок поясню,jQuery UI sortable - це плагін, що дозволяє міняти місцями виведені на HTML сторінці елементи, простим перетягуванням їх за допомогою покажчика миші (зазвичай метод такого переміщення називають Drag and Drop – перетягуй та відпускай).

дізнатися

Використання jQuery UI sortable, у веб-проекті добре тим, що дозволяє заощадити велику кількість часу, власне як і багато інших можливостей доступних у jQuery UI.

Написавши лише один рядок коду, ми зробимо всі пункти в маркованих списках, що перетягуються.

Незважаючи на зручність використання,jQuery UI sortable породжує наступну проблему, про яку програміст починає замислюватися лише за необхідності зафіксувати нові позиції елементів у базі даних.Як дізнатися нову позицію елементів?

Проблема полягає ось у чому: після перетягування елемента, послідовність змінила свій порядок, але як дізнатися з якої позиції був видалений елемент і на яку він перемістився.

Наведу приклад для наочності

Наприклад, якщо початковою послідовністю були цифри

і число "3" було переміщено між "1" та "2", отримуємо наступний результат:

У той же час, якщо "2" був переміщений між "3" і "4", отримуємо наступний масив

Хммм... один і той же масив...

Як зрозуміти які елементи змінилися місцями

У завантаженому архіві ви знайдете класиProfile.php таSortableElement.php модуль ініціалізаціїindex.php, який просто створює дані для демонстрації прикладу та займається відбором. ФайлsortExample.html є основною сторінкою та оформлений уstyle.css.

Файлиsortable.js таSortController.php є важливими. Вони забезпечують взаємодію між браузером та сервером. У класі контролера представлена ​​логіка для обробки даних від методуjQuery UI sortable при сортуванні елементів.

За допомогою функції handleReorderElements() надсилається AJAX запит на сервер. Функція initSortableContainer() визначає подію для контейнера div, який містить сортовані елементи і вказує, що функція handleReorderElements() викликається після завершення операцій із сортування.

Функцією jQuery sortable(«serialize») ми можемо отримати рядок GET параметрів із усіх відсортованих id елементів у новому порядку

function handleReorderElements ( ) < var url = 'controllers/SortController.php'; var fieldData = $ ( "#SortableElements") . sortable ("serialize"); fieldData += "&action=reorderElements" ;

var posting = $. post (url, fieldData); posting. done (function (data) < reorderElementsResponse(data); >); >

Функція reorderElementsResponse(data), що використовується в наведеному вище коді, є обробником зворотного виклику AJAX методу, який був відправлений черезjQuery UI sortable.

Вона виведе відповідне повідомлення про успішне або не успішне збереження сортування.

Для функціонування даного прикладу, id елемента, що переміщається, повинен містити в собінижнє підкреслення та номер. Якщо ви звернете увагу наindex.php, то побачите, що id елементів, що переміщуються, генеруються ось так

У SortController.php, ми можемо отримати цей масив за допомогою

Обробка даних на сервері

SortController.php обробляє надісланий AJAX запит через jQuery UI sortable зі сторінки. Він отримує значення і зберігає їх у змінній $ sortIdArray . Потім він витягує початковий масив із сесії та зберігає ключі, які є id-шниками елементів в окремий масив:

Наступна функція порівнює масиви визначення того який елемент був переміщений. Функція getArrayDiff($originalKeys, $newKeys) отримує масив із вихідною послідовністю Id елементів та масив із зміненою послідовністю Id.

За допомогою цієї функції порівнюється кожен початковий та змінений порядковий номер елементів.

Порівняння відбувається до моменту, поки не знайдуться порядкові номери, що не збігаються один з одним.

Один з ID буде видалено. Щоб визначити який саме id буде видалено ця функція видаляє початковий id з обох масивів і повторно порівнює два масиву.

Структура таблиці у базі даних

А тепер настав час трохи повернутися назад і обговорити структуру таблиці, за допомогою якої база даних зберігає порядок змінених id.

Секрет полягає у типі даних DOUBLE для поля з порядком сортування ItemIndex.

Замість того, щоб перезаписувати всі записи в таблиці та оновлювати їх індекси для відображення нового порядку, ми можемо просто змінити ItemIndex на дробову величину між попереднім і наступним значенням ItemIndex.

Наприклад, якщо ми переміщуємо ItemIndex 8 між ItemIndexes 3 і 4, ми просто оновлюємо індекс переміщеного об'єкта на3.5.

Таким чином при сортуванні по id восьмий елемент відображатиметься рівно між третім і четвертим. Це дозволить зберегти порядок елементів лише одним запитом до бази.

При такій конфігурації таблиці лише залишається порахувати різницю між наступним і попереднім ItemIndexes при обробці операцій зробленоїjQuery UI sortable з переміщенням елементів на початок списку або в кінець списку:

Цей метод має один серйозний мінус — ми можемо втратити можливість збереження індексів при численному розподілі через брак точності речового числа.

Насправді ми можемо повторно розділити величину типу DOUBLE більше тисячі разів, поки не закінчаться уточнення. На практиці, можливо, цього не станеться. Щоб убезпечити себе від втрати точності, необхідно час від часу оновлювати всі індекси в таблиці, наприклад, за допомогою cron завдань або вручну

Цей метод зустріли мною на одному з буржуазних блогів. У статтю я його включив для розширення світогляду, і тому що до нього є вихідники. Особисто мені більше подобається інший варіант збереження сортування для jQuery UI sortable, який я розробив самостійно і використовую його в своєму движку moguta.cms.

Другий приклад збереження jQuery UI sortable

Щоб змінити порядок елементів, нам необхідно мати в таблиці поле sort з цілим типом INT, на відміну, від попереднього прикладу де для аналогічного поля ми використовували тип DOUBLE. Як ви розумієте, нам доведеться міняти місцями значення сортування записів між один одним.

Наприклад, якщо в елементах 1,2,3,4,5 ми міняємо місцями два сусідні елементи 3 і 2, це означає, що в одному рядку таблиці відбудеться заміна індексу з 2 на 3, а в іншому відповідно з 3 на 2. цьому випадку внаступного разу при сортуванні по полю sort нам буде виведено вже послідовність 1,3,2,4,5

Складність полягає у обчисленні всього ланцюжка обмінів при переміщенні, наприклад, 4 елементи на місце перед 2-им. Ось так 1,4,2,3,5.

Для виявлення ланцюжка переміщення мною було розроблено наступний алгоритм. Використовуючи штатні методиjQuery UI sortable такі як start() та update(), ми можемо обробити дві події – початок сортування та її завершення, коли елемент відпущений та встановлений на нову позицію.

Алгоритм збереження сортування jQuery UI sortable:

    На старті перед початком переміщення запам'ятовуємо послідовність >

/** * Дозволяє міняти місцями рядки таблиці, для сортування елементів * tableSelector - селектор об'єкта , таблиця в якій буде доступне сортування рядків * tablename - назва таблиці в базі даних (обов'язково повинна мати поля id та sort) * у рядків таблиці обов'язково має бути атрибут data-id * @returns */ sortable : function ( tableSelector , tablename )

/** * створює масив позицій із заданою міткою на місці переміщуваного елемента * використовується для збереження стартової послідовності та фінальної */ function createArray ( ui , marker ) < var strItems = [ ] ; // пробігаємо по таблиці зберігаючи послідовність id рядків // якщо зустрічаємо > $ (tableSelector). children ( ) . each ( function ( i ) < var tr = $ ( this ) ; if ( tr . data ( "id" ) == ui . item . data ( "id" ) ) < strItems . push ( marker ) ; > else < if ( tr . > >

var list >=[]; var list >= [ ] ;

if ($ (tableSelector). has >( 'ui-sortable' ) ) < $ (tableSelector). sortable ('destroy'); $ (tableSelector). unbind(); >

$ (tableSelector). sortable ( < // на старті перед початком переміщення запам'ятовуємо послідовність id start : function ( event , ui ) < list >= createArray ( ui , 'start' ) ; > ; , // після переміщення запам'ятовується нову послідовність id update : function ( event , ui ) < list >= createArray ( ui , 'end' ) ;

var $thisId = ui . item. data ( "id"); //Обчислює послідовність заміни порядкових індексів var sequence = getSequenceSort (list >, list >, $thisId);

if ( sequence . length > 0 ) < sequence = sequence. join(); admin. ajaxRequest ( < mguniqueurl : "action/changeSortRow" , //метод обробки на сервері switch >: $thisId , sequence : sequence , tablename : tablename , > , function (response) < admin.indication (response. status, response. msg) > ); > > > );

// обчислюємо стартову позицію елемента arr1. forEach ( function ( element , index , array ) < if ( element == "start" ) < startPos = index ; arr1 [ index ] = >; return false ; > >);

// обчислюємо кінцеву позицію елемента arr2. forEach ( function ( element , index , array ) < if ( element == "end" ) < endPos = index ; arr2 [ index ] = >; return false ; > >);

// обчислюємо індекси яким і треба помінятися місцями var result = [];

// напрям перенесення, зверху вниз if ( endPos > startPos ) < arr1. forEach ( function ( element , index , array ) < if ( index >startPos && index endPos) < result. push (element); > > ); >

// напрям перенесення, знизу вгору if (endPos startPos) < arr2. forEach ( function ( element , index , array ) < if ( index > endPos && index startPos ) < result . ); >

Такий підхід як я згадував вище використаний в движку для інтернет-магазинів Moguta.CMS при сортуванні продуктів. Ось вирізка javascript функції, що реалізує даний алгоритм:

Плюси очевидні основа завжди в актуальному стані, а всі розрахунки відбуваються на комп'ютері клієнта.

На погляд збільшення кількості запитів пропорційно кількості перестановок.

На практиці якщо порівнювати цей спосіб з першим, оновлення по крону буде проводити постійно кількість запитів стільки ж, але щодня.