Skip to content

Instantly share code, notes, and snippets.

@lolmaus
Forked from lolmaus1/components.the-item.js
Last active November 15, 2017 08:12
Show Gist options
  • Save lolmaus/0a52fd0d8e8a81cdca008023f5798cdf to your computer and use it in GitHub Desktop.
Save lolmaus/0a52fd0d8e8a81cdca008023f5798cdf to your computer and use it in GitHub Desktop.
ember-drag-sort with Ember Data and rowOrder
import Ember from 'ember'
export default Ember.Component.extend({
classNames: ['the-item'],
})
import Ember from 'ember'
export default Ember.Controller.extend({
actions : {
dragEnd ({sourceList, sourceIndex, targetList, targetIndex}) {
if (sourceList === targetList && sourceIndex === targetIndex) return
const draggedItem = sourceList.objectAt(sourceIndex)
// Updating rowOrder of items in source list
sourceList
.slice(sourceIndex + 1)
.forEach(item => {
const rowOrder = item.get('rowOrder')
item.set('rowOrder', rowOrder - 1)
})
// Updating rowOrder of items in target list
targetList
.slice(targetIndex)
.forEach(item => {
const rowOrder = item.get('rowOrder')
item.set('rowOrder', rowOrder + 1)
})
// Updating rowOrder of dragged item
draggedItem.set('rowOrder', targetIndex)
// Moving dragged item into the target list
// We can't do it directly because the list is a derived one,
// so we need to access the original list using a hack from the model
targetList
.__parent__
.get('children')
.addObject(draggedItem)
// Note, that we don't need to remove the item from the source list.
// Ember Data does this automatically because our relationship is
// two-way.
},
},
})
import Model from "ember-data/model"
import attr from "ember-data/attr"
import { belongsTo, hasMany } from "ember-data/relationships"
export default Model.extend({
rowOrder: attr('number'),
parent: belongsTo('item', {inverse: 'children', async: false}),
children: hasMany('item', {inverse: 'parent', async: false}),
childrenSortOrder: ['rowOrder:asc'],
childrenSorted: Ember.computed.sort('children', 'childrenSortOrder'),
childrenSortedBound: Ember.computed('childrenSorted.[]', function () {
const children = this.get('childrenSorted').slice() // Making a shallow copy of the array, because CPs should never have side effects
children.__parent__ = this
return children
})
})
import Ember from 'ember'
const payload = {
data: [
{
type: 'item',
id: '0',
attributes: { rowOrder: 0 },
relationships: {
parent: { data: { type: 'item', id: '0' } },
children: {
data: [
{type: 'item', id: '1'},
{type: 'item', id: '4'},
]
}
}
},
{
type: 'item',
id: '1',
attributes: { rowOrder: 0 },
relationships: {
parent: { data: { type: 'item', id: '0' } },
children: {
data: [
{type: 'item', id: '2'},
{type: 'item', id: '3'},
]
}
}
},
{
type: 'item',
id: '2',
attributes: { rowOrder: 0 },
relationships: {
parent: { data: { type: 'item', id: '1' } },
children: {
data: []
}
}
},
{
type: 'item',
id: '3',
attributes: { rowOrder: 1 },
relationships: {
parent: { data: { type: 'item', id: '1' } },
children: {
data: []
}
}
},
{
type: 'item',
id: '4',
attributes: { rowOrder: 1 },
relationships: { parent: { data: { type: 'item', id: '0' } },
children: {
data: [
{type: 'item', id: '5'},
{type: 'item', id: '6'},
]
}
}
},
{
type: 'item',
id: '5',
attributes: { rowOrder: 0 },
relationships: {
parent: { data: { type: 'item', id: '4' } },
children: {
data: []
}
}
},
{
type: 'item',
id: '6',
attributes: { rowOrder: 1 },
relationships: {
parent: { data: { type: 'item', id: '4' } },
children: {
data: []
}
}
},
],
}
export default Ember.Route.extend({
model () {
const store = this.get('store')
store.push(payload)
return store.peekRecord('item', '0')
}
})
body {
margin: 12px 16px;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 12pt;
}
.the-item {
margin: 4px;
padding: 1em;
border: 1px solid black;
display: flex;
}
.the-item-title {
flex-shrink: 0;
flex-grow: 0;
width: 100px;
}
.the-item .dragSortList {
flex-shrink: 0;
flex-grow: 1;
}
.the-item .dragSortList.-isExpanded {
padding-top: 55px;
}
.the-item .dragSortList.-isDragging {
outline: 2px dashed black;
background-color: deepskyblue;
}
.the-item .dragSortList.-isExpanded.-isDraggingOver:before {
top: 15px;
}
.the-item {
background-color : #FFD0E9;
}
.the-item .the-item {
background-color: #FFAAD7;
}
.the-item .the-item .the-item {
background-color: #FF8CC9;
}
.the-item .the-item .the-item .the-item {
background-color: #FF74BD;
}
.the-item .the-item .the-item .the-item .the-item {
background-color: #FF60B4;
}
.the-item .the-item .the-item .the-item .the-item .the-item {
background-color: #FF50AD;
}
{{the-item
item = model
dragEndAction = (action 'dragEnd')
}}
<div>
<h3 class = "the-item-title">
id: {{item.id}}
</h3>
<p class = "the-item-title">
order: {{item.rowOrder}}
</p>
</div>
{{#drag-sort-list
items = item.childrenSortedBound
group = group
dragEndAction = dragEndAction
as |child|
}}
{{the-item
item = child
group = group
dragEndAction = dragEndAction
}}
{{/drag-sort-list}}
{
"version": "0.12.1",
"EmberENV": {
"FEATURES": {}
},
"options": {
"use_pods": false,
"enable-testing": false
},
"dependencies": {
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js",
"ember": "2.12.0",
"ember-template-compiler": "2.12.0",
"ember-testing": "2.12.0"
},
"addons": {
"ember-data": "2.12.1",
"ember-drag-sort": "1.0.2",
"ember-truth-helpers": "2.0.0"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment