Use routing from Angular Components in Hybrid mode - angularjs

I'm using AngularJS 1.5 and Angular 7 in hybrid mode. How can I change the url in an Angular component? I tried like to access the current url as follows:
constructor(private router: Router, private route: ActivatedRoute) {
console.log(this.route.snapshot.queryParams);
}
The query parameters are always empty. In a parent AngularJS component I get the query parameters using the $location service.
If I try to change the route using the router, it says invalid route. How can I change the current url in an Angular component? Currently I'm emitting an event, which in turn is grabbed by the parent AngularJS component who can use the $location service.

I managed to do it by upgrading the AngularJS $location service:
#Injectable()
export class LocationService {
search(queryParameter?: string, value?: string): string | any {
return undefined;
}
}
In AppModule do the following
{provide: LocationService, useFactory: (i: any) => i.get('$location'), deps: ['$injector']},

Use the following way to get the query params :
constructor(private router: Router, private route: ActivatedRoute) {
this.route.queryParams.subscribe(params => {
console.log(params);
});
}
to navigate to other url (as you specified, ie to change url ) then use:
this.router.navigate(['/someurl']);

Related

Angular web component directive its not working

I am trying to convert angular components to angular web component, I followed few articles to do it which is good, but when I tried to convert angular directive as web component it throws some error which I am not able to figure out what is wrong I am doing, also I don't have any idea on can we convert an angular directive to angular web component. Below is code which I tried to convert directive as web component.
Tooltip Directive:
<pre>#directive({
selector: '[tooltip]'
})
export class TooltipDirective {
constructor(private el: ElementRef) {
this.el.nativeElement.classList.add('my-tooltip');
}
}</pre>
Creation of tooltip web components snippet:
<pre>export class AppModule implements DoBootstrap {
constructor(private injector: Injector) {}
ngDoBootstrap() {
const webTooltip = createCustomElement(TooltipDirective, {
injector: this.injector,
});
customElements.define("web-tooltip", webTooltip);
}
}
</pre>
How I am trying to use in app HTML file is below code
Web tooltip selector:
<span web-tooltip id="tooltip" content="This is a tooltip.">
enter image description here
If I try to write same code for any component its working fine but for directive as I shown code above its not working.

Convert $window.UserSettings array from angularjs component to angular 8 component

I have an angularjs 1.7 component which I need to upgrade to angular 8 component. It has an external script, which I cannot modify. That script inserts an iframe into the div and it expects some settings from the component to customize the iframe.
The old component code:
angular.module('myApp.shared').component("userExternal", {
template: '<div id="userIframe"></div>',
controller: function ($window) {
this.scriptUrl = "//myurl/widget/addIframe.js";
this.$onInit = function () {
$window.UserSettings = [];
$window.UserSettings.push(['set', {
btn_color: '#008A00',
bg_color: 'white'
}]);
});
};
}
});
I have two problems here:
I don't know how to convert $widnow to angular 8 window object.
When I convert $window to angular 8 window, how can I add UserSettings array to it?
This is my angular 8 component, but my code did not work correctly.
HTML Template
<script src="//myurl/widget/addIframe.js"></script>
<div class="user_external></div>
TS Code
import { Component} from '#angular/core';
#Component({
selector: 'app-user',
templateUrl: './user-external.component.html'
})
export class UserExternalComponent {
constructor() {
}
ngOnInit() {
window.UserSettings = [];
window.UserSettings.push(['set', {
btn_color: '#008A00',
bg_color: 'white'
}]);
console.log(window);
}
}
Thank you
Following a combination of this tutorial for the window reference and this tutorial for upgrading from AngularJS to Angular in general, I created an injectable service that seems to be doing the job, at least so far in a downgraded context. (Next step is to start upgrading the modules that use the dependency, but I successfully replaced all AngularJS injections of $window with my new APIWindow class, and everything works as before with no breaking errors.)
Keeping in mind this is being used as a downgraded Angular class inside a currently mostly AngularJS app, the class looks like this:
// api.window.service.ts
import { Injectable } from '#angular/core'
import { downgradeInjectable } from '#angular/upgrade/static'
import * as angular from 'angular'
// You could change this to return any property on Window, but external is the one I use:
function _external (): any {
return window.external
}
#Injectable()
export class APIWindow {
get external (): any {
return _external()
}
}
angular
.module('APIModule')
.service('APIWindow', downgradeInjectable(APIWindow))
Hopefully this helps someone else with a similar situation following this upgrade path!

How to watch Route changes in AngularJS component (v1.5.8)

I'm building the app in AngularJS 1.5.8.
I've a main root component called app.component.
in app.component, I wanna watch all routes changes which happens navigating between child components.
And in watch, I need to get routeParams, as well.
I've defined the routes via $routeConfig in angularjs component-router
I've tried with this.$routerOnActivate but it wasn't called because I'm on root component.
var controller = function ($scope) {
$scope.$on('$routeChangeSuccess', (event, data) => {
// This is called everytime route is changed
// Here, I need to get the routeParams
// Not sure this is the correct way to watch route changes in angular component-router
});
}
angular
.module('example')
.component('RootComponent', {
templateUrl: 'app/components/enter/enter.component.html',
controller: controller,
$routeConfig: [
{path: '/a', name: 'AComponent', component: 'AComponent', useAsDefault: true},
{path: '/b', name: 'BComponent', component: 'BComponent'},
]
});
Thanks.
PS
I've tried with How to watch for a route change in AngularJS?.
It was called everytime I change the route but I can't get routerParams from it.
On the official doc, it said 3 params are available - $event, current, next but only $event is coming, the rest is undefined.
I thinks it's working when we define routes via $routeProvider but not in my case.

What is the Angular2 equivalent to an AngularJS $routeChangeStart?

In AngularJS we were able to specify route change event to observe changes in route object using the $routeChangeStart/End event of the $rootScope. What is the equivalent of the route change event in Angular2?
how can we do this exact functionality of below code in Angular2
$scope.$on('$routeChangeStart', function (scope, next, current) {
//do what you want
});
I got some disucussions here, But it don't have more details, So I asked a new question.
angular2 $routeChangeStart , $routeChangeSuccess ,$routeChangeError
You can listen the events of the router by doing the following:
import {
Router, ActivatedRoute,
NavigationEnd, NavigationStart,
NavigationError, NavigationCancel,
} from '#angular/router';
// constructor method of some angular element
constructor(
private _router: Router,
) {
this._router.events
.filter(event => event instanceof NavigationStart)
.subscribe(event => {
console.log("New route");
});
}
EDIT: Im not completely sure is that is actually what you need, after taking a closer look to the angularjs docs seems like those events are more related to the resolution/result of a guard in angular2

Angular 1.5 $routerOnActivate on Root Router

I want to make sure that the user is logged in properly before proceeding to any of the components he/she's trying to reach, if they're not logged in. Send them to login.
My idea is to do a check in the $routerOnActivate in the root router. Which to me would solve the issue for any sub routes.
However nothing seems to happen if i just try to log something. Example:
angular
.module('app')
.config(function($locationProvider) {
$locationProvider.html5Mode(true);
})
.value('$routerRootComponent', 'app')
.component('app', {
templateUrl:'landing.html',
controller: MainController,
$routeConfig: [
{ path: '/', name: 'Dashboard', component: 'dashboard', useAsDefault: true },
{ path: '/media', name: 'Media', component: 'media'}
...
]
});
function MainController(){
this.$routerOnActivate = function(next, previous){
console.log('activated', next, previous);
};
}
The same code this.$routerOnActivate works if i put it in any of the Components which are specified in the routeConfig. However obviously I don't want to make the same check in every component, but rather solve it once globally.
What is the approach for 1.5?
Instead of performing a check when you load a page, use following:
Angular has a special component lifecycle hook to handle these edge cases named $canActivate - to check whether it should try to activate it or not. You may talk to a authentication/authorization service to validate that for a given user's state, are they allowed to reach your component or not.
This way your component will be smart enough to encapsulate any checks required to activate itself.
Also, you can inject any service like $http or your custom service to talk to your server. In the code snippet below, I mimic this call using $timeout that just returns true, if you return false, your component will not activate.
angular.module('app').component('someComponent', {
template: 'this is an inline component template',
$canActivate: function ($timeout) {
return $timeout(function(){
return true;
}, 2000);
}
});
Use another hook named $routerOnActivate to read the next and previous routes. If you are interested in the params of a route, use next.params which is an object that will always have the parameters that were passed to that route. e.g. next.params.id where id is the parameter that was passed to the requested route.
Use $canActivate using TypeScript:
I've written a post regarding how to use write AngularJS components in TypeScript and have some drafts to use router lifecycle hooks that I'll publish today. Till then, here is the code to use some hooks using TypeScript below:
class ReviewDetailsComponent implements ng.IComponentOptions {
templateUrl = 'app/components/review-details.component.html';
// function member for this hook doesn't work!!
// so either use lambda expression or function directly.
$canActivate = $timeout => $timeout(() => true, 3000);
controllerAs = 'model';
controller = ['$http', ReviewDetailsController];
}
angular.module('app').component('reviewDetails', new ReviewDetailsComponent());
The typescript code above is same as javascript code snippet above that uses $canActivate.
Unfortunately, it didn't worked when this is defined as a function member in class like $canActivate() and the generated javascript is this member defined using prototype like ReviewDetailsComponent.prototype.$canActivate.
But it works well when written using lambda expression syntax or a function directly. If you are using a class to define a component, it is good to choose lambda expression in this case.
Use $routerOnActivate using TypeScript
The linked controller in this case also uses another lifecycle hook named $routerOnActivate and this works well if defined as a function member:
interface IReviewDetailsController {
id: number;
$routerOnActivate(next, previous);
}
class ReviewDetailsController implements IReviewDetailsController {
id: number;
constructor(private $http: angular.IHttpService) { }
$routerOnActivate(next, previous) {
this.id = next.params.id;
// talk to cache or server to get item by id
// & show that on UI
}
}
Paste from my comment as requested
What about perform your check on the loading on the page ? This would run perfectly in an angular.run.
And if you want to handle session expiration, you can add an interceptor to all requests and watch for a 401 response.

Resources