Custom Product Attribute list as number boxes

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.
7 năm cách đây
I am trying to make a custom attribute list with number boxes for each attributes.

I made a custom partial view based off of ProductAttributes.cshtml called CustomProductAttributes.cshtml and put that partial view in a custom product view in which I point to in our product set up.

My partial view renders as expected on the product when I use that custom Product View (see image):



What I want to happen is when a customer ups the number per attribute line, I want the attribute price to multiply by the value of the numberbox.  So if someone enters '2' in the attribute numberbox and the attribute's price is $4 USD, then the base price of the product would increase by $8 USD.  Does that make sense?

I am including my base basic CustomProductAttribute.cshtml code, but I need help in determining on how to get the multiplied price of the attribute numberbox x the price of the attribute.

[code]

@model IList<ProductDetailsModel.ProductAttributeModel>
@using Nop.Web.Models.Catalog;
@using Nop.Core.Domain.Catalog;
@using Nop.Core.Domain.Media;
@using Nop.Core.Infrastructure;
@using System.Text;
@using System.Globalization;
@if (Model.Count > 0)
{
    <div class="attributes">
        <dl>
            @foreach (var attribute in Model)
            {
                string controlId = string.Format("product_attribute_{0}", attribute.Id);
                string textPrompt = !string.IsNullOrEmpty(attribute.TextPrompt) ? attribute.TextPrompt : attribute.Name;
                <dt id="@string.Format("product_attribute_label_{0}", attribute.Id)">
                    <label class="text-prompt">
                        @textPrompt
                    </label>
                    @if (attribute.IsRequired)
                    {
                        <span class="required">*</span>
                    }
                    @if (!string.IsNullOrEmpty(attribute.Description))
                    {
                        <div class="attribute-description">
                            @Html.Raw(attribute.Description)
                        </div>
                    }
                </dt>
                <dd id="@string.Format("product_attribute_input_{0}", attribute.Id)">
                    @switch (attribute.AttributeControlType)
                    {
@*/////////////////////////////   NEED HELP HERE!!!!
-- CUSTOM ATTRIBUTE NUMBERBOX - NEED TO WIRE ATTRIBUTE VALUES TO THE ADD TO CART BUTTON--
////////////////////////////////////////////////////////////*@
                        case AttributeControlType.MuseumAttributeList:
                            {

                                    <ul class="museumAttributeList">
                                        @foreach (var attributeValue in attribute.Values)
                                        {
                                            var attributeName = String.IsNullOrEmpty(attributeValue.PriceAdjustment) ?
                                                attributeValue.Name :
                                                T("Products.ProductAttributes.PriceAdjustment", attributeValue.Name, attributeValue.PriceAdjustment).Text;
                                            <li>
                                                <div>@attributeName</div>
                                                <input type="number" data-val="true" data-val-number="Field Qty must be a number." value="@attributeValue.Id" id="@(controlId)_@(attributeValue.Id)" class="qty-input" placeholder="0" name="@(controlId)" />
                                            </li>
                                        }
                                    </ul>
                                
                            }
                            break;
@*
////////////////
END CUSTOM NUMBERBOX
////////////////////////////
*@

                        case AttributeControlType.DropdownList:
                            {
                        <select name="@(controlId)" id="@(controlId)">
                            @if (!attribute.IsRequired)
                            {
                                <option value="0">---</option>
                            }
                            @foreach (var attributeValue in attribute.Values)
                            {
                                var attributeName = String.IsNullOrEmpty(attributeValue.PriceAdjustment) ?
                                    attributeValue.Name :
                                    T("Products.ProductAttributes.PriceAdjustment", attributeValue.Name, attributeValue.PriceAdjustment).Text;
                                <option selected="@attributeValue.IsPreSelected" value="@attributeValue.Id">@attributeName</option>
                            }
                        </select>
                            }
                            break;
                        case AttributeControlType.RadioList:
                            {
                        <ul class="option-list">
                            @foreach (var attributeValue in attribute.Values)
                            {
                                var attributeName = String.IsNullOrEmpty(attributeValue.PriceAdjustment) ?
                                    attributeValue.Name :
                                    T("Products.ProductAttributes.PriceAdjustment", attributeValue.Name, attributeValue.PriceAdjustment).Text;
                                <li>
                                    <input id="@(controlId)_@(attributeValue.Id)" type="radio" name="@(controlId)" value="@attributeValue.Id" checked="@attributeValue.IsPreSelected" />
                                    <label for="@(controlId)_@(attributeValue.Id)">@attributeName</label>
                                </li>
                            }
                        </ul>
                            }
                            break;
                        case AttributeControlType.Checkboxes:
                        case AttributeControlType.ReadonlyCheckboxes:
                            {
                        <ul class="option-list">
                            @foreach (var attributeValue in attribute.Values)
                            {
                                var attributeName = String.IsNullOrEmpty(attributeValue.PriceAdjustment) ?
                                    attributeValue.Name :
                                    T("Products.ProductAttributes.PriceAdjustment", attributeValue.Name, attributeValue.PriceAdjustment).Text;                            
                                <li>
                                    <input id="@(controlId)_@(attributeValue.Id)" type="checkbox" name="@(controlId)" value="@attributeValue.Id" checked="@attributeValue.IsPreSelected" @(attribute.AttributeControlType == AttributeControlType.ReadonlyCheckboxes ? Html.Raw(" disabled=\"disabled\"") : null) />
                                    <label for="@(controlId)_@(attributeValue.Id)">@attributeName</label>
                                </li>
                            }
                        </ul>
                            }
                            break;
                        case AttributeControlType.TextBox:
                            {
                        <input name="@(controlId)" type="text" class="textbox" id="@(controlId)" value="@attribute.DefaultValue" />
                            }
                            break;
                        case AttributeControlType.MultilineTextbox:
                            {
                        <textarea cols="20" id="@(controlId)" name="@(controlId)">@attribute.DefaultValue</textarea>
                            }
                            break;
                        case AttributeControlType.Datepicker:
                            {
                        @Html.DatePickerDropDowns(controlId + "_day", controlId + "_month", controlId + "_year", DateTime.Now.Year, DateTime.Now.Year + 1, attribute.SelectedDay, attribute.SelectedMonth, attribute.SelectedYear)
                            }
                            break;
                        case AttributeControlType.FileUpload:
                            {
                                var downloadService = EngineContext.Current.Resolve<Nop.Services.Media.IDownloadService>();
                                Download download = null;
                                if (!String.IsNullOrEmpty(attribute.DefaultValue))
                                {
                                    download = downloadService.GetDownloadByGuid(new Guid(attribute.DefaultValue));
                                }

                                //register CSS and JS
                                Html.AddCssFileParts("~/Scripts/fineuploader/fineuploader-4.2.2.min.css");
                                Html.AddScriptParts("~/Scripts/fineuploader/jquery.fineuploader-4.2.2.min.js");

                                //ex. ['jpg', 'jpeg', 'png', 'gif'] or []
                                var allowedFileExtensions = string.Join(", ", attribute.AllowedFileExtensions.Select(x => "'" + x.Trim() + "'").ToList());

                                if (download != null)
                                {
                                    <input id="@(controlId)" name="@(controlId)" type="hidden" value="@download.DownloadGuid" />
                                }
                                else
                                {
                                    <input id="@(controlId)" name="@(controlId)" type="hidden" />
                                }

                        @*fine uploader container*@
                        <div id="@(controlId)uploader"></div>
                        @*fine uploader template (keep it synchronized to \Content\fineuploader\templates\default.html)*@
                        <script type="text/template" id="@(controlId)-qq-template">
                            <div class="qq-uploader-selector qq-uploader">
                                <div class="qq-upload-drop-area-selector qq-upload-drop-area" qq-hide-dropzone>
                                    <span>@T("Common.FileUploader.DropFiles")</span>
                                </div>
                                <div class="qq-upload-button-selector qq-upload-button">
                                    <div>@T("Common.FileUploader.Upload")</div>
                                </div>
                                <span class="qq-drop-processing-selector qq-drop-processing">
                                    <span>@T("Common.FileUploader.Processing")</span>
                                    <span class="qq-drop-processing-spinner-selector qq-drop-processing-spinner"></span>
                                </span>
                                <ul class="qq-upload-list-selector qq-upload-list">
                                    <li>
                                        <div class="qq-progress-bar-container-selector">
                                            <div class="qq-progress-bar-selector qq-progress-bar"></div>
                                        </div>
                                        <span class="qq-upload-spinner-selector qq-upload-spinner"></span>
                                        <span class="qq-edit-filename-icon-selector qq-edit-filename-icon"></span>
                                        <span class="qq-upload-file-selector qq-upload-file"></span>
                                        <input class="qq-edit-filename-selector qq-edit-filename" tabindex="0" type="text">
                                        <span class="qq-upload-size-selector qq-upload-size"></span>
                                        <a class="qq-upload-cancel-selector qq-upload-cancel" href="#">@T("Common.FileUploader.Cancel")</a>
                                        <a class="qq-upload-retry-selector qq-upload-retry" href="#">@T("Common.FileUploader.Retry")</a>
                                        <a class="qq-upload-delete-selector qq-upload-delete" href="#">@T("Common.FileUploader.Delete")</a>
                                        <span class="qq-upload-status-text-selector qq-upload-status-text"></span>
                                    </li>
                                </ul>
                            </div>
                        </script>
                        <script type="text/javascript">
                            $(document).ready(function() {
                                $("#@(controlId)uploader").fineUploader({
                                    request: {
                                        endpoint: '@(Url.RouteUrl("UploadFileProductAttribute", new { attributeId = attribute.Id }))'
                                    },
                                    template: "@(controlId)-qq-template",
                                    multiple: false,
                                    validation: {
                                        allowedExtensions: [@Html.Raw(allowedFileExtensions)]
                                    }
                                }).on("complete", function(event, id, name, responseJSON, xhr) {
                                    $("#@(controlId)").val(responseJSON.downloadGuid);
                                    if (responseJSON.success) {
                                        $("#@(controlId + "downloadurl")").html("<a href='" + responseJSON.downloadUrl + "'>@T("Common.FileUploader.DownloadUploadedFile")</a>");
                                        $("#@(controlId + "remove")").show();
                                    }
                                    if (responseJSON.message) {
                                        alert(responseJSON.message);
                                    }
                                });

                                $("#@(controlId + "remove")").click(function(e) {
                                    $("#@(controlId + "downloadurl")").html("");
                                    $("#@(controlId)").val('');
                                    $(this).hide();
                                });
                            });
                        </script>
                                <div id="@(controlId + "downloadurl")">
                                    @if (download != null)
                                    {
                                        <a href="@(Url.Action("GetFileUpload", "Download", new {downloadId = download.DownloadGuid}))" class="download-uploaded-file">@T("Common.FileUploader.DownloadUploadedFile")</a>
                                    }
                                </div>
                                <div>
                                    @if (download != null)
                                    {
                                        <a id="@(controlId + "remove")" class="remove-download-button">@T("Common.FileUploader.RemoveDownload")</a>
                                    }
                                    else
                                    {
                                        <a id="@(controlId + "remove")" class="remove-download-buttonn" style="display: none;">@T("Common.FileUploader.RemoveDownload")</a>
                                    }
                                </div>
                    
                            }
                            break;
                        case AttributeControlType.ColorSquares:
                            {
                        <ul class="option-list color-squares" id="color-squares-@(attribute.Id)">
                            @foreach (var attributeValue in attribute.Values)
                            {
                                var attributeName = String.IsNullOrEmpty(attributeValue.PriceAdjustment) ?
                                    attributeValue.Name :
                                    T("Products.ProductAttributes.PriceAdjustment", attributeValue.Name, attributeValue.PriceAdjustment).Text;  
                                <li @(attributeValue.IsPreSelected ? @Html.Raw(" class=\"selected-value\"") : null)>
                                    <label for="@(controlId)_@(attributeValue.Id)">
                                        <span class="color-container" title="@attributeName">
                                            <span class="color" style="background-color:@(attributeValue.ColorSquaresRgb);">&nbsp;</span>
                                        </span>
                                        <input id="@(controlId)_@(attributeValue.Id)" type="radio" name="@(controlId)" value="@attributeValue.Id" checked="@attributeValue.IsPreSelected" />
                                        @*uncomment below to display attribute value name*@
                                        @*<span class="name">@attributeName</span>*@
                                    </label>
                                </li>
                            }
                        </ul>
                        <script type="text/javascript">
                            $(document).ready(function() {
                                $('.attributes #color-squares-@(attribute.Id)').delegate('input', 'click', function(event) {
                                    $('.attributes #color-squares-@(attribute.Id)').find('li').removeClass('selected-value');
                                    $(this).closest('li').addClass('selected-value');
                                });
                            });
                        </script>
                            }
                            break;
                    }
                </dd>
            }
        </dl>
    </div>
}
@if (Model.Count > 0)
{
    //dynamic update support
    var attributesHaveConditions = Model.Any(x => x.HasCondition);
    var dynamicPriceUpdate = EngineContext.Current.Resolve<CatalogSettings>().AjaxProcessAttributeChange;
    var attributeChangeScriptsBuilder = new StringBuilder();
    var productId = Model.First().ProductId;
    var attributeChangeHandlerFuncName = string.Format("attribute_change_handler_{0}", productId);
    if (dynamicPriceUpdate)
    {
        //generate change event script
        foreach (var attribute in Model)
        {
            string controlId = string.Format("product_attribute_{0}", attribute.Id);
            switch (attribute.AttributeControlType)
            {
                case AttributeControlType.DropdownList:
                    {
                        attributeChangeScriptsBuilder.AppendFormat("$('#{0}').change(function(){{{1}();}});\n", controlId, attributeChangeHandlerFuncName);
                    }
                    break;
                case AttributeControlType.RadioList:
                case AttributeControlType.ColorSquares:
                    {
                        foreach (var attributeValue in attribute.Values)
                        {
                            attributeChangeScriptsBuilder.AppendFormat("$('#{0}_{1}').click(function(){{{2}();}});\n", controlId, attributeValue.Id, attributeChangeHandlerFuncName);
                        }
                    }
                    break;
                case AttributeControlType.Checkboxes:
                case AttributeControlType.ReadonlyCheckboxes:
                    {
                        foreach (var attributeValue in attribute.Values)
                        {
                            attributeChangeScriptsBuilder.AppendFormat("$('#{0}_{1}').click(function(){{{2}();}});\n", controlId, attributeValue.Id, attributeChangeHandlerFuncName);
                        }
                    }
                    break;
                    //TO HANDLE CUSTOM MUSEUM ATTRIBUTE LIST
                case AttributeControlType.MuseumAttributeList:
                    foreach (var attributeValue in attribute.Values)
                        {
                            attributeChangeScriptsBuilder.AppendFormat("$('#{0}_{1}').change(function(){{{2}();}});\n", controlId, attributeValue.Id, attributeChangeHandlerFuncName);

                        }
                    break;
                default:
                    break;
            }
        }
        //render scripts
        //almost the same implementation is used in the \Views\Product\_RentalInfo.cshtml file
        <script type="text/javascript">
            function @(attributeChangeHandlerFuncName)() {
                $.ajax({
                    cache: false,
                    url: '@Html.Raw(Url.Action("ProductDetails_AttributeChange", "ShoppingCart", new {productId = productId, validateAttributeConditions = attributesHaveConditions}))',
                    data: $('#product-details-form').serialize(),
                    type: 'post',
                    success: function(data) {
                        if (data.price) {
                            $('.price-value-@productId').text(data.price);
                        }
                        if (data.sku) {
                            $('#sku-@productId').text(data.sku);
                        }
                        if (data.mpn) {
                            $('#mpn-@productId').text(data.mpn);
                        }
                        if (data.gtin) {
                            $('#gtin-@productId').text(data.gtin);
                        }
                        if (data.stockAvailability) {
                            $('#stock-availability-value-@productId').text(data.stockAvailability);
                        }
                        if (data.enabledattributemappingids) {
                            for (var i = 0; i < data.enabledattributemappingids.length; i++) {
                                $('#product_attribute_label_' + data.enabledattributemappingids[i]).show();
                                $('#product_attribute_input_' + data.enabledattributemappingids[i]).show();
                            }
                        }
                        if (data.enabledattributemappingids) {
                            for (var i = 0; i < data.disabledattributemappingids.length; i++) {
                                $('#product_attribute_label_' + data.disabledattributemappingids[i]).hide();
                                $('#product_attribute_input_' + data.disabledattributemappingids[i]).hide();
                            }
                        }
                    }
                });
            }
            $(document).ready(function() {
                @(attributeChangeHandlerFuncName)();
                @Html.Raw(attributeChangeScriptsBuilder.ToString())
            });
        </script>
    }
}
4 năm cách đây
Hello

Regarding your descried requirement, our development team has created a plugin which might interest you, with this plugin you can use text boxes for product’s attributes, when the customer enters their desired values, the product’s price would be dynamically calculated using a formula which the store owner can define for each product.

For example, if the product has “Width” and “Length” attributes and the price should be calculated by “Product’s Price = Width * Length”, the store owner define this formula in the specified section in the product’s edit details page. After that, the product’s price would e calculated when the customer enters the width and length values.
For more information please visit:
Calculating Price from Attributes Plugin

With best regards
HyperNop
This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.