WNavigationBar::removeWidget unexpected behaviour
Added by Christian Meyer about 2 years ago
Hi, it's me again =D
I am currently building a mixed Application, with parts that are publicly accessible and some other part only for registered Users
There is a WNavigationBar
at the top with some items, and inside the useraccess item, the login form is placed
within a WStackedWidget
.
On Login, the Auth::AuthWidget
is removed fine from the container and placed into the WNavigationBar
On Logout, I would like to move it back into the container, but removeWidget
always returns nullptr
here is some code:
getAuthSession()->login().changed().connect([this](){
if(this->getAuthSession()->login().loggedIn())
{
// Login: Move Logout to Navbar
auto authPtr = this->sCon->removeWidget(this->authWidget);
this->authWidget = authPtr.get();
this->navbar->addWidget(std::move(authPtr),Wt::AlignmentFlag::Right);
this->sCon->clear();
this->sCon->addNew<Wt::WText>("Login Success");
}
else
{
// Logout: clear all, then Add Login Widget
auto authPtr = this->navbar->removeWidget(this->authWidget); // returns nullptr
this->sCon->clear();
this->authWidget =
this->sCon->addWidget(std::move(authPtr)); // understandable Segfault, moving nullptr
}
});
What I found was that WNavigationBar
is inheriting from WTemplate
and there the usual function seems to be overridden to return a bound widget.
After looking through the code of WNavigationBar
it seems like something like this should work:
std::unique_ptr<WWidget>
WNavigationBar::removeWidget(WWidget *widget)
{
auto remWidget = WTemplate::removeWidget(widget);
if(remWidget)
return std::move(remWidget);
WContainerWidget *contents = resolve<WContainerWidget *>("contents");
return contents->removeWidget(widget);
}
Is my assumption correct?
If so, please feel free to add this into the Library.
Best Regards
Christian
Replies (1)
RE: WNavigationBar::removeWidget unexpected behaviour - Added by Christian Meyer about 2 years ago
It seems I was almost correct...
I missed the wrap inside NavBar
this does work now in my code:
getAuthSession()->login().changed().connect([this](){
// keep AuthWidget if Problem with Registration (edgecase)
if(this->getAuthSession()->login().state() == Wt::Auth::LoginState::Disabled)
return;
if(this->getAuthSession()->login().loggedIn())
{
// Login: Move Logout to Navbar
auto authPtr = this->sCon->removeWidget(this->authWidget);
this->authWidget = authPtr.get();
this->navbar->addWidget(std::move(authPtr),Wt::AlignmentFlag::Right);
this->sCon->clear();
this->sCon->addNew<Wt::WText>("Login Success"); // Or Setup Access content
}
else
{
// Logout: clear all, then Add Login Widget
auto contents = this->navbar->resolve<Wt::WContainerWidget *>("contents");
std::unique_ptr<Wt::Auth::AuthWidget> authPtr;
for(auto wrap : contents->children())
{
authPtr = wrap->removeWidget(this->authWidget);
if(authPtr)
break;
}
this->sCon->clear(); // remove access content
if(authPtr)
this->sCon->addWidget(std::move(authPtr));
}
});
So then this should be dropin ready for Wt:
std::unique_ptr<WWidget>
WNavigationBar::removeWidget(WWidget *widget)
{
auto remWidget = WTemplate::removeWidget(widget);
if(remWidget)
return std::move(remWidget);
WContainerWidget *contents = resolve<WContainerWidget *>("contents");
for(auto wrap : contents->children())
{
remWidget = wrap->removeWidget(this->authWidget);
if(remWidget)
break;
}
return std::move(remWidget);
}
Cheers
Christian