2012-05-25 10 views
23

En resumen, estoy tratando de reproducir una versión básica de la demostración del carrito de la compra de jquery-ui: http://jqueryui.com/demos/droppable/shopping-cart.html con ember.js y arrastrar y soltar HTML5 nativo.Ember.js + HTML5 arrastrar y soltar el carrito de compras demo

Después de haber estado tratando de implementar arrastrar y soltar con brasa + jquery-ui y tener dificultad para usar esta solución: http://jsfiddle.net/Wu2cu/2/, vi solución HTML5 de Pangratz: http://jsfiddle.net/pangratz666/DYnNH/ y decidió darle una oportunidad.

He bifurcada jsFiddle de Pangratz, crearon un ProductsController y un addedToCartController que filtra la ProductsController basado en una propiedad isAdded: http://jsfiddle.net/GU8N7/3/

que funciona bien, pero luego se queda bloqueado cuando trato de utilizar un iterador #each y agregar vistas únicas que se pueden arrastrar a cada objeto en el iterador. Quiero poder arrastrar cada objeto "producto", y cuando se coloca en el área "carrito de compras", establezca la propiedad de propiedad de ese objeto como verdadera, haciendo que aparezca en el "carrito de compras".

¡Cualquier ayuda sería muy apreciada!

(también como un bono, me gustaría hacer los artículos en el carro de compras se puede ordenar, pero eso es probablemente demasiado pedir hasta que se cruzó el primer puente.)

Respuesta

47

Tome un vistazo al código a continuación para una solución (con algunos extras). La clasificación de los artículos del carrito está incluida (ver cartController al final del JS).

Y un violín que funciona aquí: http://jsfiddle.net/ud3323/5uX9H/.

ACTUALIZACIÓN: Se ha agregado un ejemplo de imagen de arrastre.

Manillar

<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

Gracias tanto hombre, eso es increíble! Usted fue más allá al responder la pregunta. ¡Muchas, muchas gracias por tu ayuda! Voy a implementar esto con arrastrar clones de fotos de productos. ¿Hay alguna manera fácil de implementar clonar arrastrando en esta demostración? Una vez más, muchas gracias hombre, pateas mucho culo. –

+1

Tengo una actualización para mostrar cómo usar un ícono de arrastre. –

+1

Usted señor, es un caballero y un erudito –

2

que estaba buscando un arrastrar y soltar ex emple y encontrar el suyo, he actualizado el código levemente a 1.0.0-RC5 y añaden un doble clic sobre la capacidad elemento para la diversión ...

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

Manillar

<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

¡Muchas gracias por actualizar! Sin embargo, jsfiddle en realidad no funciona :( –

+1

El archivo jsfiddle no funcionó porque no se agregaron manillares como dependencia. Cambié la versión de correo electrónico a la versión no miniaturizada y agregué manillares, ¡y funciona! Gracias de nuevo. Http: // jsfiddle.net/jlsuttles/bc5sn/ –

Cuestiones relacionadas