Widget to show data

Topics: Troubleshooting, Writing modules
Aug 21, 2014 at 4:22 PM
I created a Deposit module. My main goal with this module is to save some data on the DB.

I already made my custom type (Deposit) with my custom part (DepositPart) and it worked like I expected.

This DepositPart save the name, currency, liquidity, month, and url on the database.
But now I want to make a simple widget with 3 combobox and a button.

On those combobox I have some static text where the user can choose from. When the user hit the button I want to make a query and return a list with some Deposits and show only the name and the liquidity.

What is the best way to achieved this?
Developer
Aug 21, 2014 at 11:16 PM
One way is to write another content part for that widget, e.g. LiquidityCheckerPart (attach it to a content type called LiquidityCheckerWidget).
When the user hits the button, you make an AJAX request to a custom controller. This controller accepts the 3 values from the comboboxes, executes the query, and returns a ViewResult. You inject the resulting HTML into some placeholder DIV on your widget (and optionally hide the 3 comboboxes).
Aug 22, 2014 at 1:04 PM
My widget needs to be on the homepage. The widgets should load with a view with 3 combobox and a button. The first combobox will have 4 options to choose from. The second one will have 2 options and the third will also have 2 options to choose.
It's only after choosing all the options on the combobox that I hit the button to execute the query based on the combobox options. So I think that I can't follow your instructions
Aug 22, 2014 at 6:07 PM
I followed this tutorial: http://skywalkersoftwaredevelopment.net/blog/writing-an-orchard-webshop-module-from-scratch-part-7

I created a SimulatorWidgetPart.cs:
public class SimulatorWidgetPart : ContentPart
    {
    }
SimulatorWidgetPartDriver.cs:
public class SimulatorWidgetPartDriver : ContentPartDriver<SimulatorWidgetPart>
    {
        private readonly ISimulator _simulator;

        public SimulatorWidgetPartDriver(ISimulator simulator)
        {
            _simulator = simulator;
        }
 
        protected override DriverResult Display(SimulatorWidgetPart part, string displayType, dynamic shapeHelper) {
            return ContentShape("Parts_SimulatorWidget", () => shapeHelper.Parts_SimulatorWidget(
                Month: _simulator.GetMonth(),
                Liquidity: _simulator.GetLiquidity(),
                Currency: _simulator.GetCurrency()
            ));
        }

    }
Migrations.cs
public int UpdateFrom3()
        {
            // Define a new content type called "ShoppingCartWidget"
            ContentDefinitionManager.AlterTypeDefinition("SimulatorPartWidget", type => type

                // Attach the "ShoppingCartWidgetPart"
                .WithPart(typeof(SimulatorWidgetPart).Name)

                // In order to turn this content type into a widget, it needs the WidgetPart
                .WithPart("WidgetPart")

                // It also needs a setting called "Stereotype" to be set to "Widget"
                .WithSetting("Stereotype", "Widget")
                );

            return 4;
        }

        public int UpdateFrom4()
        {
            // Update the ShoppingCartWidget so that it has a CommonPart attached, which is required for widgets (it's generally a good idea to have this part attached)
            ContentDefinitionManager.AlterTypeDefinition("SimulatorPartWidget", type => type
                .WithPart("CommonPart")
            );

            return 5;
        }
ISimulator.cs:
public interface ISimulator : IDependency
    {
        IEnumerable<Month> GetMonth();
        IEnumerable<Liquidity> GetLiquidity();
        IEnumerable<Currency> GetCurrency();
    }

    public enum Month
    {
        One,
        Three,
        Six,
        twelve
    }

    public enum Currency
    {
        EUR,
        USD
    }

    public enum Liquidity
    {
        Anytime,
        Final
    }
Simulator.cs:
public class Simulator : ISimulator
    {
        public IEnumerable<Month> GetMonth()
        {
            return Enum.GetValues(typeof(Month)).Cast<Month>();
        }

        IEnumerable<Liquidity> ISimulator.GetLiquidity()
        {
            return Enum.GetValues(typeof(Liquidity)).Cast<Liquidity>();
        }

        IEnumerable<Currency> ISimulator.GetCurrency()
        {
            return Enum.GetValues(typeof(Currency)).Cast<Currency>();
        }
    }
SimulatorWidget.cshtml:
@{
    Style.Require("BPAE.Deposits.SimulatorWidgetPartDriver");
}

<div>
    Prazo @Html.EnumDropDownListFor(Model.GetMonth)
    Moeda @Html.EnumDropDownListFor(Model.GetCurrency)
    Mobilização @Html.EnumDropDownListFor(Model.GetLiquidity)
</div>
But now I have a compilation error:
Compilation Error

Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately. 

Compiler Error Message: CS1973: 'System.Web.Mvc.HtmlHelper<dynamic>' has no applicable method named 'EnumDropDownListFor' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax.

Source Error:


Line 4:  
Line 5:  <div>
Line 6:      Prazo @Html.EnumDropDownListFor(Model.GetMonth)
Line 7:      Moeda @Html.EnumDropDownListFor(Model.GetCurrency)
Line 8:      Mobilização @Html.EnumDropDownListFor(Model.GetLiquidity)
Aug 22, 2014 at 6:59 PM
I added @using System.Web.Mvc.Html to my SimulatorWidget.cshtml, but I still have the error.
Aug 22, 2014 at 7:27 PM
jfredsilva wrote:
I added @using System.Web.Mvc.Html to my SimulatorWidget.cshtml, but I still have the error.
The EnumDropDownListFor helper is only available from mvc 5.1, check if your module´s web.config is referencing the correct version.
Or you can allways try @Html.DropDownList helper or just use a plain html select element.
Aug 22, 2014 at 7:41 PM
I don't think the error is due to EnumDropDownListFor, because I already made a controller/view using it.
Aug 22, 2014 at 7:47 PM
Ok i see the problem, in the EnumDropDownListFor you need to use a lambda expression as argument.

like

@Html.EnumDropDownListFor(m =>m.GetMonth)
Aug 22, 2014 at 8:03 PM
Why are you using an IEnumerable of Enums in your EnumDropDownListFor?
Why don´t you just use the Enum itself?

Check this article about using enums in views, it might help you.

http://weblogs.asp.net/jongalloway/looking-at-asp-net-mvc-5-1-and-web-api-2-1-part-1-overview-and-enums
Sep 1, 2014 at 11:59 AM
Edited Sep 1, 2014 at 12:10 PM
I changed to use lambda expression and I have a new error:
Compilation Error

Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately. 

Compiler Error Message: CS1963: An expression tree may not contain a dynamic operation

Source Error:


Line 5:  
Line 6:  <div>
Line 7:      Prazo @Html.EnumDropDownListFor(m => m.GetMonth)
Line 8:      Moeda @Html.EnumDropDownListFor(m => m.GetCurrency)
Line 9:      Mobilização @Html.EnumDropDownListFor(m => m.GetLiquidity)
Now my SimulatorWidget.cshtml looks like:
@using System.Web.Mvc.Html
@{
    Style.Require("BPAE.Deposits.SimulatorWidgetPartDriver");
}

<div>
    Prazo @Html.EnumDropDownListFor(m => m.GetMonth)
    Moeda @Html.EnumDropDownListFor(m => m.GetCurrency)
    Mobilização @Html.EnumDropDownListFor(m => m.GetLiquidity)
</div>
I use IEnumerable because I was advised to use them on Interfaces. I don't think that they are the problem because when I set a breakpoint on my DriverResult in the file SimulatorWidgetPartDriver, I can see that Month, Liquitidy and Currency are filled with the correct atributes.