I'm implementing a small project with only two UIs.
1-The first UI is called Home which contains paginated users list the home component.
2-The second UI is called user details which contains user profile the user-details component
3- and of course the app component which contains the tool bar and router-outlet
let us suppose the following scenario
I'm in the home UI and in the second page of the paginated users list and I clicked on one of the users item then the user-details UI appeard and I'm now in the second UI and I now I want to navigate back to the home but when doing so the home UI is recreated and become the first page of the users list instead of the second page where we left it because this is my code of the back button
<img
routerLink = "/home" style="cursor: pointer;"
width="40"
alt="Angular Logo"
/>
<span routerLink = "/home" style="cursor: pointer;">Users</span>
my question is:
is there is any way to implement it in such a way it doesn't recreate the home page i.e. implement the correct behavior of back button?
There's a couple ways that you can approach this.
If you're using a pagination library (such as ngx-pagination), then hopefully the pagination component takes an input for the current page. You'd then need to keep track of that page either through a service or in persistent storage.
Whenever you route back to the Home UI, get the page that you were on and load that back into the pagination component.
Another way can be to use router parameters. By modifying your urls a bit, they can take on the following form:
/home/1
/home/2
/home/3
Clicking on a user in page 2 can give the url: /home/2/user-id (just an example)
The path for your home component can look like:
const routes: Routes = [
{ path: "home/:pageNumber", component: HomeComponent }
];
Upon loading the home component, you can get the get the router parameter as follows (I'm using the Router method but you can parse the URL manually as well):
export class HomeComponent implements OnInit {
constructor(private router: Router) {
const pageNumber = this.router.navigationExtras.params['pageNumber'];
}
}
You can then load this page number into your pagination component. Using this method doesn't require you to keep track of the previous pages.
There are probably better methods to do this, but this is just some suggestions :)
Related
In my Angular 8 project, I currently have a landing page (template-table.component) that shows a list of items that can be filtered and sorted. The filter and sort are added to the route queryParams(ex: "/template-table?name=another&type=Type%201"). If you select an item in the list, you will be taken to another route (that has the template-details.component) that has more details on that item. This details page will have a 'back to list' button that should take the user back to their previous list page.
Since I want the user to be taken back to the list with the filter params they were previously using, I can't simply go to the route of that component, instead I want to go back in history (like how the browser back button works). So, how do I set an element to link to what the browser back button would be link to?
So, this is the bare minimum of my template-detail.component.html:
<h1>template-details works!</h1>
<div>{{template}}</div>
<div>{{id}}</div>
<div><a routerLink="/template-table/">Return to list page</a></div>
I think I also would like to check the route to see if it's the template-table component route with query params, and not an unrelated route. (So, the route would need to be like: "/template-table?params=xxx", and couldn't be "google.com". If the browser back button isn't related to the template-table, then it should go to "/template-table" without any params (or maybe my 404 page.)
The basic functionality that I'm wanting to achieve is for the user to be able to filter a list, go to another route with more info on a list item, and then return to the list with the same filters they previously added. If there would be a better way to do this than by trying to access the browser's back button, I'd love to hear about it.
Thank you for any assistance you can provide.
Arthurofos' suggestion to use the Location service seems to be relevant, as it can be used to navigate back to the view you were in prior to routing to a new component.
Of course, while there are very Javacsripty-ways to do these sort of things, it's always recommended to use Angular's libraries, if such an alternative exists.
In our case, it does, and it presents itself as the 'Location' service you can inject into your component.
import { Location } from '#angular/common';
#Component({
// Other component info
providers: [Location, {provide: LocationStrategy, useClass: PathLocationStrategy}]
})
export class TestComponent {
constructor(private location: Location, // Other constructor arguments) { }
public goBack() {
this.location.back()
}
}
https://alligator.io/angular/location-service/
Something like that should work:
routerLink="../"
But you can solve this problem in an elegant way thanks to the location of the library. Check out this post: enter link description here
I am using ASP.NET Core 2.0 and Visual Studio 2017.
I want to create a Razor partial view to display the menu of our application. The menu is created dynamically as each user will only have menu items for which they have the necessary permissions (so the menu will be different for each user).
The problem I'm having is persisting the menu in the Razor partial view. There is no PageModel code-behind in a Razor partial view, so the problem I'm having is that the menu disappears when you click onto another page. I've persisted the menu in session storage, but I can't figure out how to load the menu from session storage into the Razor partial view.
I've tried loading the session storage menu into ViewData but this is wiped out when you click on another page.
How do I persist data in my Razor partial views?
Instead of using partial view, consider using a view component.
public class MenuComponent : ViewComponent
{
SomeDependency userDetails;
public MenuComponent(SomeDependency userDetails)
{
//store this userDetails data to extract profile info in Invoke method
this.userDetails = userDetails;
}
public IViewComponentResult Invoke()
{
//check for logged in user profile here and return appropriate view
return View(viewName,ModelObjectForView);
}
}
1.Create required menu views
Create the appropriate views for displaying menu for each role or use
conditional rendering.
Please note view for view components will be looked in to
/Views/ControllerName/Components/ViewComponentName/ViewName.cshtml this
location instead of /Views/ControllerName/ViewName.cshtml.
2.Define Layout Page
Now, since you need to display menu for all the pages user navigates to, you
need to extract this view component in a layout page. Create a _Layout.cshthml
file and make sure views that need to show menu item uses this layout page.
In the _Layout.cshtml , you can now render the view component defined above by calling
#await Component.InvokeAsync(nameof(MenuComponent))
3.Using ViewComponent instead of PartialView
I am suggesting use of ViewComponent over PartialView in this case because
ViewComponent will allow you to have its own model (RoleDetails for user in
your case) in comparison to PartialView
where you will have to pass some child data from view model and hence will have
to keep that data in each of your view model. Otherwise , you can even use PartialView. The important thing here is layout page that will help you keep menu across all views presented to user.
I'm working on a personal project, it's a simple blog app using ReactJS. I have 1 screen for the entry list page, and 1 for the entry details page.
Now, I'm trying to follow the best practices, so I laid out my components as this:
Entry List Container: container component. Handles fetching entries retrieval and updating application state by dispatching redux actions.
Entry List: presentational component. Receives an Array of Entry objects and shows a list of them
Entry Details Container: container component. Handles more application state update logic, fetching, etc. Receives an Entry object
Entry Details: presentational component. Displays the entry.
Basically both containers renders their presentational counterpart.
Now, the problem is the navigation. In my App component I'm rendering a couple of Route components, one is rendering the EntryListContainer, and another one should render the EntryDetailContainer.
Problem is, how do I navigate from EntryList ?
My hierarchy is something like this:
EntryListContainer
EntryList
EntryRow -----> This contains a button to navigate.
EntryDetailsContainer
EntryPage
I suppose I could render a Link inside EntryRow, something like
<Link to={`${match.url}/{entry.id}`} />
But then I'd have to pass down the match object down from EntryListContainer to EntryList to `EntryRow, and it feels smelly.
How do I navigate properly?
I have a new product page with the url /product/0. When product is saved using a button, I want to show 'Saved Successfully' message and change url to /product/1024 without actually navigating to that page as this would cause GET requests for the product and other data on the page.
I tried the Navigation mixin, however both, the transitionTo and replaceWith actually cause componentWillReceiveProps and I can't figure out a way how to distinguish my case (when all data on the page is already relevant) from navigation between different products, when data has to be reloaded.
So basically I am looking for a way to just change the url with React Router.
In a SPA there's no navigating to another page, the history change could lead to a different route being rendered, but as per your example, the same route will be rendered, so the only thing that did happen is a state change of the props of the Route component.
So you need to check this state with the previous state in componentWillReceiveProps and see if you need to refetch the data.
I'm creating an image gallery that loads a specific image if it is specified in the route (else loads the first):
foo/photos/sports/2
Each thumbnail is wrapped in a link to cause the address to change (so users can link back to it directly):
<ul class="gallery-thumbnails">
<li ng-repeat="piece in gallery.pieces">
<a ng-href="/foo/photos/sports/{{$index+1}}">
<img ng-src="{{piece.img}}" />
</a>
</li>
</ul>
The problem is that it causes the whole view to be re-rendered instead of just the template binded to the changed scope param (scope.gallery.selected).
I can't find a way to cancel the view re-render (but I still want $routeParams to be updated).
I've seen solutions that listen for $locationChangeSuccess, but that doesn't work for my scenario.
One way to get close is to use get parameters instead, going to /foo/photos/sports?page={{$index+1}} and in that route (as an argument to "when") set reloadOnSearch: false. You can then update the $location.search (the get parameters) without the page reloading and trigger things on the changes.
// Using reloadOnSearch
.when('/foo/photos/sports', {
templateUrl: 'sports',
reloadOnSearch: false
});
// Changing the get parameters (search part of url)
$location.search({'page': 1});
Apart from that I don't think you can do it with the default angular router. It always reloads all controllers on a routechange. You could however switch to another router such as ui-router which I believe can handle reloading parts of a view on path-change.