[CLOSED] IFrame alternative using partial view

Page 1 of 2 12 LastLast
  1. #1

    [CLOSED] IFrame alternative using partial view

    Hi Support,

    I'm working on application where I need to render basic shell of application on startup which contains few controls and Menu. And all the other pages should be render inside the loaded shell's Main content container.I was able to load the partial view, However when I do post operation it post back whole page. How do I make it behave like IFrame so whole page doesn't postback ?

    Attached is sample code to reproduce the issue.

    Shell Controller:
     public class ShellController : Controller
        {
            //
            // GET: /Test/
            [HttpGet]
            public ActionResult Shell()
            {
                return View();
            }
    
            [HttpGet]
            public ActionResult Home()
            {
                return new Ext.Net.MVC.PartialViewResult
                {
                    ContainerId = "MainContent",
                    WrapByScriptTag = false,
                    ViewName = "Home"
                };
            }
    	}
    Shell.cshtml

    @{
        ViewBag.Title = "Index";
        Layout = null;
        var X = Html.X();
    }
    
    
    
    @(Html.X().ResourceManager())
    
    @(
     X.Viewport()
            .Layout(LayoutType.Anchor)
            .Items(
    
                    X.Container()
                     .Region(Ext.Net.Region.North)
                     .Border(true)
                     .ID("TopPanel")
                     .Items(
                              X.Toolbar()
                               .ID("ToolBarContent")
                               .Items(
    
                                         X.ComboBox()
                                          .ID("cmbTest1")
                                          .Editable(false)
                                          .Width(250)
                                          .LabelWidth(30)
                                          .MarginSpec("0 5 0 5")
                                          .FieldLabel("Test1:")
                                         .Items(
                                              new Ext.Net.ListItem("Item 1", "1"),
                                              new Ext.Net.ListItem("Item 2", "2")
                                               )
    
                                          )
                                    ,
                                    X.Toolbar()
                                     .ID("ToolBarMenu")
                                     .Items(
    
                                            X.Button()
                                                .ID("MenuGlobalSetupButton")
                                                .Text("GlobalSetup")
                                                .Icon(Icon.World)
                                                .Menu(
                                                    X.Menu()
                                                        .Icon(Icon.ArrowDown)
                                                        .Header(false)
                                                        .Items(
                                                            X.MenuItem()
                                                                .ID("MenuFooItem")
                                                                .Icon(Icon.BulletWrench)
                                                                .Text("Foo Setup")
                                                                .DirectClickUrl("../Foo/Index")
    
                                                            )
                                                    )
                                                )
                                        ),
    
                                        X.Container()
                                            .ID("MainContent")
                                                 .Loader(
                                                     X.ComponentLoader()
                                                        .Mode(LoadMode.Script)
                                                        .LoadMask(loadmask => { loadmask.ShowMask = true; })
                                                        .Url(Url.Action("Home"))
                                                        .Params(new { containerId = "MainContent" })
                                                      )
                               )
    )
    Home.cshtml

    @{Layout = null;}
    
    <div >
        <h1>Welcome </h1>
        <p>This is a test page.</p>
    </div>

    Foo Controller

     public class FooController : Controller
        {
            [HttpGet]
            public ActionResult Index()
            {
                return new Ext.Net.MVC.PartialViewResult
                {
                    ContainerId = "MainContent",
                    ViewName = "FooView",
                    RenderMode = RenderMode.AddTo,
                   WrapByScriptTag = false,
                    Model = new FooModel()
                    {
                        TextValue = "TextValue",
                        DateTimeValue = DateTime.Now,
                        ComboValue1 = new ListItem("Item 1", "1"),
                        ComboValue2 = new ListItem[]
                        {
                            new ListItem("Item 1", "1"),
                            new ListItem("Item 5", "5")
                        },
                        ComboValue3 = "1",
                        CheckboxValue = true,
                        NumberValue = 1,
                        MultiSliderValue = new int[] {10, 40, 70},
    
                        Data = new ListItem[]
                        {
                            new ListItem("Item 1", "1"),
                            new ListItem("Item 2", "2"),
                            new ListItem("Item 3", "3"),
                            new ListItem("Item 4", "4"),
                            new ListItem("Item 5", "5")
                        }
                    }
                };
            }
    
            [HttpPost]
            public ActionResult Index(FooModel model)
            {
                X.Msg.Notify("Saved", "Successfully saved").Show();
                return this.Direct();
            }
    }
    FooView.cshtml

    @model MIPS.Models.FooModel
    @{
        ViewBag.Title = "Model Bind";
        Layout = null;
    }
    
    <h1>Foo</h1>
    
    @(
     Html.X().FormPanel()
            .Layout(LayoutType.Form)
            .Width(350)
            .FieldDefaults(d =>
            {
                d.LabelWidth = 150;
            })
            .BodyPadding(10)
            .Frame(true)
            .Items(
                Html.X().TextFieldFor(m => m.TextValue),
                Html.X().DateFieldFor(m => m.DateTimeValue),
                Html.X().ComboBoxFor(m => m.ComboValue1).Items(Model.Data),
                Html.X().ComboBoxFor(m => m.ComboValue2).Items(Model.Data),
                Html.X().ComboBoxFor(m => m.ComboValue3).Items(Model.Data),
                Html.X().CheckboxFor(m => m.CheckboxValue),
                Html.X().NumberFieldFor(m => m.NumberValue),
                Html.X().SliderFor(m => m.MultiSliderValue)
            )
                 .Buttons(
                                        Html.X().Button()
                                            .Text("Save")
                                            .Icon(Icon.Disk)
                                            .FormBind(true)
                                            .DirectEvents(de =>
                                                {
                                                    de.Click.Url = Url.Action("Index");
                                                    de.Click.Method = HttpMethod.POST;
                                                    de.Click.EventMask.ShowMask = true;
    
                                                }))
    )
    Foo Model

     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using Ext.Net;
    using  Ext.Net.MVC;
    
     public class FooModel
        {
            [Field(FieldLabel = "TextField")]
            public string TextValue
            {
                get;
                set;
            }
    
            [Field(FieldLabel = "DateField")]
            public DateTime DateTimeValue
            {
                get;
                set;
            }
    
            [Field(FieldLabel = "ComboBox 1")]
            public ListItem ComboValue1
            {
                get;
                set;
            }
    
            [Field(FieldLabel = "ComboBox 2")]
            public IEnumerable<ListItem> ComboValue2
            {
                get;
                set;
            }
    
            [Field(FieldLabel = "ComboBox 3")]
            public string ComboValue3
            {
                get;
                set;
            }
    
            [Field(FieldLabel = "CheckBox")]
            public bool CheckboxValue
            {
                get;
                set;
            }
    
            [Field(FieldLabel = "NumberField")]
            public int NumberValue
            {
                get;
                set;
            }
    
            [Field(FieldLabel = "MultiSlider")]
            public int[] MultiSliderValue
            {
                get;
                set;
            }
    
            public IEnumerable<ListItem> Data
            {
                get;
                set;
            }
        }

    Thanks
    Last edited by fabricio.murta; Oct 10, 2016 at 8:56 PM.
  2. #2
    Hello @fahd!

    Thanks, your example is simple and comprehensive enough! I didn't run it yet as almost always some changes are needed in MVC examples to work despite being delivered in a good shape by users. I'll try and run your sample code later on anyway.

    But from a quick look, I can see you have an action bound to a full index page, and that seems to be what makes your whole page loads.

    Can you, in the meanwhile, check this example out: Dynamic Partial Rendering - Partial Content.

    Notice how it loads data into the frame if you click the first button. But don't click once, click again on the first button, you'll see content overflowing out of the frame. That's simply because what was previously added was not cleared first when the button was clicked.

    I believe in this example you get exactly what it takes to emulate the iframe like you described. Just that the container's content should be scrolled on overflow instead of just visible.
    Fabrício Murta
    Developer & Support Expert
  3. #3
    Hello again @fahd!

    In your FooModel, you are using [Field(FieldLabel = "...")] which triggers Ext.Net.Field is not an attribute class. Can you provide full namespace for this Field attribute or maybe using statements you have for the FooModel class?
    Fabrício Murta
    Developer & Support Expert
  4. #4
    Sample updated with Using statment
  5. #5
    Hello!

    Did you forget to provide a different Home overload? I don't get the Home view loaded due to its [HttpGet] attribute. With this, I can load it if I access the Home view directly from browser but it does not load from the Shell's Loader. Just removing the attribute from the Home view in controller code seems to work but maybe you are doing something different, so I am confirming it with you!
    Fabrício Murta
    Developer & Support Expert
  6. #6
    Considering this change in the Home controller is acceptable, I'm not getting a full page reload when I click the save button in the partial form.

    How exactly are you identifying it as a full postback?..

    I have added the following to the Shell.cshtml file:

    <script type="text/javascript">
        console.log("Shell loaded! ["+Date()+"]");
    </script>
    So that it would log the time the page was loaded.

    Additionally, you may have the feeling that the page is being reloaded as a whole due to the mask "flicker" when you send the data. To address this, I also added to your public ActionResult Index(FooModel model) code:
    System.Threading.Thread.Sleep(2000);

    So I can see the load mask sit for a while before returning.

    And when it gets back, I see the shell's console.log() script is not called again.

    I believe you didn't focus your example on keeping the contents of the emulated iframe empty so I'll not elaborate on this aspect unless you ask for, probably in another thread if you want.

    As for the form submission, yours looks fine, but here's an example of a form submit with MVC that might just be interesting for you: Models - Submit.

    Let us know if this does not help you, probably you want to clarify how are you identifying the full postback is being issued.
    Fabrício Murta
    Developer & Support Expert
  7. #7
    Thank you Fabricio,

    After removing [HttpGet] as you mentioned the home page loaded. I was also able to clear the content of the container by having following in my Foo index(Get) method. Is that right approach ?
     RenderMode = RenderMode.Replace
    Yes,You were right. I thought it's full postback because of the how mask works, is there any way I can specify which area should have mask?

    Also, In my Foo Index(POST) if I do
    RedirectToAction("Home", "Shell");
    then whole page redirect happens and it renders just the script. How do I redirect in this scenario then?
  8. #8
    Hello @fahd!

    Well, I tried here simply adding this render mode as 'replace' for me didn't really work.

    What I've done is clean up from JavaScript before calling the new content. In other words, I drawn this script:

    <script type="text/javascript">
        var cleanupContainer = function () {
            var container = App.MainContent,
                content = container.el.dom.children;
    
            // Remove the main content if present
            if (content[1] && content[1].children[0]) {
                var cmp = Ext.getCmp(content[1].children[0].id);
                cmp.destroy();
            }
    
            if (content[0] && content[0].children[0]) {
                var subContent = content[0].children[0].children;
                for (var i = 0; i < subContent.length; i++) {
                    var subCmp = Ext.getCmp(subContent[i].id);
    
                    if (subCmp) subCmp.destroy();
                }
            }
        }
    </script>
    Then bound it to the menu item like this:

    X.MenuItem()
        .ID("MenuFooItem")
        .Icon(Icon.BulletWrench)
        .Text("Foo Setup")
        .Handler("cleanupContainer()")
        .DirectClickUrl("Index")
    So every time before clicking, it cleans up the contents before receiving the new page, properly disposing of the ExtJS components.

    But maybe you tried the RenderMode.Replace and it worked on your side?

    As for specifying the mask, all you have to do is specify a target to mask, which would be the container.

    To make life easier, give your container in the Shell.cshtml file an ID, say .ID("MainContent"). Then on the FooView.cshtml file, just add a line to determine the target:

    de.Click.EventMask.CustomTarget = "App.MainContent";
    About the last topic, about redirection, what you are doing is

    return RedirectToAction("Home", "Shell");
    instead of

    return this.Direct();
    Right?.. It seems to me you just swapped the parameters. First is the action, second is the controller. If you are redirecting to an action to the same controller, you don't even need to specify it. I think that, in your case, you don't have to specify the controller name (second parameter). Yet, I'm not sure what you want to achieve with that. That would pretty much just load the main page over again, doing a full page load.
    Fabrício Murta
    Developer & Support Expert
  9. #9
    I got error Cannot read property 'destroy' of undefined in javascript at line 'cmp.destroy();' so it didn't clear the content.

    For me RenderMode.Replace while returning partialview result clears the container, but then mask setting doesn't work (no masking at all) even if I set customTarget property. If you can fix the error then I can use that script and have masking work.

    About RedirectToAction("Action", "Controller"), what I'm trying to do is implement Post/Redirect/Get pattern so after successful post operation I'm trying to return fresh data with GET call. I also need to do that when I need to send users to Error page or something similar.

    Thanks
  10. #10
    For the render mode, it makes sense.

    So, while RenderMode.AddTo adds the content drawn by the returned script into the specified container, RenderMode.Replace would just replace the content drawn by the returned script removing the specified container and not removing the previous content added into the container.

    But as for the cmp.destroy() error you are getting, probably something from your view is different from mine. I might clean up the code here and provide you with the full modified code I have come up with to be sure. Notice I had to change namespaces and stuff, but I'm sure the namespaces I used won't conflict with your solution (for the names contain the number of this thread, like c61383_HomeController.
    Fabrício Murta
    Developer & Support Expert
Page 1 of 2 12 LastLast

Similar Threads

  1. Generic alternative for @model in Razor view
    By millenovanta in forum 2.x Help
    Replies: 3
    Last Post: Sep 04, 2013, 6:16 AM
  2. [MVC] How to use a partial view in a window?
    By KBorkiewicz in forum 2.x Help
    Replies: 7
    Last Post: Nov 21, 2012, 11:11 PM
  3. [CLOSED] iFrame load alternative?
    By softmachine2011 in forum 2.x Legacy Premium Help
    Replies: 10
    Last Post: Oct 11, 2012, 2:13 PM
  4. [CLOSED] [2.1] MVC Partial View
    By softmachine2011 in forum 2.x Legacy Premium Help
    Replies: 4
    Last Post: Aug 23, 2012, 12:04 PM
  5. [CLOSED] Grid.view.refreshRow too slow. Is there an alternative?
    By jchau in forum 1.x Legacy Premium Help
    Replies: 1
    Last Post: Mar 16, 2011, 10:40 PM

Posting Permissions