How to implement alternative to Html.RenderAction

  1. #1

    How to implement alternative to Html.RenderAction

    In our application, we were using Html.RenderAction to add partial views to specific regions in the ViewPort of the main page. Since we just moved to Ext 7.2 (and consequently .Net Core). This allows us to modularly add (or leave out) partialViews to the ViewPort on the calling pages when needed. Here's a stripped down example of what we did before...

    _Header
    @using Ext.Net;
    @using Ext.Net.MVC;
    @using FIS.Presentation.EWAPPM.Models
    
    @model HeaderModel
    
    @(Html.X().Menu()
            .ID("mnuBar")
            .Layout(LayoutType.HBox)
            .BodyCls("menuOverride")
            .Floating(false)
            .ShowSeparator(false)
            .Region(Region.North)
            .Height(40)
            .Items(
                Html.X().Label()
                    .Text("EWAPPM 2.0")
                    .Width(250)
                    .BaseCls("ewappmLogo")
                    .MarginSpec("5 0 0 15"),
    
                //------------------------------------
                // Home
                //------------------------------------
                Html.X().MenuItem()
                    .Text("Home")
                    .Href(Url.Content("~/Home/GoToDashboard"))
                    .BaseCls("menuItemStyleDefault")
                    .ActiveCls("menuItemStyleHover")
                    .Width(115),
    
                //------------------------------------
                // Profile
                //------------------------------------
                Html.X().MenuItem()
                    .Text("My Stuff")
                    .Href(Url.Content("~/User/GoToUserDashboard"))
                    .BaseCls("menuItemStyleDefault")
                    .ActiveCls("menuItemStyleHover")
                    .Width(120 + (Model.MyStuffCount.Length * 5))
                    .Plugins(
                        Html.X().Badge()
                            .Text(Model.MyStuffCount)
                            .AlignmentSpec("r-r")
                            .UI(UI.Danger.ToString())
                            .HideEmpty(true)
                            .RenderToBody(true)
                    ),
    
                Html.X().ToolbarFill(),
    
                //------------------------------------
                // Sign Out
                //------------------------------------
                Html.X().MenuItem()
                    .Cls("menuItemStyleDefault")
                    .ActiveCls("menuItemStyleHover")
                    .Text("Sign Out")
                    .Icon(Icon.DoorOut)
                    .Width(120)
                    .Href(Url.Content("~/Security/SignOut"))
            )
    )
    Dashboard
    @using Ext.Net;
    @using Ext.Net.MVC;
    @using FIS.Presentation.EWAPPM.Models
    
    @{
        Layout = "~/Views/Shared/_StandardLayout.cshtml";
        ViewBag.Title = "Dashboard";
    }
    
    @model DashboardModel
    
    <div class="grid-row">
        @{ Html.RenderAction("RenderTOCSideBar", "Home"); }
        @{ Html.RenderAction("RenderHeader", "Common"); }
        @{ Html.RenderAction("RenderCompatibilityWarning", "Common"); }
    
        @(Html.X().Viewport()
            .Layout(LayoutType.Border)
            .ID("vpEWAPPM")
            .Items(
                Html.X().Panel()
                    .Layout(LayoutType.Border)
                    .Region(Region.Center)
                    .Items(
                        Html.X().Portal()
                            .ID("portalDashboard")
                            .Border(false)
                            .Region(Region.Center)
                            .Items(
                                Html.X().PortalColumn()
                                    .Items(
                                        Html.X().Portlet()
                                            .Title("My Favorites")
                                            .HideCollapseTool(true)
                                            .Closable(false)
                                            .Height(250)
                                            .Frame(false)
                                            .Border(true)
                                            .Layout(LayoutType.Fit)
                                            .Icon(Icon.PageWhiteStack)
                                            .MarginSpec("0 0 10 0")
                                            .Tools(
                                                Html.X().Tool()
                                                    .Type(ToolType.Help)
                                                    .ToolTip("Help")
                                                    .DirectEvents(de =>
                                                    {
                                                        de.Click.Url = Url.Action("Dashboard_Legend");
                                                    })
                                            )
                                            .Items(
                                                Html.X().GridPanel()
                                                    .EnableColumnHide(false)
                                                    .EnableColumnMove(false)
                                                    .Store(
                                                        Html.X().Store()
                                                            .ID("storeMyItems")
                                                            .DataSource(Model.UserFavoriteDocuments)
                                                            .AutoLoad(true)
                                                            .Model(Html.X().Model()
                                                                .Fields(
                                                                    Html.X().ModelField().Name("DocKey").Type(ModelFieldType.Int),
                                                                    Html.X().ModelField().Name("DocumentNumber").Type(ModelFieldType.String),
                                                                    Html.X().ModelField().Name("DocTitle").Type(ModelFieldType.String)
                                                                )
                                                        )
                                                    )
                                                    .ColumnModel(
                                                        Html.X().Column()
                                                            .Hidden(true)
                                                            .Hideable(false)
                                                            .DataIndex("DocKey"),
                                                        Html.X().Column()
                                                            .DataIndex("DocumentNumber")
                                                            .Text("Document #")
                                                            .Flex(1)
                                                            .Resizable(false)
                                                            .Hideable(false)
                                                            .Filter(Html.X().StringFilter()),
                                                        Html.X().Column()
                                                            .DataIndex("DocTitle")
                                                            .Text("Document Title")
                                                            .Flex(3)
                                                            .Resizable(false)
                                                            .Hideable(false)
                                                            .Filter(Html.X().StringFilter())
                                                    )
                                                    .Plugins(Html.X().GridFilters())
                                                    .View(
                                                        Html.X().GridView().TrackOver(true)
                                                        .DirectEvents(de =>
                                                        {
                                                            de.ItemDblClick.Url = Url.Action("GoToViewDocumentDashboard");
                                                            de.ItemDblClick.ExtraParams.Add(new Parameter { Name = "docKey", Value = "record.data.DocKey", Mode = Ext.Net.ParameterMode.Raw });
                                                        })
                                                    )
                                                    .BottomBar(Html.X().StatusBar().Text("Double-click a row to view the item."))
                                            )
                                    ),
                                Html.X().PortalColumn()
                                    .Items(
                                        Html.X().Panel()
                                            .Title("What's New")
                                            .Icon(Icon.New)
                                            .BodyPadding(5)
                                            .Height(250)
                                            .Frame(false)
                                            .Border(true)
                                            .Layout(LayoutType.Fit)
                                            .Html(Model.PanelInfo.PanelHTML)
                                            .HideCollapseTool(true)
                                            .Closable(false)
                                            .AutoScroll(true)
                                            .MarginSpec("0 0 10 0")
                                            .Tools(
                                                Html.X().Tool().CustomType("edit").ToolTip("Edit").Hidden(!Model.AllowUpdateWhatsNew)
                                                    .DirectEvents(de =>
                                                    {
                                                        de.Click.Url = Url.Action("GoToEditPanel", "Admin");
                                                        de.Click.ExtraParams.Add(new Parameter { Name = "panelID", Value = "pnlWhatIsNew", Mode = Ext.Net.ParameterMode.Value });
                                                        de.Click.ExtraParams.Add(new Parameter { Name = "panelName", Value = "What's New", Mode = Ext.Net.ParameterMode.Value });
                                                    })
                                            )
                                    )
                            )
                    )
            )
        )
    </div>
    CommonController
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Principal;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Security;
    using Ext;
    using Ext.Net;
    using Ext.Net.MVC;
    using FIS.Presentation.EWAPPM.Models;
    using FIS.Presentation.EWAPPM.Helpers;
    using FIS.Presentation.EWAPPM.Security;
    using FIS.Infrastructure.EWAPPM.Domain;
    
    namespace FIS.Presentation.EWAPPM.Controllers
    {
        public class CommonController : Controller
        {
            #region Global Variables
    
            private HomeService _ewappmService = new HomeService(MvcApplication.Environment);
            private UserService _userService = new UserService(MvcApplication.Environment);
            private TrainingService _trainingService = new TrainingService(MvcApplication.Environment);
    
            #endregion Global Variables
    
            [AllowAnonymous]
            public ActionResult RenderCompatibilityWarning()
            {
                // This variable was originally used to handle the text in the label.
                // The message was moved to the label itself, but I left the plumbing in case we can leverage it for other purposes later.
                string labelMessage = "";
    
                return new Ext.Net.MVC.PartialViewResult
                {
                    ViewName = "_CompatibilityWarning",
                    RenderMode = RenderMode.AddTo,
                    ContainerId = "vpEWAPPM",
                    Model = labelMessage
                };
            }
    
            [EWAPPMAuthorize(ClaimType = "role", ClaimValues = "user,approver,admin")]
            public ActionResult RenderHeader()
            {
                HeaderModel model = new HeaderModel();
    
                return new Ext.Net.MVC.PartialViewResult
                {
                    ViewName = "_Header",
                    RenderMode = RenderMode.AddTo,
                    ContainerId = "vpEWAPPM",
                    Model = model
                };
            }
        }
    }
    We've used this technique to do Headers, Footers and various Sidebars appropriate to the site and specific content. We are hoping to find something that will allow us to be able to do the same thing in the new environment.

    It looks like we would need to use ViewComponents, but aren't quite sure how to handle the concept of adding directly into a given container ("vpEWAPPM" in the case of my example) since we don't have PartialViewResult.

    Hope all this makes sense... and this question helps others out in the future.

    Thanks for any help you guys can provide!
    Craig
  2. #2
    Anybody out there have a suggestion? I think my biggest hurdle with this approach is that we haven't located an EXT.Net implementation of the PartialViewResult in this version of EXT (before we were getting it from Ext.Net.MVC).

    PartialViewResult is also going to be a hurdle for my team when we do more complex popup windows.
  3. #3
    Hi. Thanks for the code samples. We will investigate and work out how this technique would be accomplished in Ext.NET Classic 7+.
    Geoffrey McGill
    Founder
  4. #4
    There are issues in Ext.NET Classic v7+ with implementing your approach. We are still investigating and will figure out a solution.
    Geoffrey McGill
    Founder
  5. #5
    Hello Craig!

    How do you think the ComponentLoader approach would fit your needs? Maybe that's worth a try? We had a recent thread asking about it and, at least the scenario therein, worked for me just fine. Take a look on the thread:
    - ComponentLoader Rendering.

    We are still working in ways related to actual partial rendering in a fashion that resembles more your scenario, but just in case that, that alternative could count towards a possibility for you, we're posting this.

    Let us know what you think.
    Fabrício Murta
    Developer & Support Expert
  6. #6
    Hello again, Craig!

    We didn't receive a follow-up from our last posts but I'll leave a few leads here for some other alternatives based on the current supported implementation of partial views in Ext.NET 7.

    All these solutions works using the new TagHelpers syntax, introduced by ASP.NET Core as an alternative for the discontinued WebForms technology. For brevety on the answer, I'll draw short code blocks suppressing context. If you feel any of these are hard to understand, we can post full example, or publish a full example using it in our examples explorer github repo and website.

    - Expression conditionals in the view

    This option allows for simpler partial views while the logic of inclusion will lie within the main view.

    Example:

    partial view
    <ext-component html="My Ext.NET Components here" />
    main view
    @{
        if (Model.Role != Project.Roles.Guest)
        {
            <ext-partial name="PartialViewName" />
        }
    }
    The partial view doesn't need an entry within the controler to be rendered. And it is just an ordinary view file without context (layout, thus html/body/head blocks), but it can have a model passed via ext-partial via model="Model" or even part of the model (model=Model.MyObject).

    - Expression conditionals within each partial view

    This one will look cleaner in the main page, and the partial view would basically be wrapped in condition. In this case, passing a model should usually be necessary (unless you have access to the condition thru other means, like global/static variables).

    partial view
    @model Project.Models.MyPageModel
    
    @{
        if (Model.Role != Project.Roles.Guest)
        {
            <ext-component html="My Ext.NET Components here" />
        }
    }
    main view
    @model Project.Models.MyPageModel
    
    <ext-partial name="PartialViewName" model="Model" />
    Which could as well be:

    partial view
    @model bool
    
    @{
        if (Model)
        {
            <ext-component html="My Ext.NET Components here" />
        }
    }
    main view
    @model Project.Models.MyPageModel
    
    <ext-partial name="PartialViewName" model="Model.Role != Project.Roles.Guest" />
    - View Components

    This may be the most complex one for a short example, but probably the most scalable option among the one(s) above, for benefitting from different features already in ASP.NET Core. Here's the feature specific documentation, essential to get it to work: View components in ASP.NET Core | Microsoft Docs

    As far as Ext.NET is concerned, it basically involves instructing the ViewComponents to be drawn to specific page sections.

    Some examples within the view page would be:

    @await Component.InvokeAsync("AdminPanel")
    @await Component.InvokeAsync("Header", new { role = Model.Role })
    @await Component.InvokeAsync("Login", new { isLogged = Model.Role != Example3Model.Roles.Guest })
    Respectively, the signatures in the view components' code files would be:

    AdminPanel
    public IViewComponentResult Invoke()
    Header
    public IViewComponentResult Invoke(Project.Models.MyPageModel.Roles role)
    Login
    public IViewComponentResult Invoke(bool isLogged)
    The key here then is to define the location of the components in the main view and in the component.

    So a view with the simpler AdminPanel component would involve:

    Component definition
    AdminPanel.cshtml
    <ext-section target="AdminPanelViewComponent">
        <ext-panel region="South" title="Administrator Panel" html="Administration panel contents" />
    </ext-section>
    View referencing the component
    Index.cshtml
    @await Component.InvokeAsync("AdminPanel")
    
    (...)
    
    <ext-section name="AdminPanelViewComponent" required="false" />
    I tried to be as brief as possible with the examples and still give good clues how things should look in the project. Let us know if you'd needed a little further in any of these options to get started. We can post further parts of each approaches as required.

    Hope this helps!
    Fabrício Murta
    Developer & Support Expert

Similar Threads

  1. 4.x alternative to parentAutoLoadControl
    By paul-2011 in forum 4.x Help
    Replies: 1
    Last Post: Jun 23, 2016, 11:21 PM
  2. Replies: 3
    Last Post: Mar 13, 2012, 7:58 PM
  3. JSON alternative
    By MGholam in forum Feature Requests
    Replies: 1
    Last Post: Nov 22, 2011, 1:15 AM
  4. [CLOSED] A lighter alternative to Toolbar
    By jchau in forum 1.x Legacy Premium Help
    Replies: 4
    Last Post: Nov 02, 2011, 7:35 AM
  5. Alternative Time control
    By r_honey in forum Open Discussions
    Replies: 3
    Last Post: Jun 16, 2009, 9:07 AM

Posting Permissions