Unplanned
Last Updated: 18 May 2020 09:03 by ADMIN
Paul Shearing
Created on: 15 May 2020 14:48
Category: Window
Type: Feature Request
1
Window "init" or "OnOpen" event

Can we please have an [Open] or [Init] or [OnVisible] event exposed for Blazor Windows?

There is a whole bunch of stuff that I need to do in a Window (e.g. custom modal editing form that needs a lot of temporary supporting data structures) and I am having to do the work in a method that that opens the window, before the Window is opened and passing many data structures to the Window as parameters (there could be more than 20 of these). This is messy.

It would be much simpler, neater and efficient to have the Window create these resources on the fly when the Window is made visible and to dispose of them when the window closes. I would then only need to pass a few essential parameters.

I'm guessing this is a new feature request because I cannot see any way of detecting, in the code for a Window, that it has just been opened (or am I missing something?).

Kind regards,

Paul

3 comments
ADMIN
Marin Bratanov
Posted on: 18 May 2020 09:03

Hello Paul,

The key thing here is that the window itself can never toggle the Visible field to true, so it could not possibly raise an event.

From a framework perspective - all that initialization belongs in the view model that hosts all components - the window, its content, the component that shows the window. What is the method that does that initialization and when is called depends on the view-model logic - for example a lifecycle method (such as OnParametersSet), a specific custom event (such as a button click) - the key thing being that this is outside of the Window component.

The way I would handle the described scenario is:

  • a component in the window content will house all that logic
  • it will use OnParametersSetAsync to fetch the data on demand (that's the initialization logic)
  • it will receive a parameter with the original edit model
  • it will store a copy of that model (e.g., through OnInitialized) for the Reset functionality - this can be an internal property of its own view-model, the parent does not need to know about it
  • if necessary, it will expose an event like MyModelChanged<MyModel> that will fire upon save click - this cal let you handle an event or even use two-way binding at the parent level

This satisfies all the needs:

  • initialization on demand
  • encapsulating the logic into one place
  • providing an event and even two-way binding to the parent

That said, when animations get implemented, they will probably be invoked through calling a method on the window instance, and that can probably allow for events. Here's the page where you can follow the animations implementation and I also added a note about a potential event there: https://feedback.telerik.com/blazor/1462921-animation-for-window

Regards,
Marin Bratanov
Progress Telerik

Progress is here for your business, like always. Read more about the measures we are taking to ensure business continuity and help fight the COVID-19 pandemic.
Our thoughts here at Progress are with those affected by the outbreak.
Paul Shearing
Posted on: 16 May 2020 13:37

Thanks, Marin,

The OnParametersSetAsync route looks promising as a workaround. I'll let you know how I get on.

I still think that an OnWindowOpen or OnWindowVisible event is a neater way to perform initialisation that is private to a window rather than doing it all in the routine that sets the window visibility. It isn't so much an efficiency issue (although it might typically reduce the number of parameters that need to be passed), more to do with cleaner modular code and better code clarity/brevity and its effect on software maintenance. With this proposed option, all of the local initialisation for a Window is done in the window's OnWindowOpen code not "outside" - makes sense and keeps the invoking code simpler.

Here is a (real) example. I have a Window that is a complex modal edit form. It contains a lot of business logic associated with more than forty separate editable fields. Validation for this form is particularly involved and runs along the lines: "well, because you selected this item in that editable field, all subsequent validation is handled differently". Consequently, there is a lot of validation C# code and this requires supporting data structures (containing more than 100 data fields in sundry database tables) that would best be initialised locally rather than being passed as parameters.

An example: I want a bail-out [Reset] button so that the user can, if necessary, revert all fields instantly to their original values and start again. Probably the simplest solution is to keep a copy of the editable record when the Window opens. Currently, I would have to pass two copies of the editable record as separate parameters to the Window - one for editing, and a copy to allow the revert to original values feature. (Or I could create a Class that that has two copies of a record and pass that as a single parameter but, again, that's messy, having to create special objects to circumvent the issue). I would much prefer to pass a record to be edited as a Window parameter and when the Window is made visible make a local copy of it. This seems to me to be the logical place to do it. Occam's Razor, as ever, rules supreme: the simplest solution is usually the best.

Anyway, I rest my case m'lud, and leave this for your consideration. For now, I will try the OnParametersSetAsync option.

Thanks for your swift reply Marin.

Kind regards,

Paul

 

ADMIN
Marin Bratanov
Posted on: 15 May 2020 15:12

Hi Paul,

To make the window visible, you always need to toggle the variable that controls that, so the place to raise up necessary info is that particular piece of code. I am not sure I follow how copying the application code from one place to another will make the Window component better - in all cases you'd probably put all the logic in a method that you will call when needed.

Another approach you can consider is using the OnParametersSetAsync event of a component that you put in the window - that's the common way to load data on demand in Blazor. Here's a mockup of that:

 

<TelerikWindow @bind-Visible="@isWndVisible">
    <WindowContent>
        <MyWindowContentComponent ParentTime="@DateTime.Now" />
    </WindowContent>
    <WindowTitle>Load on demand example</WindowTitle>
</TelerikWindow>

<TelerikButton OnClick="@( () => isWndVisible = !isWndVisible )">Toggle the window</TelerikButton>

@code{
    bool isWndVisible { get; set; }
}

 

 

and in the MyWindowContentComponent component:

 

@* of course, this is a bit simplistic but I trust it showcases the concept *@

@if (string.IsNullOrEmpty(dataLoadedOnDemand))
{
    <div>please wait...loading data</div>
}
else
{
    <div>
        The time at which the parent initialized this component is:
        @ParentTime.Millisecond

        <br />

        New data loaded when the window was made visible:
        @dataLoadedOnDemand
    </div>
}

@code {
    [Parameter] public DateTime ParentTime { get; set; }

    string dataLoadedOnDemand { get; set; }

    protected override async Task OnParametersSetAsync()
    {
        await Task.Delay(500); // simulate database operation
        dataLoadedOnDemand = DateTime.Now.Millisecond.ToString();
    }
}

 

For closing, we already have an event - VisibleChanged: https://docs.telerik.com/blazor-ui/components/window/events#visiblechanged

 

With that in mind, would you need a specific event for showing the window, considering that the VIsible parameter uses two-way binding and the corresponding <Parameter>Changed event already fires when the Window changes the visibility through its built-in [x] button (not included in the sample above), and the Window itself does not have a facility to show itself, so it is up to the app to toggle the flag to true?

Looking forward to your thoughts.

Regards,
Marin Bratanov
Progress Telerik

Progress is here for your business, like always. Read more about the measures we are taking to ensure business continuity and help fight the COVID-19 pandemic.
Our thoughts here at Progress are with those affected by the outbreak.