How to close a page in Xamarin Prism? - xamarin

I have page A and with a button, I go to page B
Now I want to close page B and "page A" appear
(But I don't want to call her again, since the page To make assessments if there is internet, ping the Server, etc. and I don't want to make these checks again.
That is why I want page A to appear once I have closed page B
(As if it were a kind of PopUp (But I don't want to use PopUp because of the type of page and data on page B)
Thank you.

If you go to PageB from PageA with:
NavigationService.NavigateAsync("PageB");
Then you can go back with :
NavigationService.GoBackAsync();
If you go to PageB from PageA with Model style(like PopUp as you mentioned in the question):
NavigationService.NavigateAsync("PageB", useModalNavigation: true);
You can use below codes to go back:
NavigationService.GoBackAsync(useModalNavigation: true);
But I don't want to call her again
To achieve that, you can make the button in Page1 not visible after Page1 appear again.

Related

Xamarin Shell: Redirect to different page and remove current page from nav stack

I imagine this is pretty straightforward, but I'm struggling to make sense of how to do it via the documentation...
I've got a tab page, that is opened from a flyout item.
The tabs for this page are dynamically loaded from saved data in the code behind, and all works exactly as expected.
However, in the scenario when there is no saved data (and thus, no tabs) I want to redirect the user to a different page, and crucially, not be able to navigate back to this tab page (but allow going back to the page they were initially on BEFORE they navigated to the tabbed page)
I've got a method in initalize for the tabbed page that, if it doesn't have any saved data, attempts to do this. I started with:
Shell.Current.Navigation.PopAsync();
Shell.Current.GoToAsync(nameof(AddNewDataPage));
which navigated to the add page, but pressing the back button just resulted in the add page being shown again, over and over.
I then tried:
Shell.Current.Navigation.PopToRootAsync();
Shell.Current.GoToAsync(nameof(AddNewDataPage));
which did the same.
So next I went with trying to navigate backwards:
Shell.Current.GoToAsync("../" + nameof(AddNewDataPage));
which showed the right page again, but now the back button doesn't work
Next, I went with trying an absolute route:
Shell.Current.GoToAsync("//HomePage/" + nameof(AddNewDataPage));
which worked... sort of.
The first time the user clicks the flyout for the tabbed page, it all works great. back button takes you to the home page etc... but the second and subsequent times the user clicked the flyout, they navigate to the tabbed page and my LoadData method isn't called.
I assumed this is because the tabbed page is still loaded, so I added:
protected override void OnAppearing()
{
LoadData();
}
Now, when the user clicks the flyout for the second and subsequent times, they navigate to the HomePage page instead of the AddNewDataPage page (an improvement, I guess?)
So, now I'm at a loss.. it seems like this should be really simple, but I can't figure it out.
You can try this.
//route The route hierarchy will be searched for the specified route, upwards from the current position. The matching page will replace the navigation stack.
https://learn.microsoft.com/nl-nl/xamarin/xamarin-forms/app-fundamentals/shell/navigation?WT.mc_id=friends-0000-jamont#relative-routes
await Shell.Current.GoToAsync($"//{nameof(AddNewDataPage)}");
https://www.youtube.com/watch?v=ylbgWHB_gMI&t=703s&ab_channel=JamesMontemagno
An explanation about relative routes.
May I don't understand your problem clearly. But I created a simple with the flyout shell app.
At first, it seems that the construction method of the content page will jut call once which the page shows first time. So I put the following code into it. Such as:
public ItemsPage()
{
InitializeComponent();
BindingContext = _viewModel = new ItemsViewModel();
Shell.Current.Navigation.PopAsync();
Shell.Current.GoToAsync(nameof(NewItemPage));
}
And then when the app got into the ItemsPage first time, it will get into the NewItemPage. User can add new item here. After that, when I clicked the back button, I will get into the ItemsPage back without it's construction method called. So you can't add the LoadData(); in it.
You can put it into the OnAppearing method. Such as:
protected override void OnAppearing()
{
//LoadData();
if (_viewModel.Items.Count < 8)
{
Shell.Current.Navigation.PopAsync();
Shell.Current.GoToAsync(nameof(NewItemPage));
// then add two item in the NewItemPage
}
else {
base.OnAppearing();
_viewModel.OnAppearing();
}
}
This will get the same effect as above. I also try to move the Shell.Current.Navigation.PopAsync();. The result is same. It will get back to the ItemsPage when you clicked the back button in the NewItemPage after you add two item.
which navigated to the add page, but pressing the back button just resulted in the add page being shown again, over and over.
You may just need a if() to judge the condition the app need to go to the AddNewDataPage with skipping the tab page.

Nativescript RadSideDrawer. I don't need back button

I'm trying to make a simple app with Playground (https://play.nativescript.org/). I'm using "RadSideDrawer" as a side menu. I'm satisfied. BUT ... every time I use "RadSideDrawer" and I move from one page to another, inside the "ActionBar" a button appears whose function is to bring back to the left page (please have a look at this page https://www.attivitacollaterali.it/appdata/services/apps/RadSideDrawer.html). I don't need and want this button. How can I make it not appear? Thank you.
Or, if not, at least update "RadSideDrawer". I mean that if the button goes back, for example to the "Search" page from the "Home" page, it should highlight/select "Search" in the "RadSideDrawer" menu and not leave "Home". Thanks again.
I think you're looking for the "clearHistory" option while navigating. When navigating to another page, you must do this:
this.router.navigate([url], { clearHistory: true });
Just make sure you're injecting RouterExtensions in your constructor:
constructor(private router: RouterExtensions) {}
That should clear the navigation stack when navigating, thus removing the button to go back to the previous page.
EDIT: If you want to retain the navigation stack, I believe you can also edit your action bar like this:
<ActionBar>
<NavigationButton visibility="collapsed"/>
</ActionBar>

Xamarin Prism Navigation in master detail cause reload of entire page on very navigation

When I navigate from my master to another detail view and y return to the original pages, this is loading everything like it was the first time, is this the expected behavior or what I am doing wrong?
this is what happening
from my login page y navigate to my master detail page with this:
await _navigationService.NavigateAsync("/MainMasterDetailPage/NavigationPage/PageA");
then from my master page I navigate to another page detail with this:
await _navigationService.NavigateAsync(target);
where target equals NavigationPage/PageB
then I go back to my first detail pages with this:
await _navigationService.NavigateAsync(target);
where target equals NavigationPage/PageA
The problem is that when PageA is showed for the second time, it was executing everything like it was the first time (Constructor for example) and I am loosing the state of the page.
How could I prevent this? it is a bug or is there a work around
This has been answered in the Prism GitHub issue you submitted. Please do not double post.
https://github.com/PrismLibrary/Prism/issues/968

Wicket (1.6) stateless form resets paging

I've already tried to find anything about that problem but I guess I either was not sure how to shortly describe the problem to find a solution or nobody else had that before which I can't think of. Maybe my thinking is wrong, too.
I have a stateless wicket 1.6 form with an ajax supporting panel (WebMarkupContainer with output id). The panel holds a dataview with paging navigator. The dataview itself is filled by a DataProvider.
The panel shows some entries from the database and below that is the navigator. by clicking any page on the navigator, the panel is refreshed (ajax) and shows content from that page. The page itself is not re-rendered by the browser.
When I now leave the page by navigating to another internal page (so basically when leaving the dataview-panel-page in any way) to open a detail page or so and then return to that dataview-page the navigator is resetted (because it's stateless I guess). The navigator can't remember which page to show and begins at the top of the first page again.
The question is: How can I solve this? I would like to i.ex. navigate to page 2 and then temporary leave the page for another internal page. When returning I want to be on page 2, focussed on the record where I clicked the link to "details" before. This also happens when I just open a new page in a new Browser tab.
Thank you!
Here's some code:
final WebMarkupContainer gamesPanel = new AjaxContainer("gamesPanel");
final DataView<Game> dataView =
new GameDataView("gameOverview", targetCurrencyModel, searchTextModel, gameFilterModel,
new GameDataProvider(searchTextModel, gameFilterModel, targetCurrencyModel));
dataView.setItemsPerPage(ITEMS_PER_PAGE);
gamesPanel.add(dataView);
final XNPagingNavigator navigator = new XNPagingNavigator("navigator", dataView);
navigator.setOutputMarkupId(true);
add(navigator);
You guys can try what I mean: The page I'm talking about is http://www.xbox-now.de. Just navigate to page 2, then click on details and return to main page.
I think you might use History API to push a new state when you click on navigation bar. In the new URL for the state you can include a parameter that indicates the index of the current navigator page.
You can customize your AJAX link in order to perform this operations when user click on it.
For more details on History API see Updating address bar with new URL without hash or reloading the page
I solved this in the NoWicket framework by introducing a model aware page cache which reuses page instances when hashcode/equals matches in the page model. You can see the implementation in the GitHub repo, try this implementation of the IPageFactory wrapper as a starting point, but it is more code involved there, just check out the code, debug the example and navigate the code to understand it better in order to apply it to your application. See your use case in action by trying this data table example in the documentation website (which you can also debug locally): http://invesdwin.de/nowicket/ajaxdatatable
Try changing the paging index, navigate to a different page and navigate back to the data table example page. You will still see the paging index that you left there.
Thank you guys for your replies. I've done it now another way. Used the base code from here and modified it in some ways. Added some nice css AttributeModifiers to indicate the actual page:
item.add(new AttributeModifier("class", new PageLinkCssModel(pageable, pageIndex, "active")));
Then I modified some code to add or reset the page parameter, that it's 1) used only once and 2) keeps all the actual page parameters which were there before adding own ones. So I am just appending the page number now. This way I can keep my initially mount path like www.foo.bar/path/path/path. Complete URL would now look like: www.foo.bar/path/path?page=123.
To pass my entered page (i.e. page=5) to the data provider I just had to override the providers iterator. It should start with the page I entered. Due to the ugly generated navigator URLs (which are extremly bad for SEO) I now have nice looking urls which are working independently what wasn't possible before. And that's also the reason why I could not get back to the correct page. The navigator URL was not lookup-able by wicket.
new DataView<GamePrice>("gamePriceOverview", new GameDetailDataProvider(gameId, targetRegion) {
#Override
public Iterator<GamePrice> iterator(final long first, final long count) {
return super.iterator(ITEMS_PER_PAGE * getCurrentPage(), count);
}
getCurrentPage() comes from the base template and gets the actual page number entered (if one is entered):
public long getCurrentPage() {
// -1 weil zero based
return getRequest().getQueryParameters().getParameterValue("page").toString() != null
? (getRequest().getQueryParameters().getParameterValue("page").toLong() - 1)
: 0;
}
So instead of having ugly SEO-unfriendly URLs which are also not compatible to work independant (directly enter the generated url) I now have the same URL I expect with an added page-parameter.
URL now would looks like:
http://localhost:8080/game/4249/de/doom-preorder?page=2
URL before was:
localhost:8080/game/4249/DE/doom-preorder?0-1.ILinkListener-gamePrices-navigator-navigation-2-pageLink
If I now go back from the detail page to the main index with active "Bookmarkable-Navigator", I correctly come back to the page and position where I left it (because of bookmarkable page links).
That's how I achieved this problem with a nice bonus: User- and SEO-friendly URLs.

Hot to implement grails server-side-triggered dialog, or how to break out of update region after AJAX call

In grails, I use the mechanism below in order to implement what I'd call a conditional server-side-triggered dialog: When a form is submitted, data must first be processed by a controller. Based on the outcome, there must either be a) a modal Yes/No confirmation in front of the "old" screen or b) a redirect to a new controller/view replacing the "old" screen (no confirmation required).
So here's my current approach:
In the originating view, I have a <g:formRemote name="requestForm" url="[controller:'test', action:'testRequest']", update:"dummyRegion"> and a
<span id="dummyRegion"> which is hidden by CSS
When submitting the form, the test controller checks if a confirmation is necessary and if so, renders a template with a yui-based dialog including Yes No buttons in front of the old screen (which works fine because the dialog "comes from" the dummyRegion, not overwriting the page). When Yes is pressed, the right other controller & action is called and the old screen is replaced, if No is pressed, the dialog is cancelled and the "old" screen is shown again without the dialog. Works well until here.
When submitting the form and test controller sees that NO confirmation is necessary, I would usually directly redirect to the right other controller & action. But the problem is that the corresponding view of that controller does not appear because it is rendered in the invisble dummyRegion as well. So I currently use a GSP template including a javascript redirect which I render instead. However a javascript redirect is often not allowed by the browser and I think it's not a clean solution.
So (finally ;-) my question is: How do I get a controller redirect to cause the corresponding view to "break out" of my AJAX dummyRegion, replacing the whole screen again?
Or: Do you have a better approach for what I have in mind? But please note that I cannot check on the client side whether the confirmation is necessary, there needs to be a server call! Also I'd like to avoid that the whole page has to be refreshed just for the confirmation dialog to pop up (which would also be possible without AJAX).
Thanks for any hints!
I know, it's not an "integrated" solution, but have you considered to do this "manually" with some JS library of your choice (my personal choice would be jQuery, but any other of the established libraries should do the trick)? This way you wouldn't depend on any update "region", but could do whatever you want (such as updating any DOM element) in the response handler of the AJAX request.
Just a thought. My personal experience is that the "built-in" AJAX/JS stuff in Grails often lacks some flexibility and I've always been better off just doing everything in plain jQuery.
This sounds like a good use-case for using web flows. If you want to show Form A, do some kind of check, and then either move onto NextScreen or show a Dialog that later redirects to NextScreen, then you could accomplish this with a flow:
def shoppingCartFlow = {
showFormA {
on("submit") {
if(needToShowDialog())return
}.to "showNextScreen"
on("return").to "showDialog"
}
showDialog {
on("submit").to "showNextScreen"
}
showNextScreen {
redirect(controller:"nextController", action:"nextAction")
}
}
Then you create a showDialog.gsp that pops up the dialog.
--EDIT--
But, you want an Ajax response to the first form submit, which WebFlow does not support. This tutorial, though, will teach you how to Ajaxify your web flow.

Resources