when i open my website i will see "Finance/voucher" on topenter image description here but when i refresh the page only "Finance" Appears and i don't want this i want when i refresh page still it will show "Finance/voucher" And all relevant code i have posted plz guide me which code i enter and where
export class TopBarComponent extends AppComponentBase {
formName = ""
constructor(
injector: Injector,
private _formTitleService: FormTitleService,
) {
super(injector);
}
ngOnInit() {
this.getFormTitle();
}
getFormTitle(){
this._formTitleService.getFormTitle()
.subscribe(name => {
this.formName = name;
});
}
Html code
<div class="page-title">
/ <span>{{formName}}</span>
</div>
You can set the initial value for formName = "Finance/voucher" in your component & it will be retained on page refresh.
I have a main page with couple of sections.
Each section can be reached by typing its fragment name on the url (Ex. www.website.com/#introduction - will open the homepage and scroll to the introduction section automatically).
In order to do that, I need to fetch the section’s container element and run .scrollIntoView() function on it.
What I have done:
List item I have created a store (ngrx) which stores the ElementRef(s) of the sections.
In each section component (located in HomeComponent - parent of the sections), I put a #ViewChild() pointing on the element.
#ViewChild(‘container’, { static: true }) private container: ElementRef;
Then on ngAfterViewInit() of this section component, I put
Store.dispatch() which stores my ElementRef on the store.
this.store.dispatch(new HomeActions.SetElementRef({
linkName: COMP_LINK_NAME,
elementRef: this.container
}));
Then, in HomeComponent, I listen to the sectionsRef store this.store.select('sectionRefs').
Filtered it if its undefined (as it is the default of the store = default statement is empty).
this.sectionRefs$ = this.store.select('sectionRefs').pipe(
map((data: { sectionRefs: SectionReference[] }) => data.sectionRefs), // transform to a more convenient object
tap((sectionRefs: SectionReference[]) => this.sectionRefs = sectionRefs), // Updates the sectionRefs array regardless the completion of it (filter below)
filter((sectionRefs: SectionReference[]) => { // No emission until sectionRefs Element Refs are completed
return sectionRefs.find((sectionRef: SectionReference) => {
return (
sectionRef.element === undefined ||
sectionRef.element === null ||
sectionRef.element.nativeElement.offsetHeight === 0 && sectionRef.element.nativeElement.offsetWidth === 0
);
}) === undefined // Means that no incompleted sectionRef was found
}),
distinctUntilChanged(
(prev: SectionReference[], next: SectionReference[]) => JSON.stringify(prev) === JSON.stringify(next)
),
first()
);
HomeCompoent: And eventually I listened to the ActivatedRoute.fragment, to check which ElementRef is relevant for the scrolling.
HomeComponent: Activate .scrollIntoView() on the relevant
ElementRef.
The issue is that I do it when the page is loaded so the ElementRef.nativeElement.scrollIntoView() is scrolling to incorrect place.
I checked to see the offsetHeight retrieved (ElementRef.nativeElement.offsetHeight) and it was also incorrect.
So In each section Component I wrapped the Store.dispatch() action with setTimeout()
setTimeout(() => {
this.store.dispatch(new HomeActions.SetElementRef({
linkName: COMP_LINK_NAME,
elementRef: this.container
}));
}, 150);
And it works!
But it is looking like a very bad practice to do this work around.
Is there any other solution?
I am facing some trouble in relflecting in my parent component if an item has been enabled or not based on the selection made in the child component.
I am displaying my child content through a router-outlet.
Overall view: I have a side menu with several headers. Upon click on a header a view page will appear and within it a checkbox to allow the user to either enable or disable the menu header item.
What i want is when a user checks the box in the child component - that a check mark will appear next to the enabled header (without having to refresh the page - which is currently what is happening)
Parent component:
public ngOnInit() {
this.getMenuHeadersList();
}
private getMenuHeadersList() {
this.service.getMenuItemList(this.id).subscribe(
(data: MenuItems[]) => {
if (data !== undefined) {
this.menuList= data;
}
},
(error: any) => {
.....
});
}
//for loop menuItem of menuList
<a id="menuId" class="refine-menu-collapse" [routerLink]="[...]">
<span *ngIf="menuItem.isEnabled" class="win-icon win-icon-CheckMark"></span>
<span class="refine-menu-subtitle">{{menuItem.name}}</span>
</a>
the span where i check if menuItem.isEnabled is the checkmark that i would like to have appear once the user enables it from the child view componenet.
Child component:
public ngOnInit() {
this.getMenuHeadersList();
}
private onMenuItemValueChange(menuItem: MenuItemType, checked: boolean) {
menuItem.isEnabled = checked;
this.saveMenuItemTypes(menuItem);// makes a service call and calls getMenuHeadersList.
}
private getMenuHeadersList() {
this.service.getMenuItemList(this.id).subscribe(
(data: MenuItems[]) => {
if (data !== undefined) {
this.menuList= data;
this.singleMenuItem = this.menuItems.find((value) => value.menuItem.id === this.menuId);
}
},
(error: any) => {
.....
});
}
Child Html:
<input type="checkbox"
[checked]="menuItem?.isEnabled"(change)="onMenuItemValueChange(menuItem, $event.target.checked)">
<span class="text-body">title</span>
I have this feeling that i don't need to make the call to get the menuItems in the child component and i could get it from the parent but i am not sure how i am messing up myself.
You have not child/parent. The most easy way to do it, is use a variable in a service
If your service you has some like
checkedItems:any[]=[]
If your header
get checkedItems()
{
return yourservice.checkedItems;
}
<span *ngIf="checkedItems[i]" class="win-icon win-icon-CheckMark"></span>
In your component, somewhere
yourservice.checkedItems[index]=true
I'm using routerLink to send an id from a component with a list of restaurants to another component via URL
[RouterLink] = "['../ restaurant-menu', restaurant.id]"
In the other component I use the id as follows
ngOnInit () {
this.restaurantId = this.router.snapshot.params ['id']
this.getRestaurantMenu (this.restaurantId)
}
restaurantMenu: void []
getRestaurantMenu (id): void {
this.RestaurantsService.getRestaurantMenu (id)
.subscribe (
restaurantMenu => this.restaurantMenu = restaurantMenu,
err => {
console.log (err);
});
}
Everything works fine the first time I click a restaurant and load its menu, the problem begins when I return to the list of restaurants and click a different restaurant, the app loads the menu of the first restaurant I clicked, I have to refresh the browser Manually to load the correct menu.
I doubt that the id could be updated after calling the function getRestaurantMenu() because no matter how many times I leave and enter into different restaurants it will always show the menu of the first restaurant, but I also tried to do this on the HTML:
<P> {{restaurantId}} </ p>
And the id number displayed is correct. I tried different ways to pass that id but the result is the same, what could be the problem? Thanks
Maybe try not to use snapshot but ActivatedRoute instead :
import { ActivatedRoute, Params } from "#angular/router";
...
constructor(private route: ActivatedRoute) { }
...
ngOnInit() {
// (+)param['id'] to convert string to number
this.route.params
.switchMap((param: Params) => this.RestaurantsService.getRestaurantMenu(+param['id']))
.subscribe(
restaurantMenu => this.restaurantMenu = restaurantMenu,
err => console.log (err)
);
}
I did what is suggested here
https://github.com/angular/angular/issues/9811#issuecomment-264874532
the restaurantMenu component stays the same but in the restaurantList component I added this:
import { Router } from '#angular/router';
...
openMenu(restaurant) {
this.router.navigate(['../restaurant-menu', restaurant])
.then(() => window.location.reload())
}
and on the restaurantList HTML I added a (click)="openMenu(restaurantId)" It reloads the new page automatically and the id is updated, its a little tricky solution but works and I'll use it until find a better one.
I finally solve this, the problem was in the service to get the menu not in the component, here is the solution:
angular 2 service is not updating params
if anybody else run into this problem this may help.
I have built an app that uses router 3.0.0-beta.1 to switch between app sections. I also use location.go() to emulate the switch between subsections of the same page. I used <base href="/"> and a few URL rewrite rules in order to redirect all routes to index.html in case of page refresh. This allows the router to receive the requested subsection as a URL param. Basically I have managed to avoid using the HashLocationStrategy.
routes.ts
export const routes: RouterConfig = [
{
path: '',
redirectTo: '/catalog',
pathMatch: 'full'
},
{
path: 'catalog',
component: CatalogComponent
},
{
path: 'catalog/:topCategory',
component: CatalogComponent
},
{
path: 'summary',
component: SummaryComponent
}
];
If I click on a subsection in the navigation bar 2 things happen:
logation.go() updates the URL with the necessary string in order to indicate the current subsection
A custom scrollTo() animation scrolls the page at the top of the requested subsection.
If I refresh the page I am using the previously defined route and extract the necessary parameter to restore scroll to the requested subsection.
this._activatedRoute.params
.map(params => params['topCategory'])
.subscribe(topCategory => {
if (typeof topCategory !== 'undefined' &&
topCategory !== null
) {
self.UiState.startArrowWasDismised = true;
self.UiState.selectedTopCategory = topCategory;
}
});
All works fine except when I click the back button. If previous page was a different section, the app router behaves as expected. However if the previous page/url was a subsection, the url changes to the previous one, but nothing happens in the UI. How can I detect if the back button was pressed in order to invoke the scrollTo() function to do it's job again?
Most answers I saw relly on the event onhashchange, but this event does not get fired in my app since I have no hash in the URL afterall...
I don't know if the other answers are dated, but neither of them worked well for me in Angular 7. What I did was add an Angular event listener by importing it into my component:
import { HostListener } from '#angular/core';
and then listening for popstate on the window object (as Adrian recommended):
#HostListener('window:popstate', ['$event'])
onPopState(event) {
console.log('Back button pressed');
}
This worked for me.
Another alternative for this issue would be to subscribe to the events emitted by the Angular Router service. Since we are dealing with routing, it seems to me that using Router events makes more sense.
constructor(router: Router) {
router.events
.subscribe((event: NavigationStart) => {
if (event.navigationTrigger === 'popstate') {
// Perform actions
}
});
}
I would like to note that popstate happens when pressing back and forward on the browser. So in order to do this efficiently, you would have to find a way to determine which one is occurring. For me, that was just using the event object of type NavigationStart which gives information about where the user is coming from and where they are going to.
To detect browser back button click
import platformlocation from '#angular/common and place the below code in your constructor :
constructor(location: PlatformLocation) {
location.onPopState(() => {
alert(window.location);
}); }
This is the latest update for Angular 13
You have to first import NavigationStart from the angular router
import { NavigationStart, Router } from '#angular/router';
Then add the following code to the constructor
constructor(private router: Router) {
router.events.forEach((event) => {
if(event instanceof NavigationStart) {
if (event.navigationTrigger === 'popstate') {
/* Do something here */
}
}
});
}
Angular documentation states directly in PlatformLocation class...
This class should not be used directly by an application developer.
I used LocationStrategy in the constructor
constructor(location: LocationStrategy) {
location.onPopState(() => {
alert(window.location);
});
}
A great clean way is to import 'fromEvent' from rxjs and use it this way.
fromEvent(window, 'popstate')
.subscribe((e) => {
console.log(e, 'back button');
});
Using onpopstate event did the trick:
window.addEventListener('popstate',
// Add your callback here
() => self.events.scrollToTopCategory.emit({ categId: self.state.selectedTopCategory })
);
I agree with Adrian Moisa answer,
but you can use "more Angular 2 way" using class PlatformLocation by injecting to your component or service, then you can define onPopState callback this way:
this.location.onPopState(()=>{
// your code here...
this.logger.debug('onpopstate event');
});
Simpler way - Link
import { PlatformLocation } from '#angular/common';
import { NgbModal } from '#ng-bootstrap/ng-bootstrap';
...
constructor(
private platformLocation: PlatformLocation ,
private modalService: NgbModal
)
{
platformLocation.onPopState(() => this.modalService.dismissAll());
}
I honestly don't know your use case. And the thread is quite old. But this was the first hit on Google. And if someone else is looking for this with Angular 2 and ui-router (just as you are using).
It's not technically detecting the back button. It's more detecting whether you as a developer triggered the state change or whether the user updated the URL themselves.
You can add custom options to state changes, this can be done via uiSref and via stateService.go. In your transitions, you can check whether this option is set. (It won't be set on back button clicks and such).
Using ui-sref
<a uiSref="destination-name" [uiOptions]="{custom: {viaSref: true}}">Bar</a>
Using state.go
import {StateService} from '#uirouter/core';
...
#Component(...)
export class MyComponent {
constructor(
private stateService: StateService
) {}
public myAction(): void {
this.stateService.go('destination-name', {}, {custom: {viaGo: true}});
}
}
You can detect it in any transition hook, for example onSucces!
import {Transition, TransitionOptions, TransitionService} from '#uirouter/core';
...
#Component(...)
export class MyComponent implements OnInit {
constructor(
private transitionService: TransitionService
) {}
public ngOnInit(): void {
this.transitionService.onSuccess({}, (transition: Transition) => this.handleTransition(Transition));
}
private handleTransition(transition: Transition): void {
let transitionOptions: TransitionOptions = transition.options();
if (transitionOptions.custom?.viaSref) {
console.log('viaSref!');
return;
}
if (transitionOptions.custom?.viaGo) {
console.log('viaGo!');
return;
}
console.log('User transition?');
}
}
You can check the size of "window.history", if the size is 1 you can't go back.
isCanGoBack(){
window.history.length > 1;
}