User is creating a record with a WebDialog. Error with record creation shows a message with a #Hashtag link in it to call-back to the server and navigate if desired. User clicks #Hashtag link and Session.HashtagChanged has been raised.
Now, inside of Session.HashtagChanged, I need to navigate the user to a new page. Works great, except the dialog is still visible. I need to close the dialog, but I do not have a reference inside of Session.HashtagChanged.
For WebPages, there’s Session.PageAt and that whole system…
Am I overlooking a way to find this WebDialog instance (or any/all open dialogs for that matter) globally from Session.HashtagChanged?
It doesn’t appear that my WebDialog is part of the Controls iterable when it’s created in code. I’ve modified the sample project to illustrate the situation I’ve gotten myself into. There are much better ways to implement a logout than this example, it’s just illustrative of the problem.
My use case is the same in which there are different pages and a dynamically created WebDialog. The link is sent to a HTMLViewer, so it’s a one-way communication that comes back via the HashtagChanged event.
It seems to be emerging that a key factor of my problem is that the WebDialog is created in code. By choice I haven’t maintained a reference to it since it’s a self-closing dialog. I might just live with it because it’s such a rare scenario, but I’m also wondering if there’s a design factor of the framework we could improve upon.
When you create it this way and you don’t attach it to the page it’s running on, you’re effectively creating a global dialog, just like it would in a desktop app if you showed a window from another one.
Right, but on Desktop I’d be able to re-acquire the floating window through App.WindowAt. These dialogs have no way of being re-acquired.
I can work a system within the limitations here, but it feels like it might be worth a ticket? Not only would it bring platform consistency to be able to re-acquire the WebDialogs, it would simplify the solution here.
I suppose that Xojo could keep an array of WebViews and you could iterate through them, but it’d just be another place for the framework to leak objects unless it was done as an array of WeakRefs and converted to objects when asked for.
It’s still not clear to me why you’re just not keeping a reference to the dialog on your page and then closing it yourself in this very special situation.
The trick here is that there are other controls that inherit from WebView that I don’t thing should be included… specifically anything that can “contain” other controls. WebPagePanel, WebTabPanel and iirc even WebRectangle.
BTW, if you want your dialog to appear in the control list, you just need to add it to its parent using the AddControl method.
The dialog is self-contained. It closes itself when you create the record, or you close it to cancel creation of the record. I have no need to maintain a reference to it since it will always close itself.
Except in this situation. I’m just pondering whether there is an issue, I guess. If there is an issue, is it that the WebDialog didn’t close when the page was navigated, or is it that I can’t reacquire a reference to this WebDialog when it’s created in his manner?
In my opinion, we should at least be able to iterate both WebPages and WebDialogs. We already can with WebPages, but this use case seems to have uncovered a path in which a WebDialog can become abandoned.
Did I misunderstand the use case of WebDialogs? I use them like transient pages which is why I’m frequent to not having a reference once they are .Shown.
Thank you! This has provided a solution for this problem that I don’t hate. The WebDialog created in code ends up in the Controls iterable and I can detect and close it during the HashtagChanged event.
@Ricardo_Cruz what are your thoughts on my usage of WebDialogs?
Personally I always keep a reference to my WebDialogs and I’m honestly surprised that you’re not having trouble with them disappearing as soon as they go out of scope.
Keeping a reference, as Greg said, would be the best option. But if you really want to make it self-contained, I’d probably add a CSS class and use some JavaScript to close them all.
Still, it would be great to be able to set the Page property on WebDialog instances created in code. Please feel free to add a Feature Request if you think that would be helpful for you.
I’ve just checked it and, as soon as you create the instance, the control will be added to the Session control map.
Maybe use a simple Class Interface, implement it to the WebDialog add a Close method to the interface (maybe call it Closeable)
On app class hold a array refrence to it in WebDialog.Closing make sure to remove the reference.
In WebDialog.Opening add a reference rthe app class array of the interface type.
Now you can call a method on the App class for example:
App.Closeables(-1) As Closeable
App.CloseAllDialogs()
If Closeables.count <= 0 Then return
For each obj As Closeable in Closeables
obj.Close
End For
I took Greg’s recommendation and add the WebDialog I create in code to the WebPage with the AddControl method. In the HashtagChanged event, before closing the current page I check all children and their children for WebDialogs to close.
Sub HashtagChanged(name As String, data As String) Handles HashtagChanged
#pragma unused data
// Close any open dialogs
var pg as WebPage = self.CurrentPage
if pg <> nil then pg.CloseAllDialogs
select case name
case "ActivityLog"
var oView as new pgActivityLog
oView.Show
self.Hashtag = ""
case "Logout"
// Logout will close all pages
self.Logout
self.Hashtag = ""
case "Settings/StoreBuilder"
var oSettings as new pgSettings
oSettings.Show
self.Hashtag = ""
case "Settings/Stripe"
var oSettings as new pgSettings
oSettings.ShowStripe
self.Hashtag = ""
end select
End Sub
Public Sub CloseAllDialogs(extends vw as WebView)
for each ctl as WebControl in vw.Controls
if ctl isa WebDialog then
// Check for WebDialogs first
WebDialog(ctl).Close
elseif ctl isa WebView then
// Check for other types of WebViews that we need to recurse
WebView(ctl).CloseAllDialogs
end
next ctl
End Sub
I’m sure there was a reason we did that somewhere along the way, but I can’t remember. If it was me, hopefully my checkin message wasn’t something like “fixed this”