Partial Rendering

Page 2 of 2 FirstFirst 12
  1. #11
    I tried the approach of using a loader, as per the example recently added to the Ext.NET 7.2 Examples Explorer. However, I'm having a problem when one of the controls that I am attempting to dynamically load is a chart. I get the following error in the JS console:

    Unrecognized class name / alias: widget.cartesian
    I believe this error is occurring because the charts.js script isn't being loaded onto the page. When I was adding charts via markup this script was being automatically loaded. I assume that's because, when adding charts at design time, the framework knows that the the charts.js script needs to be loaded. What's the best approach to load this script when adding charts dynamically to a page? Just hard-code the script link in the page? Or is there a way to signal to the Ext.NET framework that it needs to load the script?
  2. #12
    Hello @plok77!

    If you don't want the resources to be allocated unless the chart is to be actually used, an alternative would be to use the frame approach to the loader.

    If you don't mind having the charts resources always loaded, manually adding them is one of the options. This shouldn't pose a mid-term issue as the link does not tend to change -- unless theme switching is a thing in the project in question.

    Similar to the alternative above, it is possible to just reference the base chart (or any chart-related component, in fact) from the OnGet() method in the model code, and the related resources will be included for you without any other "preload" or "unused code" in the initial page script. For instance:

    public void OnGet()
    {
        this.GetCmp<CartesianChart>(String.Empty);
    }
    The code above would make it so the chart resources are included although there's no chart in the page initially.

    Unfortunately you need to know what you may use in the page beforehand; this is not something specific to Ext.NET 7, but also in some circumstances even Ext.NET 5- couldn't tell it was supposed to load resources.

    You may though, add custom scripts to make the right includes if you have some code to do so, via the this.X().AddScript() method you can call from any direct event or method; but that'd be up to you to load the right resources and deal with potential side effects.

    Hope this helps!
    Fabrício Murta
    Developer & Support Expert
  3. #13
    Thanks, adding
    this.GetCmp<CartesianChart>(string.Empty);
    ensured that the chart script was loaded. The page will always contain at least one chart, so this seems like the best approach.

    However, have run into a problem with binding a chart to a store. I have the following Razor page that is returning component content to a parent page.

        public class BookingsByMonthModel : PageModel
        {
            private readonly IQueryHandler<GetBookingsByMonthQuery, List<BookingsByMonth>> _queryHandler;
            private readonly ISerializationService _serializationService;
            private const string StoreId = "bookingsByMonthStore";
    
            public BookingsByMonthModel(
                IQueryHandler<GetBookingsByMonthQuery, List<BookingsByMonth>> queryHandler,
                ISerializationService serializationService)
            {
                _queryHandler = queryHandler;
                _serializationService = serializationService;
            }
    
            public async Task<IActionResult> OnGetAsync()
            {
                var store = new Store
                {
                    Data = (await _queryHandler.HandleAsync(new GetBookingsByMonthQuery(2020)))
                                .Select(obj => new { Month = obj.MonthName, Bookings = obj.CountOfBookings })
                                .OfType<object>()
                                .ToList(),
                    StoreId = StoreId,
                    Fields = new List<DataField>
                    {
                        new DataField { Name = "month" },
                        new DataField { Name = "bookings" }
                    }
                };
    
                var panel = new Panel
                {
                    Layout = LayoutType.Column,
                    Items = 
                    {
                        new Panel
                        {
                            ColumnWidth = 0.6,
                            Items =
                            {
                                new CartesianChart
                                {
                                    Width = 600,
                                    Height = 300,
                                    Store = StoreId,
                                    Axes = new List<Axis>
                                    {
                                        new NumericAxis
                                        {
                                            Position = Position.Left,
                                            Fields = "bookings",
                                            Grid = true,
                                            Title = "Bookings",
                                            Minimum = 0
                                        },
                                        new CategoryAxis
                                        {
                                            Position = Position.Bottom,
                                            Fields = "month",
                                            Title = "Month"
                                        }
                                    },
                                    Series = new List<Series>
                                    {
                                        new BarSeries
                                        {
                                            Highlight = true,
                                            XField = "month",
                                            YField = "bookings",
                                            Tooltip = new SeriesTooltipModel
                                            {
                                                TrackMouse = true,
                                                Width = 140,
                                                Height = 28,
                                                Renderer = "function (toolTip, storeItem) { toolTip.setTitle(Ext.String.format('{0}: {1}', storeItem.get('month'), storeItem.get('bookings'))); }"
                                            }
                                        }
                                    }
                                }
                            }
                        },
                        new Panel
                        {
                            ColumnWidth = 0.4,
                            Items =
                            {
                                new GridPanel
                                {
                                    Width = 500,
                                    Height = 300,
                                    Frame = true,
                                    Store = StoreId,
                                    Columns = new List<Column>
                                    {
                                        new Column { Text = "Month", DataIndex = "month", Flex = 1 },
                                        new NumberColumn { Text = "Bookings", DataIndex = "bookings", Format = "0" }
                                    }
                                }
                            }
                        }
                    }
                };
    
                var serializedControls = new StringBuilder();
    
                using var writer = new StringWriter(serializedControls);
    
                _serializationService.Serialize(new object[] { store, panel } , writer);
    
                return Content(serializedControls.ToString(), "application/json", Encoding.UTF8);
            }
    The following JSON content is returned by the page:

    [{storeId:"bookingsByMonthStore",type:"store",fields:[{name:"month",type:"auto"},{name:"bookings",type:"auto"}],data:[{"month":"Jan","bookings":23},{"month":"Feb","bookings":34},{"month":"Mar","bookings":58},{"month":"Apr","bookings":45},{"month":"May","bookings":45},{"month":"Jun","bookings":1},{"month":"Jul","bookings":21},{"month":"Aug","bookings":16},{"month":"Sep","bookings":0},{"month":"Oct","bookings":1},{"month":"Nov","bookings":9},{"month":"Dec","bookings":4}]},{xtype:"panel",items:[{columnWidth:0.6,xtype:"panel",items:[{height:300,width:600,xtype:"cartesian",axes:[{fields:"bookings",grid:true,minimum:0,position:"left",title:"Bookings",type:"numeric"},{fields:"month",title:"Month",type:"category"}],series:[{highlight:true,tooltip:{height:28,width:140,xtype:"tooltip",trackMouse:true,renderer:function (toolTip, storeItem) { toolTip.setTitle(Ext.String.format('{0}: {1}', storeItem.get('month'), storeItem.get('bookings'))); }},type:"bar",xField:"month",yField:"bookings"}],store:"bookingsByMonthStore"}]},{columnWidth:0.4,xtype:"panel",items:[{frame:true,height:300,width:500,xtype:"gridpanel",columns:[{flex:1,xtype:"gridcolumn",dataIndex:"month",text:"Month"},{xtype:"numbercolumn",dataIndex:"bookings",text:"Bookings",format:"0"}],store:"bookingsByMonthStore"}]}],layout:"column"}]
    When the page is being rendered, I get the following error reported in the browser console:

    Cannot read property 'getData' of undefined
    I can see that this error is occurring because there's no store bound to the chart. If I change my Razor page code to create the store inline within the chart, it works. However that means that I can't use one store as the data source for both the chart and grid. The grid renders fine using the external store id, it's only the chart that won't render.

    How do you suggest I can configure my page so that both the chart and grid can share the same store and both can render successfully?

    Thanks

    Paul
  4. #14
    Hello again Paul!

    This really looks strange as per your description, you shouldn't be getting the store if you already have it, and the returned chart should just have a reference to the already existing store allocated for a grid panel in the page.

    The code snipped you shared looks right, I can't tell by that what's wrong with the whole logic.

    If you are stuck on that, please provide a code sample so we can reproduce and advise with the right approach to take. This should be possible if we understand the requirements right, so there's probably a small review to the page logic before it can work.

    In general, if you already have the store defined, you shouldn't return the full store again, nor define it again; all that's necessary is to create the chart with the ID of the right store (as it looks you already done), and ensure the store is really available whenever the chart can be requested (so you may need to pass a "signal" if the store is not loaded for the model to also create an instance for it client side.

    Looking forward to your follow-up!
    Fabrício Murta
    Developer & Support Expert
  5. #15
    Thanks, I was able to work around the problem by defining the store inline in the chart, and assigning it a store id so that it could be referenced by the grid. This solution works so I think I'll leave it at that.
  6. #16
    Hello again, Paul!

    Glad our last post helped you, and thanks for the feedback!
    Fabrício Murta
    Developer & Support Expert
Page 2 of 2 FirstFirst 12

Similar Threads

  1. [CLOSED] [#549] Rendering Partial View Error
    By LAEUser in forum 2.x Legacy Premium Help
    Replies: 9
    Last Post: Oct 01, 2014, 12:36 PM
  2. [CLOSED] Partial View not Rendering
    By RCM in forum 2.x Legacy Premium Help
    Replies: 1
    Last Post: Apr 01, 2013, 3:10 AM
  3. [CLOSED] DataGrid only rendering partial values ( version 2.2)
    By Pyropace in forum 2.x Legacy Premium Help
    Replies: 3
    Last Post: Mar 25, 2013, 3:03 PM
  4. ASP.NET MVC partial rendering
    By wdk in forum 1.x Help
    Replies: 16
    Last Post: Jul 20, 2012, 12:01 PM
  5. [CLOSED] Problem rendering partial view
    By T3rryChan in forum 2.x Legacy Premium Help
    Replies: 4
    Last Post: Jul 03, 2012, 9:22 PM

Posting Permissions