Sharing data with component of another module in Angular - javascript

just began to work with Angular 8.
I'm currently experimenting with creating an user interface for an complex project.
The Top Navigation Bar should represent the current mode the user is in. (Like Backend Operations, or Support System, ... which could represent optionally a different Modul).
I'm trying to implement everything in its own module as they could be developed by independent teams (in the future). So I moved everything on the design to the app component. (Layout) while the services that are shared between modules reside in an shared module.
This is the part that would reflect one first shared service property:
template:
<nav class="topBar navbar default-layout col-lg-12 p-0 fixed-top d-flex flex-row {{ getLocation() }}">
...
</nav>
component.ts
...
constructor(private frameworkService:FrameworkService) {
this.fms = frameworkService;
...
}
public getLocation(){
return this.fms.getLocation();
}
ngOnInit() {
}
}
shared modules:
import {NgModule} from '#angular/core';
import {CommonModule} from '#angular/common';
import {FrameworkService} from "./services/framework/framework.service";
#NgModule({
declarations: [],
imports: [
CommonModule
],
providers: [
FrameworkService
]
})
export class SharedModule {
}
framework.service.ts
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class FrameworkService {
private _location:string = '';
getLocation(): string {
console.log('getter');
console.log(this._location);
return this._location;
}
setLocation(value: string) {
this._location = value;
console.log('setter');
console.log(value);
console.log(this._location);
}
constructor() {
this._location = 'bg-backend';
}
}
in an module I'm trying to call it like this:
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { BackendRoutingModule } from './backend-routing.module';
import {MainComponent} from "./main/main.component";
import {SharedModule} from "../shared/shared.module";
import {FrameworkService} from "../shared/services/framework/framework.service";
#NgModule({
declarations: [
MainComponent
],
imports: [
CommonModule,
BackendRoutingModule,
SharedModule
]
})
export class BackendModule {
constructor(FrameworkService: FrameworkService){
FrameworkService.setLocation('bg-backend');
}
}
As far as I can see, I'm running into the problem that it is not using a singleton pattern (as I would have expected it) but more a multi instance approach. Who can I fix this. Several of the pages I looked at didn't really help me or just simply confused me. What I currently also jet need to find out is who to set the value depending on the active module.
Any help is appreciated
:-)
Chris

In the end it didn't work as expected.
I figured out that each session opens an new instance of this service.
So what I did is to store the required informations in the localstorage and accessing it in an static manor.
thanks for you help :-)

Related

Looking for pointers on routing between feature modules in angular

I was working on a big project of mine in angular, discovered feature modules and routing modules, then tried to implement that in order to better organize the project. When I did this, the app became very disfunctional. Since then, i made this test project to try to implement routing between feature modules, on a smaller, more managable scale.
This test project works, but there are some small problems that I know will cause issues down the line, and id like to resolve.
There are two big problems as I see it:
<a routerLink="some/link> does not work in feature modules, only app module: it renders in the markup as plaintext with no working link. I tried importing routerLink to the feature modules module.ts file, as a last ditch effort, but still nothing.
I was hoping that routing to a feature module, if configured that way, could display different mark up and styling, for example- routing to module-a shows one navigation menu, and routing to module-b shows another. Instead, the default behaivor happens- app.component is displayed everywhere, and routing
to a feature module makes the url specified component appear in place of router-outlet. Id like to disable this default behaivor if possible, so that components routed to in one feature module have one set of styles and features, and components routed to in another module have different styling and features- as if router-outlet recognizes that feature-a/component is part of feature-a, and in turn loads that modules' html and css as the app.component instead of the root app.component.
Attached the source code below, for this test project. I only included source for module feature-a, as feature-b is in essence the same thing with different text, to prevent unneeded cluttering
app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { FeatureAModule } from './feature-a/feature-a.module';
import { FeatureBModule } from './feature-b/feature-b.module';
#NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
FeatureAModule,
FeatureBModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
App.routing.ts
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { ChalpComponent } from './feature-a/chalp/chalp.component';
import { FeatureAComponent } from './feature-a/feature-a.component';
import { FeatureBComponent } from './feature-b/feature-b.component';
import { SkoneComponent } from './feature-b/skone/skone.component';
const routes: Routes = [
/* { path: 'feature-a', component: FeatureAComponent,
children: [
{ path : 'feature-a/chalp', component: ChalpComponent }
]
},
{ path: 'feature-b', component: FeatureBComponent,
children: [
{ path : 'feature-b/skone', component: SkoneComponent }
]
}
*/
{ path : 'feature-a/chalp', component: ChalpComponent },
{ path : 'feature-b/skone', component: SkoneComponent },
{ path: 'feature-a', component: FeatureAComponent },
{ path: 'feature-b', component: FeatureAComponent },
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
markup for app.component:
<h1>Inside App-Module now!</h1>
Go to feature A for chalp: <a routerLink="feature-a/chalp">Chalp</a>
Go to feature B for Skone: <a routerLink="feature-b/skone">Skone</a>
<router-outlet></router-outlet>
feature-a routing + module file
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { RouterModule, Routes, RouterOutlet, RouterLink } from '#angular/router';
import { FeatureAComponent } from './feature-a.component';
import { ChalpComponent } from './chalp/chalp.component';
const routes : Routes = [
{ path : '', component : FeatureAComponent },
{ path : 'chalp', component: ChalpComponent}
]
#NgModule({
declarations: [ChalpComponent],
imports: [
CommonModule,
RouterModule.forChild(routes)
]
})
export class FeatureAModule { }
chalp- a component within feature-a
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-chalp',
templateUrl: './chalp.component.html',
styleUrls: ['./chalp.component.css']
})
export class ChalpComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}
chalp markup
<p>chalp works!</p>
<a routerLink="../">Go back one</a>
The answer is cleaner:
use lazily loaded feature modules.
// root module routing:
router.forRoot([
// this is what ng documentation suggests
{
path: 'admin',
loadChildren: () => import('./items/items.module').then(m => m.ItemsModule)
},
each of these unique route prefixes
existing already in our bloated application.
now is stored and carefully imported depending
on when the contained resources are required
by the user.
...
])
//then in each feature modules' routing module
router.forChild([
// treat the first word as root, so url is not admin/admin!
{ path: '', component: AdminComponent,
children: [
/*All urls in our app which
have 'admin' prefix*/
]
}
]
Two big lessons out of this excursion into typescript:
always know the framework and the way its designed before using it.
not only do the feature modules handle imports and routing, they also each import
a shared module called util which houses the service main module, all types and interfaces, componentry, pipes and directives that the whole app uses.
In the future, knowing this will help me better design applications. The core app is what
all our feature modules plug into and what gets bootstrapped when the application is served. Now there is a unified structure to how imports and exports are structured, and
you never have a question about how to get to a service or interface.

Angular 7 with adding new component 'the server component' isn't appear in browser when I add a component tag?

It is first time To use Angular Now I'm learning angular 7:
- I create a new custom component in
- |src folder
---| app
----|| server (name of my component)
then I added in app.component.html the name of component
I see in the tutorial show in browser
the server component
even if he add it empty element
I do all steps in
server.component.ts file
import { Component } from '#angular/core';
#Component({
selector:'app-server',
templateUrl: './server.component.html'
})
export class ServerComponent {
}
& app.module.ts file
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
import { ServerComponent } from './server/server.component';
#NgModule({
declarations: [
AppComponent,
ServerComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Have you define your <app-server></app-server> somewhere?
For instance in the app.component.html
<app-navbar></app-navbar>
<app-server></app-server>
<app-footer></app-footer>
Also you will find an example here : https://angular.io/tutorial/toh-pt1
In your app.component.html add :
<app-server></app-server>
Thus you'll see its HTML.
What you did is in fact kind of import it and make it visible to other components declared in AppModule, but you didnt call it actually.

Angular UrlResolver is not overridden by custom provider

I have an Angular application in which I'd like to use a custom UrlResolver provider in order to add some cache breaking logic, as seen in this question (https://stackoverflow.com/a/43289767/868914).
However it doesn't seem that I can override the default compiler UrlResolver using a provider, as I would normally do and as the above link suggests.
Here is a plunker showing what I mean: https://plnkr.co/edit/zFsdyfNIoPcmbLO7WafW?p=preview
If you use the chrome (or other good) dev tools debugger to view the source for compiler.umd.js and search for the UrlResolver and put a break in the 'resolve' method, you can see the default implementation is being used instead of my provided class.
I cannot find a reason for this, hopefully someone on here knows a reason / solution?
Heres app.module code (as seen on the plunkr also)
//our root app component
import {Component, NgModule, VERSION} from '#angular/core';
import {BrowserModule} from '#angular/platform-browser';
import { UrlResolver } from "#angular/compiler";
#Component({
selector: 'my-app',
templateUrl: 'my-app.html',
})
export class App {
name:string;
constructor() {
this.name = `Angular! v${VERSION.full}`
}
}
class NewUrlResolver extends UrlResolver {
resolve(baseUrl: string, url: string): string {
console.log("Custom resolve");
return "rubbish";
}
}
#NgModule({
imports: [ BrowserModule ],
providers: [{
provide: UrlResolver, useClass: NewUrlResolver
}]
declarations: [ App ],
bootstrap: [ App ]
})
export class AppModule {}
You should provide your custom UrlResolver as part of providers in CompilerOptions when bootstraping application:
platformBrowserDynamic().bootstrapModule(AppModule, {
providers: [{ provide: UrlResolver, useClass: NewUrlResolver
}]})
Plunker Example

Angular2 "No provider for Service!" error when provider is added #NgModule

I have an app module and single component application (made to demonstrate my problem), and getting following error:
Error in ./AppComponent class AppComponent_Host - inline template:0:0 caused by: No provider for UserService! ; Zone: <root> ; Task: Promise.then ; Value:
code for AppModule:
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { UserService } from './components/common/userservice';
#NgModule({
imports: [
BrowserModule,
],
declarations: [
AppComponent
],
providers: [UserService],
bootstrap: [AppComponent],
entryComponents: []
})
export class AppModule {
}
Code for my AppComponent:
import { Component} from '#angular/core';
import { UserService} from './userservice';
#Component({
selector: 'App',
template: `<h3>App component</h3>
user name: {{userName}}
`,
providers: []
})
export class AppComponent {
userName: string;
constructor(userService: UserService) {
this.userName = userService.userName;
}
}
My UserService Code:
import { Injectable, EventEmitter } from '#angular/core';
#Injectable()
export class UserService {
obs$: EventEmitter<any> = new EventEmitter<any>()
userName = 'Sherlock Holmes';
}
Now if i add UserService as provider to AppComponent, it will solve the issue. but i dont want to, because i want only one instance of my service in whole application. Even in subModules(feature modules).
according to my understanding, if i add service as provider on module level, then i can just inject it to any component under module.
here is am example i was watching.
Plunker
am using angular2 version: "2.0.0"
The import path is wrong: you use /Common in one and /common right below.
Visual Studio and WebStorm will not show IntelliSense errors for case-sensitivity of paths.
Furthermore, if using Angular 5's AoT template compilation, you can get a "This component is not part of a module" error, even though it is, because the import path is incorrect. Without AoT this will work, so you'll get a surprise when converting to AoT.
Remove your service: UserService from app.module.ts, then add in component:
#Component({
selector: 'App',
template: `<h3>App component</h3>
user name: {{userName}}
`,
providers: [UserService]
})
Hope this will help you.
An additional reason for getting this error - I duplicated a service to a different directory and was updating each file individually. Even though the first file still existed I got this error until I updated app.module.ts.

Angular 2 - How to pass URL parameters?

I have created a single page mortgage calculator application in Angular 2, which acts like a learning playground for me (trying to get more accustomed to technology stack currently used at work)... It's running at http://www.mortgagecalculator123.com if you want to look at it. I've made it open source with a Fork Me link right on the page if you want to look at it.
Anyhow, what I want to do, is to be able to pass variables to my app, straight from the URL, so they can be consumed by my Angular 2 app. Something like this: http://www.mortgagecalculator123.com/?var1=ABC&var2=DEF
I've tried following, in my app.component.ts, I've added following:
import { Router, ActivatedRoute, Params } from '#angular/router';
AppComponent {
private var1: string;
private var2: string;
constructor(
private route: ActivatedRoute,
private router: Router
) {}
ngOnInit() {
this.route.params.forEach((params: Params) => {
this.var1 = params['var1'];
this.var2 = params['var2'];
});
console.log(this.var1, this.var2);
}
...
}
But this won't work, when I run npm start, I get following error:
aot/app/app.component.ngfactory.ts(45,30): error TS2346: Supplied parameters do not match any signature of call target.
Thank you, any help would be much appreciated.
I created a pull request with the query params working. I will try to explain everything I did.
The reason why the previous answers doesn't work is because you aren't using the router at all. You created a massive app component without routes. To fix that we need to start using the route module, I also advise you to read these two tutorials: Routing and Routing & Navigation.
First we need to change your index.html, add this to your <head>:
<base href="/">
See here why it's important to add that.
Then since you are using your AppComponent to show everything we need to create a new component, which we will call RootComponent. On your index.html change <my-app> to <root>; it will look like this:
<root>Loading...</root>
Now inside your app folder we need to create two files the first one will be root.component.ts which will look like this:
import { Component } from '#angular/core';
#Component({
selector: 'root',
template: `<router-outlet></router-outlet>`,
})
export class RootComponent {
constructor() { }
}
Look that we have the <router-outlet></router-outlet> as a template, Angular will inject our components based on the route.
We still need to create one more file, which will be main.route.ts, this is what it looks like:
import { Routes, RouterModule } from '#angular/router';
import { AppComponent } from './app.component';
export const mainRoutes: Routes = [
{ path: '', component: AppComponent }
];
export const mainRoutingProviders: any[] = [];
export const routing = RouterModule.forRoot(mainRoutes);
In this file we are saying that for our base route, we want to render our AppComponent
We have created our new files, now we need to tell our App Module about them, in your app.module.ts so we import the new files and declare the new component. We also need to change our boostrap component:
import {NgModule} from '#angular/core';
import {BrowserModule} from '#angular/platform-browser';
import {FormsModule, ReactiveFormsModule} from "#angular/forms";
import {AppComponent} from './app.component';
import {RootComponent} from './root.component'; // we import our new RootComponent
import {ChartModule} from 'primeng/primeng';
import {TooltipModule} from 'primeng/primeng';
import { routing, mainRoutingProviders } from './main.routes'; // We also import our Routes
#NgModule({
imports: [
BrowserModule,
ChartModule,
FormsModule,
mainRoutingProviders, // we also need to import our route provider into the module
ReactiveFormsModule,
routing, // and also import our routes declarations
TooltipModule
],
declarations: [AppComponent, RootComponent], // we declare our new RootCpmponent
bootstrap: [RootComponent] // Notice that we are now using our RootComponent to bootstrap our app
})
export class AppModule {
}
Now with all this in place we can now finally start passing parameters to our app, on your AppComponent import the Router, ActivatedRoute and the Params from #angular/router so your AppComponent will look something like this:
import { Component, OnDestroy, OnInit } from '#angular/core';
import { Router, ActivatedRoute, Params } from '#angular/router';
import { Subscription } from 'rxjs/Subscription';
export class AppComponent implements OnInit, OnDestroy {
private var1: string;
private var2: string;
private sub: Subscription;
constructor(
private route: ActivatedRoute,
private router: Router
) {}
ngOnInit() {
// assign the subscription to a variable so we can unsubscribe to prevent memory leaks
this.sub = this.route.queryParams.subscribe((params: Params) => {
this.var1 = params['var1'];
this.var2 = params['var2'];
console.log(this.var1, this.var2);
});
}
ngOnDestroy() {
this.sub.unsubscribe();
}
...
}
You can see the pull request here
It seems you are dealing with Queryparams . So to access them, you can try below code,
this.var1= this.route
.queryParams
.map(params => params['var1']);

Categories

Resources