4

I used the examples of this question to create drag-and-drop-script I could use on a web application.

After re-designing it for my own purposes, there are some features I'd like to have implemented. I've been trying for myself a while, but I haven't found the soulution yet...

associated jsfiddle: http://jsfiddle.net/BLLTH/

Features:

  • already added objects should be removed from the available list

  • removing an added object by clicking on an "x"-symbol, which puts it back to the available list

  • objects must be in the same order as they were added

any ideas? =)

templates:

<script type="text/x-handlebars" >  
<b>Available Objects</b><br /><br />
{{#each App.objectsController}}
    {{#view App.ObjectView contentBinding="this"}}
        {{view.content.name}}<br />
    {{/view}}
{{/each}}
<br /><br /><br /><br />
{{#view App.ObjectDropTarget dragContextBinding="App.objectsController.currentDragItem"}}
    {{#each App.cartController}}
        {{#view App.ObjectView contentBinding="this" class="single"}}                
            {{view.content.name}}
        {{/view}}
    {{/each}}  
{{/view}}

javascript:

App = Em.Application.create({});
DragNDrop = Em.Namespace.create();
DragNDrop.cancel = function(event) {
    event.preventDefault();
    return false;
};
DragNDrop.Draggable = Em.Mixin.create({
    attributeBindings: 'draggable',
    draggable: 'true',
    dragStart: function(event) {
        var dataTransfer = event.originalEvent.dataTransfer;
        dataTransfer.setData('Text', this.get('elementId'));
    }
});
DragNDrop.Droppable = Em.Mixin.create({
    dragEnter: DragNDrop.cancel,
    dragOver: DragNDrop.cancel,
    drop: function(event) {
        event.preventDefault();
        return false;
    }
});
App.Object = Em.Object.extend({
    name: null,
    isAdded: null
});
App.ObjectView = Em.View.extend(DragNDrop.Draggable, {
    tagName: 'div',
    // .setDragImage (in #dragStart) requires an HTML element as the first argument
    // so you must tell Ember to create the view and it's element and then get the 
    // HTML representation of that element.  
    dragStart: function(event) {
        this._super(event);
        // Let the controller know this view is dragging
        this.setPath('content.isDragging', true);
        // Set the drag image and location relative to the mouse/touch event     
    },
    dragEnd: function(event) {
        // Let the controller know this view is done dragging
        this.setPath('content.isDragging', false);
    }
});
App.ObjectDropTarget = Em.View.extend(DragNDrop.Droppable, {
    tagName: 'div',
    classNames: ['dropTarget'],
    classNameBindings: ['cartAction'],
    // This will determine which class (if any) you should add to
    // the view when you are in the process of dragging an item.
    drop: function(event) {
        var viewId = event.originalEvent.dataTransfer.getData('Text'),
        view = Em.View.views[viewId];
        // Set view properties
        // Must be within `Ember.run.next` to always work
        Em.run.next(this, function() {
            view.setPath('content.isAdded', !view.getPath('content.isAdded'));
        });
        return this._super(event);
    }
});
App.objectsController = Em.ArrayController.create({
    content: [
    App.Object.create({
        name: "Object 1",
        isAdded: false
    }),
    App.Object.create({
        name: "Object 2",
        isAdded: false
    }),
    App.Object.create({
        name: "Object 3",
        isAdded: false
    }),
    App.Object.create({
        name: "Object 4",
        isAdded: false
    })
    ],
    currentDragItem: Em.computed(function(key, value) {
        return this.findProperty('isDragging', true);
    }).property('@each.isDragging').cacheable(),
    objectsInCart: Em.computed(function(key, value) {
        return this.filterProperty('isAdded', true);
    }).property('@each.isAdded').cacheable()
});
App.cartController = Em.ArrayController.create({
    content: Em.computed(function(key, value) {
        var cartItems = this.get('cartItems');
        if (!Em.empty(cartItems)) {
            // Sort desc by name
            return cartItems.sort(function(a, b) {
                 if ((a.get('name').toLowerCase()) < (b.get('name').toLowerCase())) return -1;
                 else return 1;
            });
        }
    }).property('cartItems').cacheable(),
    cartItemsBinding: 'App.objectsController.objectsInCart'
 });​
Community
  • 1
  • 1
Ajuhzee
  • 85
  • 5

1 Answers1

3

I've implemented the first two features for you here http://jsfiddle.net/QE9CS/

"already added objects should be removed from the available list" was achieved by creating another computed property on your array.

"removing an added object by clicking on an "x"-symbol, which puts it back to the available list" just uses a standard Ember {{action}} helper.

EDIT:

Full version http://jsfiddle.net/R9hnY/ I have turned isAdded into a computed property which sets the value on the object and adds or removes the object from the cartController's content at the right time. Thus giving the cartController an ordered array of objects to render from.

Bradley Priest
  • 7,438
  • 1
  • 29
  • 33