2016-01-20 8 views
5

Ich lerne Spree 3.0 und ich habe einen Setup-Test-Shop, der Shorts verkauft.Spree Dropdown-Boxen für Variante Option Werte

Shorts hat mehrere Optionstypen: Größe, Farbe, Länge

ich den Weg, es zeigt die Variante Optionen auf dem Frontend von einem Radiokontrollkästchen, um ein Dropdown-Feld ändern wollte.

Derzeit Spree zeigt die Optionstypen wie Radio-Buttons:

Current Spree setup

Ich möchte diese Menüs für jede Option Typ Drop-Down zu verwenden, um ändern, wie folgt aus:

What I want Spree to do

Ich habe folgendes versucht:

<%= select_tag "variant_id", options_for_select(@product.variants_and_option_values(current_currency).collect{ |v| ["#{variant_options(v)} #{variant_price(v)}", v.id] })%> 

Aber es zeigt einfach die Werte aller Optionstypen in jedem tag:

Dropdown with all the option types 1

Dropdown with all the option types 2

ich die beste Art und Weise zu spalten die Optionswerte in einzelne Dropdown-Menüs wissen wollte?

Jede Hilfe ist meine sehr geschätzt, danke.

Antwort

4

Das ist nicht so einfach wie es aussieht, da Sie Spree::OptionValue Datensätze statt Varianten verwenden werden, und irgendwann werden Sie wollen Varianten konvertieren, um wieder es in Ihren Warenkorb hinzuzufügen. Kombinationen sind möglicherweise nicht möglich und/oder nicht auf Lager, so dass es sehr unpraktisch ist, mit option_values ​​zu arbeiten.

Aber dennoch, Sie wollten wissen, wie so einrichten ich die folgende:

@options = Spree::OptionValue.joins(:option_value_variants).where(spree_option_value_variants: { variant_id: @product.variant_ids }).group_by(&:option_type) 

Dies gibt Ihnen einen Hash mit den Tasten des Hash sein option_types (Größe, Farbe, Länge in Ihrem Fall) und die Werte sind Arrays von option_values.

Sie können diese leicht in Radios wie folgt bilden:

<% @options.each do |option_type, option_values| %> 
    <%= content_tag :h2, option_type.presentation %> 
    <% option_values.each do |option_value| %> 
    <%= radio_button_tag option_type.name, option_value.id %> 
    <%= label_tag option_value.presentation %> 
    <% end %> 
<% end %> 

Oder für Dropdown-Listen:

<% @options.each do |option_type, option_values| %> 
    <%= content_tag :h2, option_type.presentation %> 
    <%= collection_select :variants, option_type.name, option_values, :id, :presentation %> 
<% end %> 

Und in Ihrem Controller würden Sie eine Variante passende diese drei Kriterien finden möchten, prüfen Sie, ob es ist in_stock, backorderable oder track_inventory? ist false und reagiert mit Fehlern oder einem aktualisierten Warenkorb :)

Ich hoffe, das hat geholfen

+0

Vielen Dank für die Antwort Fabian. Es sieht schwierig aus. Ich habe speziell Dropdown-Boxen angeschaut. Vielleicht könnte eine Javascript-Lösung die Antwort sein und die Radios verstecken. –

+0

Radios können leicht in eine Auswahl konvertiert werden. Es ist die gleiche Art von Sache, wählen Sie eine Option aus einer Reihe von Optionen in einem Kontext. Ich habe dies zuvor in einem SPA implementiert und ich habe die API verwendet, um alle Varianten von einem Produkt zu bekommen, und dann für die Varianten, bei denen "in_stock: true" die Optionswerte gesammelt und dem Benutzer nur diese Optionswerte angezeigt hat. Oder vielleicht die Optionen für vergriffene Varianten ausgrauen –

+0

Nochmals vielen Dank @Fabian de Pabian, ich muss dies verdauen und herausfinden, wie man es implementiert. Ich kann das Radio einfach in das Dropdown-Menü umwandeln, aber es gibt Optionstypen pro Produkt in einem Dropdown-Menü, anstatt eines Dropdown-Menüs für die Farbe. Größe; etc .. –

0

Dies ist, was ich getan habe, um dieses Problem zu lösen. Es nimmt im Grunde genommen den variant_id Parameter, der durch die Radioknöpfe kontrolliert wurde und verwandelt es in ein verstecktes Feld, das durch jQuery und AJAX mit zusätzlichen Mitteilungen gesteuert wird.

Ich hoffe, das hilft jemandem.

config/routes.rb

# Mount the core routes 
Rails.application.routes.draw do 
    mount Spree::Core::Engine, at: '/' 
end 

# Create new routes 
Spree::Core::Engine.routes.draw do 
    post "products/:product_id/get_variant", 
     to: "products#toggle_like", 
     as: "get_variant", 
     constraints: { :format => /(js)/ } 
end 

app/Modelle/spree/product_decorator.rb

Spree::Product.class_eval do 

    # Find the Product's Variant from an array of OptionValue ids 
    def find_variant_by_options(array) 
    option_values = Spree::OptionValue.where(id: array) 
    variants = [] 
    option_values.each do |option_value| 
     variants.push(option_value.variants.ids) 
    end 
    self.variants.find_by(:id => variants.inject(:&).first) 
    end 
end 

app/Controller/Spree/products_controller_decorator.rb

Spree::ProductsController.class_eval do 

    # Get the Variant from params[:ids], respond with JavaScript 
    def get_variant 
    @product = Spree::Product.find_by :slug => params[:product_id] 
    @variant = @product.find_variant_by_options(params[:ids].split(',')) 

    respond_to do |format| 
     format.js 
    end 
    end 
end 

app/views/Spree/products/get_variant.js.erb

// Update hidden field #varient_id's value. 
$("#variant_id").val("<%= @variant.id %>") 
// Update price 
$(".price.selling").html("<%= number_to_currency @variant.price %>"); 
<% if @variant.in_stock? && @variant.available? %> 
// If in stock and available 
    $("#add-to-cart-button").prop("disabled", false); // Enable button 
    $(".out-of-stock").hide(); // Hide 'out of stock' message 
<% else %> 
// Otherwise 
    $("#add-to-cart-button").prop("disabled", true); // Disable button 
    $(".out-of-stock").show(); // Show 'out of stock' message 
<% end %> 

app/views/Spree/products/_cart_form.html.erb

<%= form_for order, url: populates_orders_path do |f| %> 
    ... 
    <% if @product.variants_and_option_values(current_currency).any? %> 
    <div id="product_variants" class="col-md-6"> 
     <h3 class="product-section-title"><%= Spree.t(:variants) %></h3> 
     <% @product.option_types.each do |option_type| %> 
     <%= f.label "option_type_#{option_type.id}", option_type.name %> 
     <br> 
     <%= f.select "option_type_value_#{option_type.id}", 
        option_type.option_values.all.collect { |v| [ v.name, v.id ] }, 
        { include_blank: true }, 
        { class: "form-control" } %> 
     <br> 
     <% end %> 
     <%= hidden_field_tag "variant_id", value: "0" %> 
     ... 
    </div> 
    <% else %> 
    <%= hidden_field_tag "variant_id", @product.master.id %> 
    <% end %> 
    ... 
    <span class="price selling" 
      itemprop="price" 
      content="<%= @product.price_in(current_currency).amount.to_d %>"> 
     <%= display_price(@product) %> 
    </span> 
    ... 
    <%= button_tag class: "btn btn-success", 
         id: "add-to-cart-button", 
       disabled: @product.variants.any?, 
        type: :submit do %> 
     <%= Spree.t(:add_to_cart) %> 
    <% end %> 
    ... 
    <span class="out-of-stock" style="display: none;"> 
    <%= Spree.(:out_of_stock) %> 
    </span> 
<% end %> 

<script> 
    // Call AJAX if all options are selected, otherwise clean up. 
    $("#product-variants select").change(function(){ 
    var option_value_ids = []; 
    $("#product-variants select").each(function(){ 
     option_value_ids.push($(this).val()); 
    }); 
    if(option_value_ids.indexOf("") == -1){ 
     $.ajax({ 
     url: "<%= get_variant_path(@product) %>?ids=" + option_value_ids.join(','), 
     method: "post" 
     }); 
    }else{ 
     $("#variant_id").val("0"); 
     $("#add-to-cart-button").prop("disabled", true); 
     $(".out-of-stock").hide(); 
    } 
    }); 
</script>