Spree Dropdown for Optional Option Values

I am learning Spree 3.0, and I have a test store that sells shorts.

Shorts have several types of options: size, color, length

I wanted to change the way options are displayed on the interface from the radio in the drop-down list.

Spree currently displays option types as radio buttons:

Current speed setting

I want to change this to use drop-down menus for each type of parameter, for example:

I want Spree to do

I tried the following:

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

But it just displays the values ​​of all types of options in each tag:

Drop-down menu with all types of options 1

Drop-down menu with all types of options 2

I wanted to know the best way to split parameter values ​​into separate dropdown menus?

Any help is greatly appreciated, thanks.

+6
source share
4 answers

It's not as easy as it sounds, since you will use Spree::OptionValue instead of options, and at some point you will need to go back to the options to add them to your cart. Combinations may not be possible and / or out of stock, so working with option_values ​​is extremely impractical.

But, nevertheless, you wanted to know how I configured the following:

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

This will give you a hash with hash keys, which are option_types (Size, Color, Length parameters in your case), and the values ​​are arrays of option_values ​​parameters.

You can easily configure this in a radio station as follows:

 <% @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 %> 

Or for drop down menus:

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

And in your controller you want to find an option that meets these three criteria, check if it in_stock , backorderable or track_inventory? false and respond with errors or an updated cart :)

I hope this helps

+5
source

This is what I did to solve this problem. It basically takes a variant_id parameter, which is controlled by radio buttons and turns it into a hidden field controlled by jQuery and AJAX with additional notifications.

Hope this helps someone.

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 

application / models / Spree / product_decorator.rb

 Spree::Product.class_eval do # Find the Product 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 

application / controllers / 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 

application / views / Spree / Products / get_variant.js.erb

 // Update hidden field #varient_id 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 %> 

application / 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> 
+1
source

how do you update / update product images (for example, the Ruby on Rails baseball jersey example), I selected these two options and want to show the blue

Here is what I did with the js.erb file (I found a solution there):

 // Update hidden field #varient_id value. $('#variant_id').val('<%= @variant.id %>') // Render product/_image partial $('#main-image').html("<% j (render partial: 'image', locals: {product: @variant}) %>"); // Update price $('.price.selling').html('<%= number_to_currency @variant.price %>'); <% if @variant.in_stock? && @variant.available_on %> // 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 %> 

but it didn’t work, please help

0
source

The solution that worked for me was to use Solidus Variant Variants

https://github.com/gildardoperez/solidus_variant_options

0
source

Source: https://habr.com/ru/post/1241009/


All Articles