PrevPrev Go to previous topic
NextNext Go to next topic
Last Post 11/15/2017 10:22 PM by  Adam Bernstein
Hide product options conditionally in ProductViewer
 4 Replies
 1 Subscribed to this topic
 1 Subscribed to this forum
Sort:
You are not authorized to post a reply.
Author Messages





New Member






--
11/1/2017 8:35 PM
    Hello, on the page ProductViewer I am trying to hide certain options under certain circumstances. We are using Hotcakes version 1.10.4 Pro.

    In _ProductDetails.cshtml, I added logic inside the loop [i]foreach (var opt in Model.LocalProduct.Options)[/i]:

    [code=csharp]foreach (var opt in Model.LocalProduct.Options)
    {
    if (HasStudentOptions(opt) && !ShowStudentPricing())
    {
    RemoveStudentOptions(opt);
    }
    <div class="dnnFormItem clearfix">
    @if (!opt.NameIsHidden)
    {@opt.Name}
    <div class="hc-option">
    @Html.Raw(opt.RenderWithSelection(Model.Selections.OptionSelectionList))
    </div>
    </div>
    }[/code]

    For RemoveStudentOptions, I tried two approaches:

    Approach #1 was to remove the unwanted OptionItems from the actual Items list of the product's option:

    [code=csharp]private void RemoveStudentOptions(Hotcakes.Commerce.Catalog.Option opt)
    {
    int i = 0;
    foreach(var optItem in opt.Items)
    {
    if (!optItem.Name.EndsWith("Student"))
    {
    //opt.Items.Remove(optItem);
    opt.Items.RemoveAt(i);
    }
    i += 1;
    }
    }[/code]

    However this caused the product viewer to not render at all, producing the error:
    [quote]InnerMessage:Error executing child request for handler 'System.Web.Mvc.HttpHandlerUtil+ServerExecuteHttpHandlerAsyncWrapper'.
    InnerStackTrace:
    at System.Web.HttpServerUtility.ExecuteInternal(IHttpHandler handler, TextWriter writer, Boolean preserveForm, Boolean setPreviousPage, VirtualPath path, VirtualPath filePath, String physPath, Exception error, String queryStringOverride)
    at System.Web.HttpServerUtility.Execute(IHttpHandler handler, TextWriter writer, Boolean preserveForm, Boolean setPreviousPage)
    at System.Web.HttpServerUtility.Execute(IHttpHandler handler, TextWriter writer, Boolean preserveForm)
    at System.Web.HttpServerUtilityWrapper.Execute(IHttpHandler handler, TextWriter writer, Boolean preserveForm)
    at System.Web.Mvc.Html.ChildActionExtensions.ActionHelper(HtmlHelper htmlHelper, String actionName, String controllerName, RouteValueDictionary routeValues, TextWriter textWriter)
    at System.Web.Mvc.Html.ChildActionExtensions.Action(HtmlHelper htmlHelper, String actionName, String controllerName, RouteValueDictionary routeValues)
    at Hotcakes.Commerce.Dnn.Mvc.MvcRenderingEngine.Render(String controllerName, String actionName, String viewName, Object routeValues)
    at Hotcakes.Modules.ProductViewer.ProductViewerView.RenderView()
    at Hotcakes.Commerce.Dnn.Web.HotcakesModuleBase.OnLoad(EventArgs e)[/quote]

    Approach #2 was to clone the Items list of the product's option, and render it rather than the original:

    [code=csharp]private Hotcakes.Commerce.Catalog.Option RemoveStudentOptions(Hotcakes.Commerce.Catalog.Option opt)
    {
    var newOpt = opt.Clone();
    newOpt.Items.Clear();
    foreach(var optItem in opt.Items)
    {
    if (!optItem.Name.EndsWith("Student"))
    {
    newOpt.Items.Add(optItem);
    }
    }
    return newOpt;
    }[/code]

    This renders the options as desired on the page, however it produces the error "Please make all selections before adding to cart" as shown in the image attached below.

    Is there a way to achieve the goal of conditionally hiding certain options?

    Thanks in advance,
    Adam

    [img=https://lh3.googleusercontent.com/ryVwfLcI5gzYT_5Q-vgZggIDQVB-XcXQDPt_1Ur1tBLMIxVFQbR27S_mGDXR00Qd5HyAS1E-hO7dEb6VuUKInLb5RTI7IdiTvamMRmjitHdVZMLjwZbh7xb7wxzBMh8F0CyFtabX278rgNaC9g5DZXArrmTnpGuPVU8BhZbdQ8U1HfkrThpG7jyH8OiL7C33ha2kESgZuCnhQ5YrW56yxqjFlhFAyZUyQAI4lqpo5j4ndynN-CE8JVv6TfOJEMaZkIx_wO5pxtCK16lLSRaxzFleHIvpJzD3OO95Tk3Xbu90G9mRe8Drx5IJOKgRmSRfD7pcmkNTHOvxHxChJAo2FJGT8YFZef9m1fcWsbpp4hM4SvK7pvIn7mQ69zXmt_M4H18OmH7jl_07xsUBZOLO6SpEQeIWAxwvwxQ5q7g48CGDJ7Xz2zeGB1SbZ7QUfjFtfvNzT5GOT7Apt_PemEaErypv9s-zWiWH45ynhYE3Zk6zFlGCFuXxe7xjdyriOfg4WRcstWhBduDRyzmRxbrLjIBiWe5KQ2nVaTxPfZN-k2EOnUUpZOEGITSBHdOtlD1Z8kT2zxRI9oSj-QVajyt_GY7rlb9rzumlZN6tru-_ahA=w1022-h761-no]Error message for approach 2[/img]





    Basic Member






    --
    11/2/2017 4:49 PM
    Adam the way we do this is to hide the product options with a style of display: none. Then we perform the selection on the hidden options via a javascript callback. For our instance, we know what selection to make based on the users earlier input. In your instance, you can hook up a javascript change event on your second option list that you created in your Attempt #2 to select the option in the hidden primary option list.





    New Member






    --
    11/2/2017 8:03 PM
    Thank you Matt! That approach seems to be working well at first look.

    Here is the code I used in _ProductDetails.cshtml (along with approach #2 from my original post).

    [code=csharp]int optionItemCounter = 0; //Counts optionItems across all options for the product, for use with PracticeWise custom student option hiding code.
    foreach (var opt in Model.LocalProduct.Options)
    {
    string optId = "hccProductOption" + optionItemCounter;
    string newOptId = "hccNonStudentProductOption" + optionItemCounter;
    string optDisplay = "Block";
    if (HasStudentOptions(opt) && !ShowStudentPricing())
    { //Set display of the original option to none, and display a clone without the student optionItems.
    optDisplay = "None";
    Hotcakes.Commerce.Catalog.Option newOpt;
    newOpt = CloneWithoutStudentOptions(opt);
    <div class="dnnFormItem clearfix" id="@newOptId">
    @if (!newOpt.NameIsHidden)
    {@newOpt.Name}
    <div class="hc-option">
    @Html.Raw(newOpt.RenderWithSelection(Model.Selections.OptionSelectionList))
    </div>
    </div>
    }
    <div class="dnnFormItem clearfix" id="@optId" style="display:@optDisplay">
    @if (!opt.NameIsHidden)
    {@opt.Name}
    <div class="hc-option">
    @Html.Raw(opt.RenderWithSelection(Model.Selections.OptionSelectionList))
    </div>
    </div>
    if (HasStudentOptions(opt) && !ShowStudentPricing())
    { //Add an event listener for the option's clone (newOpt) and use it to update the selection for the original option (opt).

    document.getElementById('@newOptId').onclick = function() {
    var optName = document.getElementById('@optId').getElementsByTagName('input')[0].name;
    var newOptName = document.getElementById('@newOptId').getElementsByTagName('input')[0].name;
    var selectdValue = $('input[name="' + newOptName +'"]:checked').val();
    $('input[name="' + optName + '"][value="' + selectdValue + '"]').prop('checked', true);
    };

    }
    }
    optionItemCounter++;[/code]





    Veteran Member






    --
    11/14/2017 10:39 PM
    @Adam: It sounds like you have this resolved. Is that right?
    Will Strohl, Upendo Ventures Hotcakes Cloud | Get Support | Code Support Official Cloud & Support provider for Hotcakes





    New Member






    --
    11/15/2017 10:22 PM
    Hi Will, thanks for checking on this. Yes, I think this is resolved. I haven't put it into production yet, but it is looking good in my testing.
    You are not authorized to post a reply.


    Loading
    • Sign-up for the Hotcakes Community Newsletter: