2012-05-25 41 views
23

簡而言之,我試圖重現jquery-ui的購物車演示的基本版本:http://jqueryui.com/demos/droppable/shopping-cart.html,其中包含ember.js和HTML5原生拖放。Ember.js + HTML5拖放購物車演示

先前試圖執行拖放與Ember +的jQuery UI的下降,並使用此解決方案時遇到困難後:http://jsfiddle.net/Wu2cu/2/,我看到pangratz的HTML5解決方案:http://jsfiddle.net/pangratz666/DYnNH/,決定給它一個鏡頭。

我已付出pangratz的的jsfiddle,創建了一個ProductsController的和基於一個isAdded屬性過濾ProductsController中addedToCartController:http://jsfiddle.net/GU8N7/3/

這工作正常,但後來我碰到困難時,我嘗試使用#each迭代器和將獨特的可拖動視圖添加到迭代器中的每個對象。我希望能夠拖動每個「產品」對象,當它放入「購物車」區域時,將該對象的isAdded屬性設置爲true,從而使其顯示在「購物車」中。

任何幫助將不勝感激!

(也作爲獎金,我想打在購物車中的項目排序,但是這可能是過分的要求,直到第一橋交叉。)

回答

47

看看代碼下面是一個解決方案(有一些額外的)。包含購物車物品的分類(參見JS末尾的cartController)。

這裏還有一個小提琴:http://jsfiddle.net/ud3323/5uX9H/

更新:添加了一個拖放圖像示例。

把手

<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

非常感謝,真是太棒了!你在回答問題時超越了自己。非常感謝您的幫助!我將通過拖放產品照片的克隆來實現這一點 - 是否有任何簡單的方法在此演示中實現克隆拖動?再次感謝這麼多人,你踢了很多屁股。 –

+1

我已更新以顯示如何使用拖動圖標。 –

+1

您好,先生,是個紳士和學者 –

2

我一直在尋找一個拖ñ下降前emple和找到你,我的代碼更新稍微1.0.0-RC5和項目能力的樂趣增添雙擊...

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

把手

<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

非常感謝您的更新!然而,jsfiddle實際上並沒有工作:( –

+1

jsfiddle沒有工作,因爲把手沒有作爲依賴項添加。我將ember版本更改爲unminified版本,並添加了handlebars,它工作正常!再次感謝。 jsfiddle.net/jlsuttles/bc5sn/ –