How does Wt navigation actually work

Added by Alex Gouws about 1 month ago

I'm new to Wt so I apologise if this is a bit of a dumb question. The page navigation is a little confusing to me.
I see from the Wt Widget Gallery navigation page that the button sets the page to the internal path once clicked:

button->setLink(Wt::WLink(Wt::LinkType::InternalPath, "/navigation/anchor"));

But what exactly is "/navigation/anchor". Is it a class? Is "anchor" an anchor inside a class named "navigation"?

For example. Say we have a basic log in screen as the home page. Once the user authenticates, the next page should be loaded, say a dashboard.
What exactly would the dashboard be? Would it just be a class with it's own widgets defined? Would we simply call it with an instance of that class? What happens to the widgets on the previous page? Would they be destroyed? Or would we load the dashboard in some other way?

In normal web development each webpage is an actual file as far as my limited web dev knowledge reaches. Each with it's own functions and 'widgets'. Is this the same concept for Wt?
Any links to some resources or any examples would be appreciated!


Replies (7)

RE: How does Wt navigation actually work - Added by lm at about 1 month ago

Welcome to Wt!

Alex Gouws wrote:

But what exactly is "/navigation/anchor".

As far as I understand, it's simply a string called the Internal Path. It doesn't correspond to any filesystem nor program reality except inasmuch as you create such a reality.

When a user first visits your site, you can inspect this path and render your page accordingly (see the "URLs and Internal Paths" section in https://www.webtoolkit.eu/wt/doc/reference/html/classWt_1_1WApplication.html). Also, as the user navigates your site, you can adjust the internal path. What is the point of adjusting the path? 1) It gives the user a different site than your root URL to use as a bookmark (this is useful if your web application responds to the initial internal path), and 2) it gives them a hint as to where they are in your web application.

What exactly would the dashboard be? Would it just be a class with it's own widgets defined?

The dashboard would likely be a custom class extending Wt::WContainerWidget filled with widgets you put in there.

Would we simply call it with an instance of that class?

Call what with an instance of that class? You would instantiate your custom class (which extends Wt::WContainerWidget) then put it into the widget hierarchy somehow. The widget hierarchy conveniently has a fixed root: Wt::WApplication::root to which you will be adding widgets: https://www.webtoolkit.eu/wt/doc/reference/html/classWt_1_1WApplication.html#a485af3ad2b758931edbde77fcf529981

What happens to the widgets on the previous page?

That's up to you. The easiest way to proceed is not to delete the widgets, but simply hide them. For instance, perhaps in the root, you put a Wt::WStackedWidget (https://www.webtoolkit.eu/wt/doc/reference/html/classWt_1_1WStackedWidget.html) that has two widgets inside it: struct my_auth_widget and a struct my_homepage_widget. When the application loads up, you

my_auth_widget auth {stacked_widget->addNew(auth_service)};
my_homepage_widget homepage{stacked_widget->addNew(homepage_service)};
stacked_widget->setCurrentWidget(my_auth_widget);
And when authentication is done, you
stacked_widget->setCurrentWidget(my_homepage_widget);
In this case, the authentication widget will not be destroyed, but will disappear from sight when it's not needed. (If you want it destroyed, remove it from the Wt::WStackedWidget.)

In normal web development each webpage is an actual file as far as my limited web dev knowledge reaches. Each with it's own functions and 'widgets'. Is this the same concept for Wt?

No. WT is a single-page application framework (https://en.wikipedia.org/wiki/Single-page_application). Your whole application will act like a single, dynamic, reactive webpage. You can create the appearance of moving to different "pages" using internal path (we started by talking about that), but since you are writing a single-page application, there will be no loading time when switching pages (or close to it).

RE: How does Wt navigation actually work - Added by Alex Gouws about 1 month ago

Great thank you! That's making a lot more sense to me now!

I have another simple question relating to the creation of Wt objects.
I'm trying to create some widgets and add them to the WStackedWidget just as a test but it's not working as I expect.

@auto text = cpp14::make_unique<Wt::WText>("Hello World!");
auto button = cpp14::make_unique<Wt::WPushButton>("Click Me!");
auto containerStack = cpp14::make_unique<Wt::WStackedWidget>();
containerStack->addWidget(std::unique_ptr<Wt::WText>(button));
containerStack->addWidget(std::unique_ptr<Wt::WText>(text));
root()->addWidget(std::unique_ptr<WStackedWidget>(containerStack));@

I'm a bit confused. When should std::unique_ptr and std::make_unique be used when creating or adding widgets to other widgets?
The addWidget function expects a "std::unique_ptr< WWidget >widget" which is what I have provided is it not? Some links for more info on this would be great!

Sorry if this is a simple question but Wt is boggling my mind a bit.

Thank you.

RE: How does Wt navigation actually work - Added by lm at about 1 month ago

Alex Gouws wrote:

Great thank you! That's making a lot more sense to me now!

Good. It was not so long ago that I was in your position grappling with the basic design of Wt. Little more is required before you are properly up and running with Wt.

I'm trying to create some widgets and add them to the WStackedWidget just as a test but it's not working as I expect.

1 auto text = cpp14::make_unique<Wt::WText>("Hello World!");
2 auto button = cpp14::make_unique<Wt::WPushButton>("Click Me!");
3 auto containerStack = cpp14::make_unique<Wt::WStackedWidget>();
4 containerStack->addWidget(std::unique_ptr<Wt::WText>(button));
5 containerStack->addWidget(std::unique_ptr<Wt::WText>(text));
6 root()->addWidget(std::unique_ptr<WStackedWidget>(containerStack));

I'm a bit confused. When should std::unique_ptr and std::make_unique be used when creating or adding widgets to other widgets?
The addWidget function expects a "std::unique_ptr< WWidget >widget" which is what I have provided is it not? Some links for more info on this would be great!

Sorry if this is a simple question but Wt is boggling my mind a bit.

This is not a Wt question but a C++ question. Yes, Wt requires a std::unique_ptr<A>, but it doesn't look like you're passing on. In fact, your problem is a good deal before what Wt requires. Get in the habit of reading (and understanding to some degree) compiler errors! The compiler knows a lot about your code and can point you right to where you went wrong.

I numbered your code lines above to facilitate the following discussion.

Lines 1, 2, and 3 look fine, but I think you would do better if you didn't use auto (more on this later).

Lines 4, 5, and 6 are nonsensical. You're creating a unique_ptr from an existing unique_ptr (by copy) which is not allowed. If you would rewrite the first three lines without auto, I think the error would become clearer:

cpp14::unique_ptr<Wt::WText> text = cpp14::make_unique<Wt::WText>("Hello World!");
...
As you can see, text is a unique_ptr. On line 4, you need only move this unique_ptr into the containerStack:
containerStack->addWidget(std::move(text));
(If you're not using a c++14 compiler, 1) you probably won't be able to do this, and 2) go get a c++14 compiler; they're cheap.)

You may want to keep a pointer to your Wt::WText so that you can manage it later (remove it from the container, change the text, etc.) so that the whole code example for the Wt::WText will look like this:

auto text {cpp14::make_unique<Wt::WText>("Hello, World!")};
Wt::WText * my_text_ptr {text.get()};
containerStack->addWidget(std::move(text));
...
my_text_ptr->setText("Bye, World!");

This can be shortened considerably by using addNew:

Wt::WText * my_text_ptr {containerStack->addNew<Wt::WText>("Hello, World!")};
...
my_text_ptr->setText("Bye, World!");
Happy Wting!

RE: How does Wt navigation actually work - Added by Alex Gouws about 1 month ago

Thanks a lot for your efforts and detailed answers and explanations. I appreciate someone taking the time to help out. I'm a CS student and I'm not too familiar with smart pointers yet (just touched on them), mostly raw pointers at this stage. But it does make more sense to me know to move the pointer into the container instead of copying it (at least I know why copying pointers is bad haha). I'm really keen to learn how to use Wt properly so I hope you don't mind me asking you a few more questions till I get the hang of it.

I've created a class to represent a page, let's call it dashboard (could be anything really) which extends Wt::WContainerWidget and I've placed some widgets in there just to test. Am I creating the widgets in the correct way here?

dashboard.h

class dashboard    : public WContainerWidget
{
public:
    dashboard();
    WPushButton *button;
    WText *text;

    ~dashboard();
};

dashboard.cpp

dashboard::dashboard()
{
    //is this implementation correct?
    button = this->addWidget(cpp14::make_unique<WPushButton>("Dashboard button"));
    text = this->addWidget(cpp14::make_unique<WText>("This is your dashboard."));
}

Will this be enough to display the widgets on screen when the class object is selected from the StackedContainer in main.cpp?

Following is how to correctly create the class object in the main.cpp and add it to the StackedContainer widget?
As its derived from WContainerWidget, the object would itself essentially be a widget correct? I tried an approach like this but it seems completely wrong:
containerStack->addWidget(cpp14::make_unique<dashboard>());

Another approach I tried is:

    std::unique_ptr<dashboard> myDash;
    containerStack->addWidget(std::move(myDash));

This too is not correct. It compiles but I get runtime exceptions. I can only imagine it has to do with incorrect pointer referencing.
What would the correct way be to add a (essentially Widget?) class to the container?

Thanks!

RE: How does Wt navigation actually work - Added by Alex Gouws about 1 month ago

I think I figured this out. I tried

dashboard *dash{ containerStack->addNew<dashboard>() };

which seems to work. The page displays the widgets from the dashboard class.
Question is: Is this the correct way to do this (adding a class object to a container)? Or is there some other better way?

RE: How does Wt navigation actually work - Added by Alex Gouws about 1 month ago

I can't seem to find where to edit a post so I'll just make another reply.
I realize this thread may have gone a bit out of scope from my original question and the thread title after my follow up questions.

If I have more questions I will create a new thread, but your answers and opinions on the ones posted above would still be greatly appreciated here.
Thanks!

RE: How does Wt navigation actually work - Added by lm at about 1 month ago

dashboard *dash{ containerStack->addNew<dashboard>() };
Exactly. By the way, in case you need to make unique_ptr@s anymore, you can probably just do @std::make_unique<A> instead of cpp14::make_unique<A> (it appears that you have a C++14 compiler).

It looks like you're in a good way. Feel free to ask other questions in a new thread. Cheers!

(1-7/7)