Scrolling to a div inside a container with overflow-y in Angular - html

In an angular app I have two bootstrap columns - the left col contains a scrollable div with overflow-y: auto; - the right col is a set of links that are essentially bookmarks that jump to the sections within the left scrollable container.
As far as I can see I'm facing two challenges:
1 - Setting up Angular to recognise I wish to scroll to page section when routing is enabled.
This I've over come by using router options and fragments
const routerOptions: ExtraOptions = {
useHash: false,
scrollPositionRestoration: 'enabled',
anchorScrolling: 'enabled',
scrollOffset: [0, 64]
};
imports: [
...
RouterModule.forRoot(appRoutes, routerOptions),
...
]
And the link:
<a [routerLink]='"."' fragment="uniquedivid">Link</a>
2 - Getting a fragment / anchor to be scrolled into place when it's inside an overflow
From what I've read on SO and other blogs I can see a varying array of ways to do this but most of them use JQuery (which I want to avoid as I'm using pure Angular) and none of these methods seem to compliment the route system in Angular.
I don't know if this makes a difference but my links come AFTER my overflow-ed div as shown below:
<div class="row">
<div class="col">
<div id="overflow">
<div id="section-1"></div>
<div id="section-2"></div>
<div id="section-3"></div>
</div>
</div>
<div class="col">
<a [routerLink]='"."' fragment="section-1">Section 1</a>
<a [routerLink]='"."' fragment="section-2">Section 1</a>
<a [routerLink]='"."' fragment="section-3">Section 3</a>
</div>
</div>
I feel like I'm along the right lines here there's just something I'm missing, or maybe I'm overcomplicating things and there's a simpler way I'm not aware of?

I'm not sure you got a solution for it, but if I were you, I would have used a well organized npm module that can directly help you organize the breadcrumbs. If I understand the question correctly, you can use angular-crumbs.
You can organize your routing like this :
export const rootRouterConfig: Routes = [
{path: '', redirectTo: 'home', pathMatch: 'full'},
{path: 'home', ..., data: { breadcrumb: 'Home'}},
{path: 'about', ..., data: { breadcrumb: 'About'}},
{path: 'github', ..., data: { breadcrumb: 'GitHub'},
children: [
{path: '', ...},
{path: ':org', ..., data: { breadcrumb: 'Repo List'},
children: [
{path: '', ...},
{path: ':repo', ..., data: { breadcrumb: 'Repo'}}
]
}]
}
];
Then try to add the breadcrumb selector in the component where your routes are destined to (when using bootstrap):
<breadcrumb #parent>
<ol class="breadcrumb">
<ng-template ngFor let-route [ngForOf]="parent.breadcrumbs">
<li *ngIf="!route.terminal" class="breadcrumb-item">
{{ route.displayName }}
</li>
<li *ngIf="route.terminal" class="breadcrumb-item active" aria-current="page">{{ route.displayName }}</li>
</ng-template>
</ol>
</breadcrumb>
There are other ways too, you can check here to implement.

Related

How to implement routing in Angular?

I got a project developed by Angular. I got a problem implementing routing properly. I defined a button on the welcome page, So when you click on that, You'll be directed to the main page actually. Here's the problem; I got two buttons instead of only one!
<div class="container text-center">
<a class="btn btn-lg btn-warning btn-block" routerLink="persons">List of Persons</a>
</div>
<div class="mt-5 container text-center">
<router-outlet></router-outlet>
</div>
Here's a how the first page looks like
This is the person's HTML page supposed to be shown after clicking on the button.
<h1 class="container">
<p>You currently have {{ favoritesIds.length }} favorites</p>
<app-welcome-message [name]="person[0].name"></app-welcome-message>
</h1>
<div class="row justify-content-center align-items-center ms-4 container">
<div class="col-sm-4 text-center" *ngFor="let p of person">
<app-profile-info
[isFavorite]="favoritesIds.includes(p.id)"
[person]="p"
(selectEvent)="favoriteHandler($event)"></app-profile-info>
</div>
<div class="mt-5">
<app-new-friend-card></app-new-friend-card>
</div>
</div>
Here is app.module.ts
imports: [
BrowserModule,
RouterModule.forRoot([
{path: '', component: FirstPageComponent},
{path: 'persons', component: AppComponent},
{path: 'newfriend', component: NewFriendPageComponent}
])
],
providers: [],
bootstrap: [FirstPageComponent]
I assume your first code snippet is taken from your app.component.html, is that correct? It would definitely help if you could add the file names to your code snippets.
What you should do first of all is to add pathMatch: 'full' as an option to your first route.
imports: [
BrowserModule,
RouterModule.forRoot([
{path: '', pathMatch: 'full', component: FirstPageComponent},
{path: 'persons', component: AppComponent},
{path: 'newfriend', component: NewFriendPageComponent}
])
],
providers: [],
bootstrap: [FirstPageComponent]
Angular routing works by iterating through the list of routes until a matching one is found (by default it is checked if the target route starts with one of the configured ones). Since your first route is empty, every route will start with it, leading to other routes being never loaded.
Nevertheless it's kind of strange that the second route contains component: AppComponent. Usually AppComponent is the root component of your application, where also the <router-outlet> is contained. If this is the case, seeing the duplicate button is correct, since you are first of all rendering your AppComponent, but once you route angular router injects AppComponent again right after your <router-outlet></router-outlet>.

Angular: Route from Card to a new View

I am working on an exercise project in Angular (latest V).
My App instanciates bootstrap cards dynamically from an Order Array and show them on my "Order-Item-Component through my template.
I added Routing so that I can update my OrderId on the Browser-Link after a click. It is working.
What I want is: If a user clicks on one of my cards - a whole new View Opens with my Order-Detail-Component for that specific Id. My cards should be invisible in that view. Subsequently, the user can go back to the cards-view with 'back' Link.
I don't know how to route so that my cards are going to be replaced by the Detail View.
Where do I have to place my 'router-outlet' for the detail-comp? I know, that I cannot place it in the same View as my Order-Component - because there are both visible in this case.
Here is my app.routing.ts: (The first route for orders is working fine)
import {RouterModule, Routes} from '#angular/router';
import {OrderComponent} from './order/order.component';
import {ORDER_ROUTES} from './order/order.routes';
import {OrderDetailComponent} from './order/order-detail/order-detail.component';
const APP_ROUTES: Routes = [
{ path: '', redirectTo: '/orders', pathMatch: 'full'},
{ path: 'orders', component: OrderComponent},
{ path: 'orders/:id', component: OrderDetailComponent
];
export const routing = RouterModule.forRoot(APP_ROUTES);
Here is my Order.Component.html:
<div class="container-fluid"><br>
<h2 id="heading-order"><i class="fa fa-shopping-cart f-left "></i>Open Orders</h2>
<p id="heading-items"> {{ orders.length }} Items </p>
</div>
<app-order-list></app-order-list>
<app-order-completed></app-order-completed>
Thanks in advance.
You might be able structure your app this way:
app.component.html:
<router-outlet></router-outlet>
routing module:
const APP_ROUTES: Routes = [
{ path: '', redirectTo: '/orders', pathMatch: 'full'},
{ path: 'orders', component: OrderComponent},
{ path: 'order-details/:id' component: OrderDetailsComponent}
];
order.component.html:
Provide [routerLink]="['/order-details', id] on your card, and pass the parameters to identify cards
Order component can also include <order-completed> in the view, if you need the completed orders to behave the same way, have them link to order details in the same way as the other orders.
To navigate back to the list of order, in your order-details.component.html provide a router link like routerLink="/orders"
You would use <router-outlet> instead of the custom tags <app-order-list></app-order-list>, <app-order-completed></app-order-completed> in your app component.
This way you can create child views:
const APP_ROUTES: Routes = [
{ path: '',
pathMatch: 'full',
component: OrderComponent,
children: [
{ path: 'order-list', component: OrderListComponent},
{ path: 'orders-completed', component: OrderCompletedComponent},
]},
];
And this is how the OrderComponent would look like:
<div class="container-fluid"><br>
<h2 id="heading-order"><i class="fa fa-shopping-cart f-left "></i>Open Orders</h2>
<p id="heading-items"> {{ orders.length }} Items </p>
</div>
<router-outlet></router-outlet>
Then use routerLink="/orders-completed" on a <button> or <a> tag to navigate

Why in my Angular-project does not replace home-page when I go to another route, and just adds the bottom of the page?

Here is the markup of my home page. I wrote several routes, and I need to display the content of the corresponding component instead of the home page when switching to them. And I have it added from the bottom of the home, and the home content continues to be displayed.
<div class="container">
<div class="row">
<app-header></app-header>
</div>
<div class="row">
<app-home></app-home>
<router-outlet></router-outlet>
</div>
<div class="row">
<app-footer></app-footer>
</div>
</div>
This is my app-home:
<app-home-news [homeImages]="homeImages"></app-home-news>
<router-outlet></router-outlet>
This is my routes:
const routes: Routes = [
{ path: 'sign-up', component: SignUpComponent },
{ path: 'sign-in', component: SignInComponent }
];
There is no error, the content simply adds to the home. How to make it appear in his place?
See anything which is outside <router-outlet></router-outlet> will always be there. Like in your case header and footer only should be in main html not home component. Anything you to change on the basis of routing, you should be part of routing configuration.
Make the following changes
<div class="container">
<div class="row">
<app-header></app-header>
</div>
<div class="row">
<!-- removed the home component -->
<router-outlet></router-outlet>
</div>
<div class="row">
<app-footer></app-footer>
</div>
</div>
Add the home component as the part of the routing.
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'sign-up', component: SignUpComponent },
{ path: 'sign-in', component: SignInComponent }
];
Note : I add the component at the root level so I left the path blank but you can as per your path like
{ path: 'home', component: HomeComponent },
You need to be careful about your routes and what router outlets your urls are going to populate. It's not just a case of putting a router-outlet at the bottom of each of your components to display something new...
Assuming I had a very basic AppComponent template:
<h1>Hello</h1>
<router-outlet></router-outlet>
... and some configured routes:
{ path: '', component: HomeComponent }
{ path: 'test', component: TestComponent },
{ path: 'hello', component: HelloComponent}
... which just contained their own names in a p tag (home, test, and hello respectively).
The following would be true for each url:
example.com
Hello
Home
example.com/test
Hello
Test
example.com/hello
Hello
Hello
The route has loaded the component into the router-outlet.
If my components then had router outlets of their own, we're in to child route territory, wherein you start to use urls such as example.com/test/abc, with your routes looking more like:
{
path: 'test',
component: TestComponent,
children: [
{ path: 'abc', component: AbcComponent },
{ path: 'def', component: DefComponent }
]
}
Which would result - assuming the same content rules as above would look like:
example.com/test/abc:
Hello
Test
Abc
example.com/test/def:
Hello
Test
Def
Typically, your AppComponent handles your site-wide header/footer/nav/etc. with a single router-outlet that every other component will be loaded into, which includes your home page itself...
{ path: '', component: HomeComponent }
{ path: 'sign-up', component: SignupComponent }
{ path: 'sign-in', component: SigninComponent }
There may well be further router-outlets in the components (as above), but it seems that what you currently WANT, most likely, is this case rather than the more complex type with nested outlets above that you currently HAVE.

How to hide my left nav menu only on certain pages

I am working on a angular5/html 5 project. I have a side-nav-menu component that displays on all the pages of my app. The thing is that this side-nav-menu component is dynamic and automatically updates if any more pages are added in the app.
Now what i want to do is hide this menu only on certain pages. for example i want to remain visible on page 1-5, hidden on page 6-8 and again visible on 9 and 10. How should i do this?
This is my edited html code for side-nav-menu:
<aside>
<div class="sidebar">
<nav>
<div class="sidebar__wrap">
<ol class="left-nav">
</ol>
</div>
</nav>
</div>
</aside>
See How to get current route
You can read the route from the Router object from the parent component of the sideNav or in sideNav itself and *ngIf on the template:
constructor(router: Router) {
router.events.subscribe(event => {
if (router.url === 'SOMEROUTE') {
this.showSideNav = false;
}
}
}
then set *ngIf on your side nav to showSideNav.
Looks like a suitable case for a Shell Component. You can create one that is going to shell the whole area of your App. In this you can have a <router-outlet></router-outlet> which is going to host all the pages without the side-nav.
And for the pages that you want to have a side-nav, you can create a parent route(say /app) and then in its children define the routes for the pages that you want to have the side-nav.
So your routeConfig would look something like:
const APP_ROUTES: Routes = [
{ path: '6', component: Component6 },
{ path: '7', component: Component7 },
{ path: '8', component: Component8 },
{ path: 'app', component: ComponentApp, children: [
{ path: '1', component: Component1 },
{ path: '2', component: Component2 },
{ path: '3', component: Component3 },
{ path: '4', component: Component4 },
{ path: '5', component: Component5 },
{ path: '9', component: Component9 },
{ path: '10', component: Component10 },
]}
];
Now, in the AppComponent's template, add a <router-outlet></router-outlet>. This is supposed to load ComponentApp, Component6, Component7, and Component8. And then there would be ComponentApp that will have the side-nav and below that, another <router-outlet></router-outlet> that is going to load Component1-Component5, Component9 and Component10.
Just one thing that is going to be an issue in your case would be, you'll have to consider the children components to be under a sub-route.
Deborah Kurata has a very interesting NGCONF Talk about this and several other router related concepts that I suggest you watch to get a better understanding.

How to trigger multiple outlets with one routerLink in angular2 (2.1.1)

I'd like to swap out components in 2 separate areas of the DOM when I select a routerLink element. How can I route a single routerLink to 2 <router-outlet>s and designate a unique component for each <router-outlet>?
I'd like something like this:
<div id="region1>
<a routerLink="/view1" routerLinkActive="active">View 1</a>
<a routerLink="/view2" routerLinkActive="active">View 2</a>
<!-- First area to swap -->
<router-outlet name="sidebar"></router-outlet>
<div>
<div id="region2>
<!-- Second area to swap -->
<router-outlet name="mainArea"></router-outlet>
<div>
routes
const routes: Routes = [
{ path: '', redirectTo: 'view1', pathMatch: 'full'},
{ path: 'view1', {
outlets :
[
//one path specifies 2 components directed at 2 `router-outlets`
component: View1Sidebar, outlet : 'sidebar'
component: View1mainArea, outlet : 'mainArea'
]
}
},
{ path: 'view2', {
outlets :
[
component: View2Sidebar, outlet : 'sidebar'
component: View2mainArea, outlet : 'mainArea'
]
}
},
];
This cannot be done exactly as you ask. The purpose of a router is to maintain information about the specific page.
If you want to show and hide any components without reflecting any route information then you'll want to use the *ngIf directive. To use it like this, you'll need to keep a variable in you application somewhere that can be used to trigger the *ngIf directive.
You can make use any type of data, but you need to pass it to the *ngIf statement in the form of a boolean or expression that resolves to a boolean: here are examples"
component
showComponentBool: boolean = true;
showComponentStr: string = 'show';
html
<div *ngIf="showComponentBool">
<div *ngIf="showComponentStr='show'"></div>
</div>
With "#angular/core": "^4.0.0"
<a [routerLink]="[{ outlets: { primary: 'contact', aux: 'aside' }}]">Contact + Aux</a>
https://stackoverflow.com/a/42558766/2536623