Change Angular base href with ngx-translate - javascript

I have already implemented ngx-translate succesfully. Now, I want to change the base href of my Angular project, depending on the language I choose from my header menu.
Currently, my URL looks like this: "localhost:4200". Then, when you launch the project, it must show something like this: "localhost:4200/en" or like this: "localhost:4200/es", depending on the choosen language.
My index html has this:
<base href="/"/>
And my header component ts file has a function that changes the language using ngx-translate. As you can see, I tried to use 'replaceState' to show the choosen language in the URL, and it worked, but it disappears once I navigate to another route.
import { Component, OnInit } from '#angular/core';
//For translate language
import { TranslateService } from '#ngx-translate/core';
import { Router, Event, NavigationStart, NavigationEnd } from '#angular/router';
import { Location } from '#angular/common';
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss'],
})
export class HeaderComponent implements OnInit {
constructor(private translate: TranslateService,
private router: Router,
private location: Location,
)
{ translate.addLangs(['es','en']);
translate.setDefaultLang('es');
}
ngOnInit(): void {
}
useLanguage(language: string): void {
this.translate.use(language);
// alert(language);
// location.replace("https://www.google.com");
// return;
const modified_path = language;
this.location.replaceState(modified_path);
}
}

It looks like you are trying to achieve some kind of routing using base href. I would use base href only if I need multiple instances of my application. E.g. each of them in a subfolder.
Maybe you should give try on Angular Router (https://angular.io/guide/router-reference) if you want just one instance of the application handling different languages.
The idea is to have a route on the root level that represents the language and a language guard that ensures only valid languages are called.
This would look something like this:
const routes2: Routes = [
{
path: ':language',
canActivate: [LanguageGuard],
children: [
{
path: 'home',
component: HomeComponent,
},
{
path: 'some-page',
component: SomePageComponent,
},
]
},
{
path: '**',
redirectTo: '/en',
},
];

Related

Angular 8 routing changes unintentionally querystring order

Building an app using Angular 8 as landing page that accepts dynamic query strings within the redirect link which contains some query string keys as number like: 42=17 so for example when I hit in the browser the full link as follow with:
http://localhost:4200/success?id1=123&42=17&hash=qwertzuiop
Result: It changed the sequence unintentionally to:
http://localhost:4200/success?42=17&id1=123&hash=qwertzuiop
Expected: To maintain the same order of the query string as I need to check the hash string against the original url if it's altered and of course when the sequence changes, the hash function result changes consequently.
Code sample:
app-routing.module.ts
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { SuccessComponent } from './success/success.component';
import { NotFoundComponent } from './not-found/not-found.component';
const routes: Routes = [
{ path: 'success', component: SuccessComponent },
{ path: '**', component: NotFoundComponent }
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
success.component.ts
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute, Router } from '#angular/router';
#Component({
selector: 'app-success',
templateUrl: './success.component.html',
styleUrls: ['./success.component.scss']
})
export class SuccessComponent implements OnInit {
constructor(
private route: ActivatedRoute,
private router: Router) { }
ngOnInit() {
console.log(this.route.snapshot.queryParams);
// {42: "17", id1: "123", hash: "qwertzuiop"}
console.log(this.router.routerState.snapshot.url);
// /success?42=17&id1=123&hash=qwertzuiop
}
}
Any clue if I can intercept the original URL before matching angular routes and navigating?

Trigger Module Lazy Load Manually Angular 7

Official documentation has quite a lot of information about how to load angular modules lazily. [link here]
const routes: Routes = [
{
path: 'customers',
loadChildren: './customers/customers.module#CustomersModule'
},
{
path: 'orders',
loadChildren: './orders/orders.module#OrdersModule'
},
{
path: '',
redirectTo: '',
pathMatch: 'full'
}
];
This basically makes the module load when user visits /customers or /orders routes.
However, I can't figure out how do I load a module when from another module.
In my application I have these modules:
auth
core
events
flash messages
One route of my auth module (profile page) has to use ngrx store from events module.
My code looks like this:
import { Observable } from 'rxjs';
import { Component, OnInit } from '#angular/core';
import { Store } from '#ngrx/store';
import { AppState } from '../../app.store';
import { IUser } from '../auth.api.service';
import { selectUser } from '../store/auth.selectors';
import { IEvent } from '../../events/events.api.service';
import { selectAllEvents, selectIsLoading } from '../../events/store/events.selectors';
#Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.scss'],
})
export class ProfileComponent implements OnInit {
isLoading$: Observable<boolean>;
events$: Observable<IEvent[]>;
user$: Observable<IUser>;
constructor(
private store: Store<AppState>,
) {
this.user$ = this.store.select(selectUser);
this.isLoading$ = this.store.select(selectIsLoading);
this.events$ = this.store.select(selectAllEvents);
}
ngOnInit() {
}
}
However, as you can expect this code does not work. Because ../../events is not loaded yet. How do I load the module manually? Something like:
constructor(
private store: Store<AppState>,
) {
this.user$ = this.store.select(selectUser);
this.loadModule('../../events/events.module.ts').then(() => {
this.isLoading$ = this.store.select(selectIsLoading);
this.events$ = this.store.select(selectAllEvents);
})
}
The Angular CLI bundler bundles up the modules based on two things:
1) If you have the modules set up for lazy loading (loadChildren), it will bundle the module up separately and provide it lazily.
2) HOWEVER, if there are any references to a lazy loaded module in any other module (by adding it to its imports array), it instead bundles the module with the referenced component.
So what should be happening is that if your events module is referenced from a component, it should be bundled with that component.
Do you have the module referenced in the imports array for the module containing the component that references it?
What error are you getting exactly?
BTW - I cover this in the "lazy loading" part of this talk: https://www.youtube.com/watch?v=LaIAHOSKHCQ&t=1120s
You need not worry about loading the ../../events. Since you have the import statement, the class/interface would be available in the module. If for some reason, you want to use features of other modules, you can add the module name in the imports array in the #NgModule declaration.

Angular: Setup routes depending on service method call

I have route configuration set up via #NgModule. And I have a service that identifies what parts of the application should be shown for the user depending on certain conditions. I need to call that service and setup the routes according to the returned value.
Problem: Route configuration is setup inside an annotation and I can't get how to call the service in such setup.
To be more specific here is the example configuration I want to enhance.
My current routing setup:
const appRoutes: Routes = [
{
path: '',
redirectTo: 'first-route',
pathMatch: 'full'
},
{
path: 'first-route',
component: FirstComponent,
pathMatch: 'full'
},
{
path: 'second-route',
component: SecondComponent,
pathMatch: 'full'
},
...
];
#NgModule({
imports: [RouterModule.forChild(appRoutes)],
exports: [RouterModule]
})
export class MyRoutingModule {
}
The service that should change the route setup:
#Injectable()
export class MyService {
getAccessibleRoutes(): Observable<string[]> {...}
}
Question: How can I make a service call and change the routes?
Note: I also looked on "Dynamically adding routes in Angular" and "How we can add new routes dynamically into RouterModule(#NgModule imports)" but I haven't found clear answer there.
If I correctly understood your problem, I think you probably can consider using route guards to reach you goal. I suggest you to use guards feature to specify the conditions of accessing your routes, instead of changing the list of routes.
Please check this link for more information about route guards:
https://codecraft.tv/courses/angular/routing/router-guards/
I hope this will help you.
import { Injectable } from '#angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '#angular/router';
import { YourSecurityService } from './your-security.service';
#Injectable()
export class YourRouteGuardService implements CanActivate {
constructor(
private router: Router,
private yourSecurityService: YourSecurityService) {
}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): boolean {
console.log(state.url); // HERE YOU CAN GET REQUESTED ROUTE
if (this.yourSecurityService.checkIfUserHaveAccess())
return true;
this.router.navigate(['your-route-to-redirect']);
return false;
}
}
Next you should apply your guard to your route:
const appRoutes: Routes = [
{
path: 'someroute',
component: RouteComponent,
canActivate: [YourRouteGuardService]
},
...
]

Angular 5. How to track route change in Javascript file, or execute function in component level?

I have global.js script file and need to launch InitSwiper() function when route changes to '/home', but can't find how to track router in script file or launch function through home.component.ts
import { Component, OnInit } from '#angular/core';
declare var global: any;
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
ngOnInit() {
global.initSwiper();
}
}
global.js
$(function () {
"use strict";
$(window).load(function(){
pageCalculations();
$('#loader-wrapper').fadeOut();
$('body').addClass('loaded');
initSwiper();
});
...
})
If you are using CLI, you need to include that file in .angular-cli.json file inside "scripts" array.
if you want to call a function from that file in home.component.ts only, then you can declare as below
declare var global:any;
and then on
ngOnInit(){
global.InitSwiper();
}
Some have suggested guards, but it's overkill if you don't need to delay or prevent the route from being loaded.
If you import router in your constructor you can actually subscribe it like so:
import { Router, NavigationEnd } from '#angular/router';
constructor(private next: Router) {
next.events.subscribe((route) => {
if (route instanceof NavigationEnd) {
console.log(route.url);
}
});
}
In the example above it should print out the current route.
You can create a service and have your router call it in the canActivate once it goes to the required route like so. This will let you handle anything before the component gets loaded
router.module.ts
...
import {myService} from '../services/myService.service'
export const routes: Routes = [
{path: '/home', component: HomeComponent, canActivate:[myService]}
]
...
myService.service.ts
import { Injectable } from '#angular/core';
import { CanActivate, Router } from '#angular/router';
#Injectable()
export class myService implements canActivate{
canActivate{
//execute initSwiper here
if(/*success?*/){
return true;
}
else{
//redirect?
}
constructor(
private _router: Router) { }

Conditional routing change default route in Angular 2

I'm creating an app that when the user enters to the page he goes to the default route wich is "Login" page. What I want is based on a condition (if the user has a local storage variable id, a method called isAuthenticaded() returns true if not false) the user must see the "Polls" page instead of "Login" page.
I think two different ways to aprouch this:
1- Change default page: if the method returns true the default page should be "Polls" if not "Login".
2- Redirect the user: if the method returns true the user is redirected to "Polls".
What's the best aprouch to archieve this?
How can I do one or both of the point to get conditional routing?
This is my routing config with the isAuthenticated() method:
import {Component} from 'angular2/core'
import {HTTP_PROVIDERS, Http} from 'angular2/http';
import 'rxjs/Rx'; // load the full rxjs
import {RouteConfig, ROUTER_DIRECTIVES, Router} from 'angular2/router';
import { PollsComponent } from './pollslist/pollslist.component'
import { Login } from './login/login'
#Component({
selector: 'my-app',
templateUrl: 'app/app.component.html',
directives: [ROUTER_DIRECTIVES, Login, PollsComponent],
providers: [HTTP_PROVIDERS]
})
#RouteConfig([
{ path: '/login', name: 'Login', component: Login, useAsDefault: true },
{ path: '/polls', name: 'Polls', component: PollsComponent }
])
export class AppComponent {
isAuthenticated() {
if (localStorage.getItem('id')) {
return true;
} else {
return false;
}
}
}
You can check in
#CanActivate() and navigate to a different route using router.navigate()
or create a custom <router-outlet> where you do this.
For details see https://medium.com/#blacksonic86/authentication-in-angular-2-958052c64492#.f76jyafdn
See also Check if the user logged in on any page change in Angular 2
Router definition has loader parameter:
loader : () => Promise<Type>
that allows to determine component type dynamically and async.

Categories