2012-05-25 17 views
23

In breve, sto cercando di riprodurre una versione di base della demo del carrello acquisti di jquery-ui: http://jqueryui.com/demos/droppable/shopping-cart.html con ember.js e HTML5 nativo di trascinamento.Ember.js + HTML5 drag and drop demo carrello acquisti

Dopo aver in precedenza cercando di attuare il drag and drop con brace + jquery-ui e avere difficoltà ad usare questa soluzione: http://jsfiddle.net/Wu2cu/2/, vidi la soluzione HTML5 di Pangratz: http://jsfiddle.net/pangratz666/DYnNH/ e ha deciso di dare un colpo.

ho biforcuta jsfiddle di Pangratz, ha creato un ProductsController e un addedToCartController che filtra il ProductsController in base a una proprietà isAdded: http://jsfiddle.net/GU8N7/3/

Questo funziona bene, ma poi mi si blocca quando si tenta di utilizzare un iteratore #each e aggiungi viste draggabili uniche a ciascun oggetto nell'iteratore. Voglio essere in grado di trascinare ogni oggetto "prodotto" e quando viene rilasciato nell'area "carrello della spesa", impostare la proprietà isAdded dell'oggetto su true, quindi visualizzarla nel "carrello della spesa".

Qualsiasi aiuto sarebbe molto apprezzato !!

(anche come bonus, mi piacerebbe fare gli elementi nel carrello ordinabili, ma questo è probabilmente troppo chiedere fino al primo ponte è attraversato.)

risposta

47

Date un'occhiata al codice di sotto per una soluzione (con alcuni extra). L'ordinamento degli articoli del carrello è incluso (vedi cartController alla fine del JS).

E un violino funzionante qui: http://jsfiddle.net/ud3323/5uX9H/.

AGGIORNAMENTO: Aggiunto un esempio di immagine di trascinamento.

Manubrio

<script type="text/x-handlebars" > 
    <b>Available Products</b> 
    <br /><br /> 
    {{#each App.productsController}} 
     {{#view App.ProductView contentBinding="this"}} 
     {{content.name}} 
     {{/view}}<br /> 
    {{/each}} 
    <hr /> 

    {{#view App.ProductDropTarget 
      dragContextBinding="App.productsController.currentDragItem"}} 
    Shopping Cart 
    <div style="height: 20px">{{helpText}}</div> 
    {{/view}} 
    <br /> 
    {{#each App.cartController}} 
     {{#view App.ProductView contentBinding="this"}} 
     {{content.name}} 
     {{/view}}<br /> 
    {{/each}}  
</script>​ 

JavaScript:

App = Ember.Application.create({}); 

DragNDrop = Ember.Namespace.create(); 

DragNDrop.cancel = function(event) { 
    event.preventDefault(); 
    return false; 
}; 

DragNDrop.Draggable = Ember.Mixin.create({ 
    attributeBindings: 'draggable', 
    draggable: 'true', 
    dragStart: function(event) { 
     var dataTransfer = event.originalEvent.dataTransfer; 
     dataTransfer.setData('Text', this.get('elementId')); 
    } 
}); 

DragNDrop.Droppable = Ember.Mixin.create({ 
    dragEnter: DragNDrop.cancel, 
    dragOver: DragNDrop.cancel, 
    drop: function(event) { 
     event.preventDefault(); 
     return false; 
    } 
}); 

App.Product = Ember.Object.extend({ 
    name: null, 
    isAdded: null 
}); 

App.ProductView = Ember.View.extend(DragNDrop.Draggable, { 
    tagName: 'span', 

    // .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. 
    dragIconElement: Ember.View.create({ 
     attributeBindings: ['src'], 
     tagName: 'img', 
     src: 'http://twitter.com/api/users/profile_image/twitter' 
    }).createElement().get('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 
     var dataTransfer = event.originalEvent.dataTransfer; 
     dataTransfer.setDragImage(this.get('dragIconElement'), 24, 24); 
    }, 

    dragEnd: function(event) { 
     // Let the controller know this view is done dragging 
     this.setPath('content.isDragging', false); 
    } 
}); 

App.ProductDropTarget = Ember.View.extend(DragNDrop.Droppable, { 
    tagName: 'div', 
    classNames: ['dropTarget'], 
    classNameBindings: ['cartAction'], 
    helpText: null, 

    // This will determine which class (if any) you should add to 
    // the view when you are in the process of dragging an item. 
    cartAction: Ember.computed(function(key, value) { 
     if(Ember.empty(this.get('dragContext'))) { 
      this.set('helpText','(Drop Zone)'); 
      return null; 
     } 

     if(!this.getPath('dragContext.isAdded')) { 
      this.set('helpText', '(Drop to Add)'); 
      return 'cart-add'; 
     } else if(this.getPath('dragContext.isAdded')) { 
      this.set('helpText', '(Drop to Remove)'); 
      return 'cart-remove'; 
     } else { 
      this.set('helpText', '(Drop Zone)'); 
      return null; 
     } 

    }).property('dragContext').cacheable(), 

    drop: function(event) { 
     var viewId = event.originalEvent.dataTransfer.getData('Text'), 
      view = Ember.View.views[viewId]; 

     // Set view properties 
     // Must be within `Ember.run.next` to always work 
     Ember.run.next(this, function() { 
      view.setPath('content.isAdded', !view.getPath('content.isAdded')); 
     }); 

     return this._super(event); 
    } 
}); 

App.productsController = Ember.ArrayController.create({ 
    content: [ 
     App.Product.create({ name: "MacBook Pro", isAdded: false }), 
     App.Product.create({ name: "iPhone", isAdded: false }), 
     App.Product.create({ name: "iPad", isAdded: true }), 
     App.Product.create({ name: "iTV", isAdded: false }) 
    ], 

    currentDragItem: Ember.computed(function(key, value) { 
     return this.findProperty('isDragging', true); 
    }).property('@each.isDragging').cacheable(), 

    productsInCart: Ember.computed(function(key, value) { 
     return this.filterProperty('isAdded', true); 
    }).property('@each.isAdded').cacheable() 

}); 

App.cartController = Ember.ArrayController.create({  
    content: Ember.computed(function(key, value) { 
     var cartItems = this.get('cartItems'); 

     if(!Ember.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.productsController.productsInCart' 
}); 

+3

Grazie mille, è fantastico! Sei andato ben oltre nel rispondere alla domanda. Molte grazie per il tuo aiuto! Ho intenzione di implementarlo con il trascinamento dei cloni delle foto dei prodotti. C'è un modo semplice per implementare il clone durante questa demo? Ancora una volta, grazie mille amico, prendi a calci un sacco di culo. –

+1

Ho aggiornato per mostrare come usare un'icona di trascinamento. –

+1

Tu signore, sei un gentiluomo e uno studioso –

2

ero alla ricerca di un drag'n'drop ex emple e trovare la vostra, ho aggiornato il codice leggermente a 1.0.0-RC5 e aggiungere un doppio click sulla capacità oggetto per il divertimento ...

http://jsfiddle.net/kadactivity/hhBrM/1/

Manubrio

<script type="text/x-handlebars" > 
    <b>Available Products</b> 
    <br /><br /> 
    {{#each product in model}} 
     {{#view App.ProductView contentBinding="product"}} 
      {{view.content.name}} 
     {{/view}}<br /> 
    {{/each}} 
    <hr /> 

    {{#view App.ProductDropTarget 
     dragContextBinding="currentDragItem"}} 
    Shopping Cart 
    <div style="height: 20px">{{helpText}}</div> 
    {{/view}} 
    <br /> 
    {{#each cart in productsInCart}} 
     {{#view App.ProductView contentBinding="cart"}} 
      {{view.content.name}} 
     {{/view}}<br /> 
    {{/each}}  
</script> 

Javascript

App = Ember.Application.create(); 

App.Router.map(function() { 
    // put your routes here 
}); 

App.ApplicationRoute = Ember.Route.extend({ 
    model: function() { 
    return [ 
     App.Product.create({ name: "MacBook Pro", isAdded: false }), 
     App.Product.create({ name: "iPhone", isAdded: false }), 
     App.Product.create({ name: "iPad", isAdded: true }), 
     App.Product.create({ name: "iTV", isAdded: false }) 
    ]; 
    } 
}); 

DragNDrop = Ember.Namespace.create(); 

DragNDrop.cancel = function(event) { 
    event.preventDefault(); 
    return false; 
}; 

DragNDrop.Draggable = Ember.Mixin.create({ 
    attributeBindings: "draggable", 
    draggable: "true", 
    dragStart: function(event) { 
    var dataTransfer = event.originalEvent.dataTransfer; 
    dataTransfer.setData("Text", this.get("elementId")); 
    } 
}); 

DragNDrop.Droppable = Ember.Mixin.create({ 
    dragEnter: DragNDrop.cancel, 
    dragOver: DragNDrop.cancel, 
    drop: function(event) { 
    event.preventDefault(); 
    return false; 
    } 
}); 

App.Product = Ember.Object.extend({ 
    name: null, 
    isAdded: null 
}); 

App.ProductView = Ember.View.extend(DragNDrop.Draggable, { 
    tagName: "span", 

    // .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. 
    dragIconElement: Ember.View.create({ 
    attributeBindings: ["src"], 
    tagName: "img", 
    src: "http://twitter.com/api/users/profile_image/twitter" 
    }).createElement().get("element"), 

    dragStart: function(event) { 
    this._super(event); 
    // Let the controller know this view is dragging 
    this.set("content.isDragging", true); 

    // Set the drag image and location relative to the mouse/touch event 
    var dataTransfer = event.originalEvent.dataTransfer; 
    dataTransfer.setDragImage(this.get("dragIconElement"), 24, 24); 
    }, 

    dragEnd: function(event) { 
    // Let the controller know this view is done dragging 
    this.set("content.isDragging", false); 
    }, 

    doubleClick: function(event) { 
    this.set("content.isAdded", !this.get("content.isAdded")); 
    } 
}); 

App.ProductDropTarget = Ember.View.extend(DragNDrop.Droppable, { 
    tagName: "div", 
    classNames: ["dropTarget"], 
    classNameBindings: ["cartAction"], 
    helpText: null, 

    // This will determine which class (if any) you should add to 
    // the view when you are in the process of dragging an item. 
    cartAction: function() { 
    if(Ember.isEmpty(this.get("dragContext"))) { 
     this.set("helpText","(Drop Zone)"); 
     return null; 
    } 

    if(!this.get("dragContext.isAdded")) { 
     this.set("helpText", "(Drop to Add)"); 
     return "cart-add"; 
    } else if(this.get("dragContext.isAdded")) { 
     this.set("helpText", "(Drop to Remove)"); 
     return "cart-remove"; 
    } else { 
     this.set("helpText", "(Drop Zone)"); 
     return null; 
    } 

    }.property("dragContext"), 

    drop: function(event) { 
    var viewId = event.originalEvent.dataTransfer.getData("Text"), 
     view = Ember.View.views[viewId]; 

    // Set view properties 
    // Must be within `Ember.run.next` to always work 
    Ember.run.next(this, function() { 
     view.set("content.isAdded", !view.get("content.isAdded")); 
    }); 

    return this._super(event); 
    } 
}); 

App.ApplicationController = Ember.ArrayController.extend({ 
    currentDragItem: function() { 
     return this.findProperty("isDragging", true); 
    }.property("@each.isDragging"), 

    productsInCart: function() { 
    var cartItems = this.filterProperty("isAdded", true); 
    console.log(cartItems); 
    if(!Ember.isEmpty(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("@each.isAdded") 
}); 
+0

Grazie mille per l'aggiornamento! Tuttavia, il jsfiddle in realtà non funziona :( –

+1

Il jsfiddle non ha funzionato perché il manubrio non è stato aggiunto come dipendenza.Ho cambiato la versione di ambra nella versione non ancora terminata e ho aggiunto manubri e funziona! Grazie ancora. Http: // jsfiddle.net/jlsuttles/bc5sn/ –