Product Attribute Based Product Image

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.
10 years ago
Change the Image Based on Color Option Like black red ..Selected in Product Attribute Dropdown
we have done it in Our Nopcommerce 2.70 Site
These are the Steps required to complete this task

(1)Add the following fields  in  Nop=>Core=>Domain=>Catalog=>ProductPicture


using Nop.Core.Domain.Media;

namespace Nop.Core.Domain.Catalog
{
  
    public partial class ProductPicture : BaseEntity
    {

       /*----------Existing code----------*/
      
        /// <summary>
        /// Gets or sets the product variant attribute mapping identifier
        /// </summary>
        public virtual int ProductVariantAttributeId { get; set; }
      
        /// <summary>
        /// Gets the product variant attribute
        /// </summary>
        public virtual ProductVariantAttribute ProductVariantAttribute { get; set; }
    }

}



(2)Add the following fields  Nop=>Admin=>Models=>Catalog=>ProductModel


public partial class ProductPictureModel : BaseNopEntityModel
{
            public ProductPictureModel()
            {
                AvailableProductAttributes = new List<SelectListItem>();
              
            }            
           /*----------Existing Code----------*/
            public int ProductVariantAttributeId { get; set; }          
            [NopResourceDisplayName("Admin.Catalog.Products.Pictures.Fields.ProductAttribute")]
            [UIHint("ProductVariantAttribute")]
            public string ProductVariantAttribute { get; set; }

            public IList<SelectListItem> AvailableProductAttributes { get; set; }

}

(3)In Nop=>Admin=>Views=>Product=>Editor Templates Add New Editor Template


@using Telerik.Web.Mvc.UI;
@using Nop.Core.Domain.Catalog;
@using Nop.Services.Catalog;
@{    

    var _productAttributeService = EngineContext.Current.Resolve<IProductAttributeService>();
    var allProductAttributes = _productAttributeService.GetAllProductAttributes();
    var productAttributesList = new List<SelectListItem>();
    foreach (var pa in allProductAttributes)
    {
        var item = new SelectListItem()
        {
            Text = pa.Name,
            Value = pa.Id.ToString()
        };
        productAttributesList.Add(item);
    }    
}

@Html.Telerik().DropDownList().Name("ProductAttribute").BindTo(productAttributesList)

(4)Nop=>Admin=>Views=>Product=>_CreateOrUpdate.cshtml  find the @helper TabPictures() then change it with following code


@helper TabPictures()
{
    if (Model.Id > 0)
    {
    <div>
        @(Html.Telerik().Grid<ProductModel.ProductPictureModel>()
                    .Name("productpictures-grid")
                    .DataKeys(x =>
                    {
                        x.Add(y => y.Id).RouteKey("Id");
                    })
                    .Columns(columns =>
                    {
                        /*----------Existing Code----------*/
                        columns.Bound(x=> x.ProductVariantAttribute).Width(75).Centered();                      
                        columns.Command(commands =>
                        {
                            /*----------Existing Code----------*/

                        });

                    })
                    .Editable(x =>
                    {
                        x.Mode(GridEditMode.InLine);
                    })
                    .DataBinding(dataBinding =>
                    {
                        /*----------Existing Code----------*/

                    })
                    .ClientEvents(events=> events.OnEdit("onPictureListEdit"))
                    .ClientEvents(events=> events.OnSave("onPictureListSave"))
                    .EnableCustomBinding(true))
    </div>
    <p>
        <strong>@T("Admin.Catalog.Products.Pictures.AddNew")</strong>
    </p>
    <script type="text/javascript">
    
        $(document).ready(function () {
            $('#addProductPicture').click(function () {
              /*----------Existing Code----------*/
                var attributeId = $('#ProductAttributes').val();
                if(attributeId == null)
                    attributeId = 0;
                /*----------Existing Code----------*/
                $.ajax({
                    cache:false,
                    type: "POST",
                    url: "@(Url.Action("ProductPictureAdd", "Product"))",
                    data: { "pictureId": pictureId, "displayOrder": displayOrder,"attributeId":attributeId,"productId": @Model.Id },
                    success: function (data) {
                         /*----------Existing Code----------*/
                    },
                    error:function (xhr, ajaxOptions, thrownError){
                        /*----------Existing Code----------*/
                    }  
                });
            });
        });


        function onPictureListEdit(e) {

            var value = $("#@Html.FieldIdFor(model => model.Id)").val();

            if (value != 0) {
                $.getJSON("/Admin/Product/GetProductVariantAttributes?productId=" + value, function (data) {
                    $("#ProductAttribute").data("tDropDownList").dataBind(data);    
                  
                    $("#ProductAttribute").data("tDropDownList").reload();
                });                
            }

        }

        function onPictureListSave(e)
        {
            var values = e.values;
            values.ProductVariantAttribute = $("#ProductAttribute").data('tDropDownList').value();
        }

    </script>        
    <table class="adminContent">
        <tr>
            /*----------Existing Code----------*/
        </tr>

        @if(Model.AddPictureModel.AvailableProductAttributes.Count() > 0)
             {
         <tr>
            

            <td class="adminTitle">
                @Html.NopLabelFor(model => model.AddPictureModel.ProductVariantAttribute):
            </td>
            <td class="adminData">
                @Html.DropDownList("ProductAttributes",Model.AddPictureModel.AvailableProductAttributes)
              
            </td>
        </tr>
        }

        <tr>
          
            /*----------Existing Code----------*/
        </tr>

        <tr>
           /*----------Existing Code----------*/
        </tr>

    </table>
    }
    else
    {
     /*----------Existing Code----------*/
    }
}


(5)Then In Nop=>Admin=>Controllers=> ProductController.cs update the following


public ActionResult ProductPictureAdd(int pictureId, int displayOrder,int attributeId, int productId)
{
    /*----------Existing Code----------*/
    _productService.InsertProductPicture(new ProductPicture()
    {
               /*----------Existing Code----------*/
                ProductVariantAttributeId = attributeId,
    });

     /*----------Existing Code----------*/
            return Json(new { Result = true }, JsonRequestBehavior.AllowGet);
     }

[HttpPost, GridAction(EnableCustomBinding = true)]
public ActionResult ProductPictureList(GridCommand command, int productId)
{
             /*----------Existing Code----------*/
            var productPicturesModel = productPictures
                .Select(x =>
                {
                    return new ProductModel.ProductPictureModel()
                    {
                        /*----------Existing Code----------*/
                        ProductVariantAttributeId = x.ProductVariantAttributeId,
                        ProductVariantAttribute = _productAttributeService.GetProductVariantAttributeValueById(x.ProductVariantAttributeId) != null ?_productAttributeService.GetProductVariantAttributeValueById(x.ProductVariantAttributeId).Name :"none"
                    };
                })
                .ToList();

            var model = new GridModel<ProductModel.ProductPictureModel>
            {
               /*----------Existing Code----------*/
            };

            return new JsonResult
            {
                 /*----------Existing Code----------*/
            };
  }

[GridAction(EnableCustomBinding = true)]
public ActionResult ProductPictureUpdate(ProductModel.ProductPictureModel model, GridCommand command)
{
            /*----------Existing Code----------*/
            productPicture.ProductVariantAttributeId = Int32.Parse(model.ProductVariantAttribute) != 0 ? Int32.Parse(model.ProductVariantAttribute) : 0;
           /*----------Existing Code----------*/
        }


then add this One For Admin  ProductList Grid Product Attribute Dropdown

   #region Product Attribute Dropdown

        public JsonResult GetProductVariantAttributes(int productId)
        {
            var attributeList = new List<SelectListItem>();

             var productvariant  = _productService.GetProductVariantsByProductId(productId).FirstOrDefault();
             var productvariantattribute = productvariant.ProductVariantAttributes.FirstOrDefault();

             if (productvariantattribute != null)
             {
                 int productvariantattributeId = productvariant.ProductVariantAttributes
                                                 .Where(p => (p.TextPrompt == "Color") || (p.ProductAttribute.Name == "Color") || (p.TextPrompt == "color") || (p.ProductAttribute.Name == "color"))
                                                 .FirstOrDefault().Id;                                                
                 var allAttributes = _productAttributeService.GetProductVariantAttributeValues(productvariantattributeId);
                 attributeList.Add(new SelectListItem()
                {
                    Text = "--Select--",
                    Value = "0",
                    Selected = true
                });
                 foreach (var cr in allAttributes)
                 {
                     var item = new SelectListItem()
                    {
                        Text = cr.Name,
                        Value = cr.Id.ToString(),
                      
                    };
                     attributeList.Add(item);
                 }
                 if (attributeList != null)
                 {
                     return Json(attributeList, JsonRequestBehavior.AllowGet);
                 }
                 else
                 {
                     attributeList.Add(new SelectListItem()
                     {
                         Text = "--Select--",
                         Value = "0"
                     });
                     return Json(attributeList, JsonRequestBehavior.AllowGet);
                 }
             }
             else
             {
                 attributeList.Add(new SelectListItem()
                 {
                     Text = "--Select--",
                     Value = "0"
                 });
                 return Json(attributeList, JsonRequestBehavior.AllowGet);
             }

        }


        #endregion




(6)In Nop=>Web=>Views=>Catalog=>_ProductAttributes.cshtml


@model IList<ProductDetailsModel.ProductVariantModel.ProductVariantAttributeModel>
/*----------Existing code----------*/  
@{
    
      /*----------Existing code----------*/    

    //Productvariant  
    string attributeTableName = "";
    string attributeFuncName = "";  

    if (dynamicPriceUpdate && !hidePrices)
    {
         /*----------Existing code----------*/
    }

    //Added For Image Change Based On Product  Color Attribute  Dropdown ...  
    foreach (var attribute in Model)
    {
        string controlId = string.Format("product_attribute_{0}_{1}_{2}", attribute.ProductVariantId, attribute.ProductAttributeId, attribute.Id);

        attributeTableName = string.Format("attributeTable_{0}", attribute.ProductVariantId);
        attributeFuncName = string.Format("attributeFuncName_{0}", attribute.ProductVariantId);      
         if( attribute.TextPrompt =="Color" || attribute.TextPrompt =="color" || attribute.Name == "Color" || attribute.Name == "color")
        {
        
        switch (attribute.AttributeControlType)
        {
            case AttributeControlType.DropdownList:
                {
                    attributeTableScripts.AppendFormat("{0}['{1}'] = new Array(", attributeTableName, controlId);
                    attributeScripts.AppendFormat("$('#{0}').change(function(){{{1}();}});\n", controlId,attributeFuncName);

                    int numberOfJsArrayItems = 0;
                    if (!attribute.IsRequired)
                    {
                        attributeTableScripts.AppendFormat(CultureInfo.InvariantCulture, "{0},", decimal.Zero);
                        numberOfJsArrayItems++;
                    }

                    foreach (var pvaValue in attribute.Values)
                    {
                        //attributeTableScripts.AppendFormat(CultureInfo.InvariantCulture, "{0}['{1}_{2}'] = '{3}';\n", attributeTableName, controlId, pvaValue.Id, (string)pvaValue.PictureThumbnailUrl);                    
                        attributeTableScripts.AppendFormat(CultureInfo.InvariantCulture, "'{0}',",pvaValue.PictureThumbnailUrl, pvaValue.Id);
                        //attributeScripts.AppendFormat("$('#{0}').change(function(){{{1}['{2}_{3}']}});\n", controlId, attributeFuncName,controlId,pvaValue.Id);
                        //attributeScripts.AppendFormat("$('#{0}').change(function(){{{1}();}});\n", controlId,attributeFuncName,pvaValue.Id);
                        numberOfJsArrayItems++;
                    }

                    //If you create an array with a single numeric parameter, that number is used for specifying the number of elements in this array.
                    //so have a little hack here (we need at least two elements)
                    if (numberOfJsArrayItems == 1)
                    {
                        attributeTableScripts.AppendFormat(CultureInfo.InvariantCulture, "{0},", decimal.Zero);
                    }
                   attributeTableScripts.Length -= 1;
                   attributeTableScripts.Append(");\n");
                }
                break;
            case AttributeControlType.RadioList:
                {
                    foreach (var pvaValue in attribute.Values)
                    {
                        attributeTableScripts.AppendFormat(CultureInfo.InvariantCulture, "{0}['{1}_{2}'] = '{3}';\n", attributeTableName, controlId, pvaValue.Id, (string)pvaValue.PictureThumbnailUrl);                      
                        attributeScripts.AppendFormat("$('#{0}_{1}').click(function(){{{2}();}});\n", controlId, pvaValue.Id, attributeFuncName);
                    }
                }
                break;
            case AttributeControlType.Checkboxes:
                {
                    foreach (var pvaValue in attribute.Values)
                    {
                        attributeTableScripts.AppendFormat(CultureInfo.InvariantCulture, "{0}['{1}_{2}'] = '{3}';\n", attributeTableName, controlId, pvaValue.Id, (string)pvaValue.PictureThumbnailUrl);
                        attributeScripts.AppendFormat("$('#{0}_{1}').click(function(){{{2}();}});\n", controlId, pvaValue.Id, attributeFuncName);
                    }
                }
                break;
            default:
                break;
        }

    }
    }
}
@if (Model.Count > 0)
{
    if (dynamicPriceUpdate && !hidePrices)
    {
               /*----------Existing code----------*/
    }
    
/*Newly Added */  
<script type="text/javascript">

    var mainImagePath = '';
    // Adjustment table
    var @(attributeTableName) = new Array();
    // Adjustment table initialize
    @Html.Raw(attributeTableScripts.ToString())    

    // Adjustment function
    function @(attributeFuncName)() {          
        var sum = 0;
        var imageString = '';
        for(var i in @(attributeTableName)) {
            var ctrl = $('#' + i);
            if((ctrl.is(':radio') && ctrl.is(':checked')) || (ctrl.is(':checkbox') && ctrl.is(':checked'))) {
                sum += @(attributeTableName)[i];
                    imageString = imageString + @(attributeTableName)[i];                    
                }
                else if(ctrl.is('select')) {              
                  
                    var idx = $('#' + i + " option").index($('#' + i + " option:selected"));                  
                    if(idx != -1) {
                        sum += @(attributeTableName)[i][idx];
                        imageString = imageString + @(attributeTableName)[i][idx];                        
                    }
                }
            mainImagePath = imageString.substring(0,imageString.length);  
        
            if(mainImagePath != null)
            $("#thumb").attr('href',mainImagePath);
            $("#thumb").trigger('click');    
            $("#mainImage").attr('src',mainImagePath);
          
        }
  
    }
    // Attributes handlers
    $(document).ready(function() {
       @* @(attributeFuncName)();*@
            @Html.Raw(attributeScripts.ToString())          
    });
    </script>    

    
    <div class="attributes">
          /*----------Existing code----------*/
    </div>
}



(7) Nop=>Web=>Views=>Catalog=>_ProductDetailPictures.cshtml

<div class="picture">
    @if (Model.DefaultPictureZoomEnabled)
    {
        <a href="@Model.DefaultPictureModel.FullSizeImageUrl" data-gallery="lightbox-pd" title="@Model.Name">
            <img alt="@Model.DefaultPictureModel.AlternateText" src="@Model.DefaultPictureModel.ImageUrl" title="@Model.DefaultPictureModel.Title" id="mainImage"/>
        </a>
    }
    else
    {
        <img alt="@Model.DefaultPictureModel.AlternateText" src="@Model.DefaultPictureModel.ImageUrl" title="@Model.DefaultPictureModel.Title" id="mainImage"/>
    }
    @if (Model.PictureModels.Count > 1)
    {
        <table class="picture-thumbs">
            @for (int i = 0; i < Model.PictureModels.Count; i++)
            {
                /*----------Existing code----------*/
                    
                <td class="a-left">
                    <a href="@picture.FullSizeImageUrl" data-gallery="lightbox-p" title="@Model.Name" id="thumb">
                        <img src="@picture.ImageUrl" alt="@picture.AlternateText" title="@picture.Title"/>
                    </a>
                </td>
                                    
                /*----------Existing code----------*/
            }
        </table>
    }
</div>
10 years ago
Good work Snow. It would be ideal if any product attribute could be associated with a product picture, I believe with little modification to your code it can be possible. Then, any product attribute changed in the ui could update the product picture
10 years ago
Thanks for your contribution. I've just also finished the official support for images per attribute values (it's not the same).

Please see the latest development version on Codeplex. It'll be available in the next version 3.10
10 years ago
Andrei,
what do you mean by  "images per attribute values"?

I have 3.10 and I don't see a way to add an image for each product variation. For example, If I have a shirt with 3 types of neck lines, I'd like the picture of the shirt to change when the user changes a different style of neck...

I can create a NECK LINE option with 3 values, but there's no way to associate a value to each of the options.

Please advise.

Thanks
10 years ago
If you have the product setup to use product attributes for the neck lines, make sure that you have uploaded an impage for eacj neckline. Then edit the product's attributes' values and you will see the photos that you have uploaded. You will be able to assign an image for each attribute (neck line).

Hope this helps!

-HB
10 years ago
To explain a bit further, when an attribute is selected, it's associated image will replace the main product image.
10 years ago
Hi,
Am using NopCommerce 3.01, i followed the steps above, but in Product Service class in [GetProductPicturesByProductId] function it gives an error that [ProductVariantAttributeId] invalid column. please am i missing something ?
Thanks.
This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.