Multi Variables Mapping Path
Added by Alex Tumovsky about 2 months ago
Hello
Please advise how to better organize page routing (check inside the slot internalPathChanged) based on the principle of parsing a url with several parameters in the middle of the request.
For example: site.com/gallery/{1}/photo/{2}
Where: {1}, {2}, etc. are unknown transmitted parameters (both integer and text).
I managed to achieve this using the hierarchical pages method (internalPathMatches, internalPathNextPart), but the code looks very bad and I believe it can be done better.
maybe I don't fully understand how to do this according to the principle of hierarchy...
Has anyone encountered an optimal solution? Can you suggest a sensible solution for such page routing?
Maybe you can use something similar to the routing mechanism from oatpp (https://oatpp.io/docs/components/api-controller/#path-variables-mapping)
Thanks in advance
Replies (2)
RE: Multi Variables Mapping Path - Added by Matthias Van Ceulebroeck 22 days ago
Hello Alex,
I apologize for the belated reply. In this case, I would approach it with WMenu
, where WMenu::setInternalPathEnabled() will be of great help to you. You can create a WMenu
and call setInternalPathEnabled("gallery")
. That will let the menu know it should match an incoming path /gallery/{1}/photo/{2}
(omitting the origin). It will then look at the next part of the path /{1}/photo/{2}
.
Depending on whether the set of possible values of {1}
or {2}
is small or large, you may want to add them to the menu eagerly/lazily, or not at all beforehand. In the latter case, you may need to do some customization of WMenu::internalPathChanged().
I believe that with this approach as your basis, you should be able to write clean code that encapsulates, and decides on, a single level.
If you have any further questions, feel free to respond.
Best,
Matthias
RE: Multi Variables Mapping Path - Added by Alex Tumovsky 2 days ago
Tried to experiment.
The topic of normal routing is not disclosed in the documentation in an accessible way.
Wrote a small example implementing a menu and processing parameters from the address bar to select the necessary data, according to the selected gallery category and the selected photo.
Using the internal paths method, I was unable to correctly respond exclusively to the necessary URL paths.
When opening "/gallery/g1/photo/p3", the handler for the path "/gallery/g1" is also called at the same time, which may not be acceptable if you need to display only photo p3 from gallery g1. Together with the display of photo p3, app->internalPathMatches(basePath1_) is executed in the gallery widget. Since the path "/gallery/g1/photo/p3" does contain "/gallery/g1...." but it can contain anything further, but you only need to implement one parameter in this address. In general, I did not overcome this correctly.
In a real project, for address types either for previously known or for unknown parameters like "/qwe///new" I used a set of nested internalPathNextPart
if (app->internalPathMatches(basePath_ + "qwe")) {
std::string path2 = app->internalPathNextPart(basePath_ + "qwe/");
std::string path3 = "" ;
if(!path2.empty()){
path3 = app->internalPathNextPart(basePath_ + "qwe/" + path2 + '/');
}
...
"else if (internalPath == basePath_ + "qwe/" + path2 + "/" + path3)"
Which actually looks awkward and inflexible on more complex parameterized URLs (by this I mean unknown /*/ parts of the path, not GET parameters). In addition, you can see warnings about incorrect/not found paths in the logs.
In addition, if you get parts of dynamic paths from the database, then this method turns into a complete mess).
Another inconvenience is the creation of all possible menu items in advance.
menuGal->addItem(Wt::WString("Item 1"),
std::make_unique<OneParamWidget>(...), Wt::ContentLoading::Lazy);
If you initialize all possible galleries and photos in them in advance, then conditionally more than 10000..+ constructors of the class whose object is passed to this menu item will be called (for displaying later in WStackedWidget, for example, or something easier, but still). But any person is unlikely to want to view all photos from all categories at once. And therefore these resources will be wasted. In a real project, I used WAnchor more often for links, including in large menus, and already in widgets I searched for data by parameters from the URL separately.
That is, the approach with the pre-creation of all menu elements is suitable for a small and specific number of menu elements (the main menu or the application menu), but not for dynamic data from the database. Also, this is not critical for a small number of users for the application, but it is critical for a large flow of people to a public site.
To partially solve the problem and visually simplify the code, I created the "urlParamByMask(string, string)" method, similar to the "Configuration::matchEntryPoint" code.
In a simplified form, we get unknown parameters from the address bar by the URL mask, monitoring the correctness of the URL address for the specified mask.
In general, this solution allows you to control the address bar parameters of interest in any widget, but the question is that there may be many widgets that would like to know the address bar parameters. Roughly speaking, 100 widgets with the internalPathChanged() signal handler will probably cause a bunch of extra events and load. I would like to get the address bar parameters by mask without the extra work of analyzing it, since there will be a lot of repeating masks.
Maybe you could consider adding a standard similar method to the Wt API or come up with another option for conveniently getting data by mask from the address bar, as well as a more optimal method for working with them inside internalPathChanged() ?
Thank you very much for your response.
routing.cpp (9.11 KB) routing.cpp | Example routing |