Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sortable on ember.js #175

Closed
trampos opened this issue Dec 16, 2014 · 17 comments
Closed

Sortable on ember.js #175

trampos opened this issue Dec 16, 2014 · 17 comments

Comments

@trampos
Copy link

trampos commented Dec 16, 2014

I found an issue trying to use "sortable" with ember.js, i would appreciate if someone could explain to me why this happens.

well, the issue is in the line 447, where you have a condition to appendChild instead of insertBefore, if it's in the end of the list. After sorting an item to the end of the list, ember reload the list, but for some reason it doesn't remove the "appended" item. This code below fixed my problem, ive changed the line 447.

from:
el.appendChild(dragEl);

to:
target.parentNode.insertBefore(dragEl, target.nextSibling); // got this from jQuery.after source.

My english is not good, sorry.

@RubaXa
Copy link
Collaborator

RubaXa commented Dec 16, 2014

  1. Try dev-branch
  2. if not helped, create example on jsbin.com

@trampos
Copy link
Author

trampos commented Dec 16, 2014

http://jsbin.com/woxalasiru/1/edit

I don't know why the first item doesn't reproduce the error, but drag the second item to the bottom of the list, then click on reload. You will see that ember can't remove the item.

One more clue to confirm that it's the appendChild function that is causing the error: Drag the item 2 to the end of the list, then drag it back to somewhere, then click on reload, you will see that it will behave right.

@trampos
Copy link
Author

trampos commented Dec 17, 2014

i made another jsbin without sortable, showing what appendChild and insertBefore does with ember lists http://jsbin.com/liruxureke/1/edit?html,js,output

@RubaXa
Copy link
Collaborator

RubaXa commented Dec 17, 2014

I do not know what help you, I have no experience with Ember.

@trampos
Copy link
Author

trampos commented Dec 17, 2014

I hope someone help us then, i think this issue is more about the usage of appendChild vs insertBefore, they look more similar than they really are

@kozak
Copy link

kozak commented Dec 19, 2014

Ember uses metamorph script tags, to handle data binding, http://emberjs.com/guides/understanding-ember/keeping-templates-up-to-date/. This causes problems with sorting libraries. I am not sure if this is the exact issue, but for me the workaround was to use the CollectionView (http://emberjs.com/api/classes/Ember.CollectionView.html) which creates child elements without metamorphs in between.

@trampos
Copy link
Author

trampos commented Dec 19, 2014

I thihnk the version of ember that i included is using metal views that doesn't use metamorph script tags anymore

@kozak
Copy link

kozak commented Dec 19, 2014

Ahh nice, I thought this functionality will be available in 2.0. But it seems 1.9 already does it. Thanks for the info -- good to know.

@maxkueng
Copy link

I'm experiencing the same or a similar issue. When I drag-sort the dragged element sometimes appears twice in the DOM. It only happens when I store the sort order back in to the model which causes Ember to re-render the list and the cloned item remains.

@cdunn
Copy link

cdunn commented Dec 26, 2014

I was having a similar problem: http://jsbin.com/jikurimeyo/2/edit?html,js,output
If you drag 'one' to the end and then remove 'three' it kills the last 2 elements.

I banged my head on this for awhile and ended up with jquery ui sortable (ugh) and used the sortable('cancel') to revert the drag and manually update the order in ember.

It doesn't seem like a Sortable issue but more like Ember doesn't work out of the box with the way the sortable libraries manipulate the templates.

If anyone figures out anything better lmk.

@sandstrom
Copy link

With minor adjustments jQuery sortable can be implemented in Ember using the cancel event[1][2]. The trick is to (1) cancel the update in an onUpdate handler (whilst taking note of the new/desired order) and (2) use Ember to change the actual order of elements (it's also common to save the new order to the server).

I'm guessing something similar would be possible here. To either cancel the reorder globally, or from within the onUpdate handler.

@RubaXa Is it possible to add a cancel-method of some sort to this awesome library? 😄

[1] https://code.google.com/p/jquery-ui/source/browse/trunk/ui/jquery.ui.sortable.js?r=3706#344
[2] http://api.jqueryui.com/sortable/#method-cancel

@coddingtonbear
Copy link

I ran into the same thing as the above folks did when using this library, but was able to work around it by instead sorting the array just once before rendering; it looks like it's only a problem if one uses Ember.SortableMixin which will automatically re-order the list when whatever fields used as the sorting index are changed.

@RubaXa RubaXa closed this as completed Apr 10, 2015
@sandstrom
Copy link

@RubaXa I'd love to hear your thoughts on a cancel method! (see above)

@RubaXa
Copy link
Collaborator

RubaXa commented Apr 10, 2015

Cancel sorting should occur during event processing.
But there is no time to do this, only plans.

@tp
Copy link

tp commented Apr 16, 2015

For anyone finding this issue: Since there won't be official support in the near-term, here is my solution:

I created a SortableList component.

JS:

import Ember from 'ember';
import Sortable from 'npm:sortablejs';

export default Ember.Component.extend({
  init: function() {
    this._super();

    Ember.assert('required `viewModels` param is set', !Ember.isNone(this.get('viewModels')));
  },
  tagName: 'ul',
  classNames: ['topicReferenceList'],
  actions: {
    removeItem: function(index) {
      this.sendAction('removeItem', index);
    }
  },
  didInsertElement: function() {
    console.debug('Setup Sortable in didInsertElement');

    let s = Sortable.create(document.getElementById(this.get('elementId')), {
      draggable: ".sortableTopicListItem",
      onSort: (evt) => {
        if (evt.type !== 'sort') {
          console.debug('Skipping event that is not sort.')
          return;
        }

        if (evt.oldIndex === evt.newIndex) {
          console.debug('NOOP, evt.oldIndex === evt.newIndex; not sending action; not removing element');
          return;
        }

        console.debug('sortable onSort');
        console.debug(`evt.oldIndex = ${evt.oldIndex} -> evt.newIndex = ${evt.newIndex}`);
        console.debug(evt.item);

        let dragItem = evt.item;
        dragItem.parentNode.removeChild(dragItem);

        this.sendAction('itemMoved', evt.oldIndex, evt.newIndex);
      },
    });

    this.set('Sortable', s);

    console.debug('Done setting up Sortable in didInsertElement');
  },
  willDestroyElement: function() {
    console.debug('destroying Sortable');
    this.get('Sortable').destroy();
  }
});
{{#each viewModels as |viewModel index| }}
  <li class="sortableTopicListItem">{{viewModel.displayName}} <i {{action removeItem index}} class="remove">✖</i></li>
{{/each}}

Usage is easy like this:

  {{sortable-list viewModels=references moveItem ='moveItem' removeItem='removeItem'}}

The actions are called on the using component with the indexes, so you can change your data model after moves / deletions occurred.

Hope this helps anyone finding this issue 😃

@MaazAli
Copy link

MaazAli commented Apr 16, 2015

Take a look at this ember-cli-addon, it's a work in progress but it's working pretty well: https://github.com/MaazAli/ember-cli-sortable

@owen-m1
Copy link
Member

owen-m1 commented Jun 7, 2019

Here is the official version: https://github.com/SortableJS/ember-sortablejs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants