https://angular.io/guide/architecture#services
I'm following the docs on angular.io to inject dependencies like services, etc. I did everything they said and when I try to run it, the console keeps telling me:
Uncaught ReferenceError: LedgerService is not defined
I am doing nothing crazy except creating a simple component with a service where both constructors have console.log commands (constructors in both the component and service). I've done everything Angular says to do in their 2 paragraphs that details this feature of Angular.
The component itself is being injected into the main app module (with the service being injected into the component) and both the component and service were created with the Angular CLI. So there isn't much I've even done at all minus trying to inject the service. So I'm not sure where it is going wrong but it is definitely not working and just shows a blank page (when it previously had basic content by default).
I created both units, tried to specify providers in both the app.module and the component.ts file and neither works and yields the same error--when Angular claims either could work. I've also specified it as a private service within the constructor of the component.ts file.
Everything I've seen relating to this is always for Angular 1 or 2. Neither of which are even remotely similar to Angular 4/5.
If you really want to see this code, fine but it's literally just framework and nothing else:
bookkeeper.component.ts:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-bookkeeper',
templateUrl: './bookkeeper.component.html',
styleUrls: ['./bookkeeper.component.css'],
providers: [LedgerServiceService]
})
export class BookkeeperComponent implements OnInit {
constructor(private service: LedgerServiceService) { }
ngOnInit() {
console.log("Ledger component works!");
}
}
app.module.ts:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
import { InterfaceComponent } from './interface/interface.component';
import { BookkeeperComponent } from './bookkeeper/bookkeeper.component';
#NgModule({
declarations: [
AppComponent,
InterfaceComponent,
BookkeeperComponent
],
imports: [
BrowserModule
],
providers: [
LedgerServiceService
],
bootstrap: [AppComponent]
})
export class AppModule { }
ledger-service.service.ts:
import { Injectable } from '#angular/core';
#Injectable()
export class LedgerServiceService {
constructor() {
console.log("wtf");
}
}
LedgerService is actually called LedgerServiceService because I initially created LedgerService manually and then tried to use the AngularCLI to generate a service and named it LedgerService and it created a service called LedgerServiceService. Naming is not what is wrong. I only initially called it simply LedgerService because I figured it would be confusing.
Your examples are missing the import.
Anywhere we use a custom type, we also need to import that type.
For that reason, in both the module and component you will need to add:
import { LedgerServiceService } from './your-path-here'
You can see this in the examples they give on https://angular.io/guide/dependency-injection
Related
I have been working on creating a service to make http requests and hence I'm using HttpClientModule given by Angular. I have data.serivce.ts file where the service is declared and I'm importing the HttpClient as shown below.
import { Injectable } from '#angular/core';
import { HttpClient} from '#angular/common/http'
#Injectable()
export class DataService {
constructor(private http:HttpClient) {
}
validateLogin(){
return this.http.get('https://someurl')
}
}
Since I'm injecting the dependency of DataService in the providers array of the app.module.ts, I don't understand why I need to import the HttpClientModule again in the app.module.ts
You should look into how angular modules work. Your app.module.ts contains AppModule which is a root module. Every application has at least one module i.e. root module. If you import any module inside your AppModule then its (imported module) components will be accessible to every component of your application.
Thats why to make HttpClient available "everywhere" in the app:
import the HttpClientModule inside AppModule.
Now you can use Services, Components etc defined inside HttpClientModule in your own services or components.
For the variable type information you use on this line
constructor(private http:HttpClient)
Without that import, there would be an error since that type would be unknown.
In the Angular docs it says that the HttpClientModule, "Configures the dependency injector for HttpClient with supporting services for XSRF." So it looks like that's why it would be a prerequisite for using the HttpClient.
https://angular.io/api/common/http/HttpClientModule#description
https://angular.io/tutorial/toh-pt6
This is driving me crazy, hopefully someone can shed some light on the problem. I am Lazy loading my Ionic components everything works fine in development, however when I go to compile AOT throws an error. I spent about 4 hours trying different ways to load this in I am lost, keep getting the same error.
From what I read and found in examples this should be correct. What am I missing here?
'tester' is not a known element: 1. If 'tester' is an Angular component, then verify that it is part of this
module. 2. To allow any element add 'NO_ERRORS_SCHEMA' to the '#NgModule.schemas' of this component. ("
<ion-list *ngIf="!id"> <ion-list-header> [ERROR -><tester></tester>
// components/tester/tester.ts
import { Component } from '#angular/core';
#Component({
selector: 'tester',
templateUrl: 'tester.html'
})
export class TesterComponent {
text: string;
constructor() {
console.log('Hello TesterComponent Component');
this.text = 'Hello World';
}
}
// components/components.module.ts
import { NgModule } from '#angular/core';
import { TesterComponent } from './tester/tester';
import {IonicModule} from "ionic-angular";
#NgModule({
declarations: [TesterComponent],
imports: [IonicModule],
exports: [TesterComponent,
]
})
export class ComponentsModule {}
// pages/faq/faq.module.ts
import { NgModule } from '#angular/core';
import { IonicPageModule } from 'ionic-angular';
import { FaqPage } from './faq';
import {ComponentsModule} from "../../components/components.module";
#NgModule({
declarations: [
FaqPage
],
imports: [
IonicPageModule.forChild(FaqPage), ComponentsModule
],
})
export class FaqPageModule {}
// pages/faq/faq.html
<tester></tester>
EDIT
Thanks to #Joel Joseph - Apparently the view needs to reside in the same directory as your parent component. I had the view .html file in a shared directory hence the problem.
templateUrl: '../shared/view/list.html'
changed to
templateUrl: 'list.html'
and it compiles fine now. Will leave this up incase anyone else has this issue.
Thanks to #Joel Joseph - Apparently the view needs to reside in the same directory as your parent component. I had the view .html file in a shared directory hence the problem.
templateUrl: '../shared/view/list.html'
changed to
templateUrl: 'list.html'
and it compiles fine now. Will leave this up incase anyone else has this issue.
In the below code from ../src/app/app.module.ts,
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
Component consists:
view(../src/app/app.component.html)
logic(../src/app/app.component.ts)
style(../src/app/app.component.css)
Angular application is a tree of components. Good components have high cohesion, i.e. each component contains only elements with related functionality. They are also well encapsulated and loosely coupled.
How modules are different from components?
A component is just a class with the #Component() annotation. Note that .html and .css files might be referenced by the component, certainly not mandatory. The component template might very well be 'inlined' directly in the component configuration, or there simply might not be any html template at all for a given component.
A module is a structural element of an Angular application (and maybe other classes and interfaces). It is also "just a class" with the #NgModule() annotation.
It acts as a logical 'container' for your components, directives, services, pipes, etc... to help you structure your overall source code better.
You can have a look at this existing question : What's the difference between an Angular component and module
A module is something that has components. It wraps them up so you can import and manage them.
Notice when you make a component you can put anything that's decorated as #Injectable in your constructor:
#Component({
selector: 'app-heroes',
templateUrl: './heroes.component.html',
styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
constructor(private myService: MyService) { }
ngOnInit() {
}
}
And magically you will have a myService to use. This is dependency injection, which is built into Angular - but it's managed on a Module level. In your module you import what other modules you want to be able to use:
imports: [
BrowserModule,
FormsModule
],
define what your module includes:
declarations: [
AppComponent,
HeroesComponent,
MyService
],
export any components (so other modules can import them)
exports: [
HeroesComponent
],
They help organize an application into blocks of functionality. Components are things that tell angular how to render something. Modules compose Components, Pipes, Services etc into 'blocks' that can be compiled by angular or imported and used by others.
Edit to address comment
Taking your specific question about HttpClient. The HttpClient is the service you are using to perform the actions. The HttpClientModule is the module you import into your module, so you can use the service it contains.
You import the module:
#NgModule({
imports: [
BrowserModule,
// Include it under 'imports' in your application module
// after BrowserModule.
HttpClientModule,
],
})
And use the service:
#Component(...)
export class MyComponent implements OnInit {
// Inject HttpClient into your component or service.
constructor(private http: HttpClient) {}
...
}
The HttpClientModule contains within it all you need for the HttpClient to work, and packages it up so you can use it in your own projects.
This particular module only wraps up that one service, but the module could contain a bunch of related services, components, pipes or directives. For example, the RouterModule allows you to use the RouterOutlet and RouterLink directives.
Module in angular is set of Components, Services, Filters, or some another smaller modules too, or we can say where you import all these in order to use later in the app for future use. in a single app there can be one or more than one module may exist.
Whereas, A component controls a patch of screen called a view.
You define a component's application logic—what it does to support the view—inside a class. The class interacts with the view through an API of properties and methods.
Refer this guide for more details:
https://angular.io/guide/architecture
I'm working on an Angular4 project and I have created a filter on my app.component.ts which I'm currently using on my app.component.html.
<button (click)="filterBy('cars')">Cars</button>
This works fine in this file by I want to use this same filter on my nav.component.html but I'd like to avoid recreating the filter code again on the nav.component.ts.
Is there a way of using this filter on my nav.component.html from app.component.ts ?
Migrate your created filter code in some new .ts file. Import this file in your app.component and other components by using import {ClassName} from file.ts syntax and then easily implement it in your component html code
You can create service, for example "filter.service.ts". Good thing in service is - it will create only one instance. So you use less memory, and app is faster.
Then - you can include it to the parent module:
import { FilterService } from "some/filter.service.ts";
#NgModule({
declarations: [ AppComponent, NavComponent],
providers: [ FilterService ]
})
export class MyModule { }
And use in your components like this:
import { FilterService } from "some/filter.service.ts";
constructor(filter: FilterService) {
this.filter = filter;
}
And then your html:
<button (click)="filter.filterBy('cars')">Cars</button>
#Injectable()
export class Service{
//create all the logic here for all the things you want to be shared across compponents
}
call this in the component you want to use like
import {Service} from "../shared/service";
#Component({
selector: 'app-angular4'
})
export class Angular4Component implements OnInit {
constructor(private service:Service) {
// resuse all the methods
}
I have an app that is structured like this.
<app>
<header>
<component-a></component-a>
</header>
<div>
<router-outlet></router-outlet>
<component-b></component-b> <!-- loaded through router -->
</div>
</app>
In component-b some data is retrieved and later set to a new object. For example, something like this..
{
infoThatComponentANeeds : true,
someMoreInfoAddedFromCompB : []
}
This info is needed for the template in component-a. At first I tried to pass the info up to component-a via #Outuput and eventEmitter using a custom event. But I was unable to get it to bubble up. I suspect that has to do with it being loaded through the router. So now I am trying to share the data between the two components using a shared service.
My Service So Far:
import {Injectable} from 'angular2/core';
#Injectable()
export class SharedService
{
public spec:Spec= null;
public getSpec()
{
return this.spec;
}
public setSpec(spec:Spec)
{
this.spec = spec;
}
}
This is how I am trying to use it in component-a:
ngDoCheck()
{
if(this._sharedService.spec)
{
this.spec= this._sharedService.getSpec();
}
}
The Problem:
After the spec is set in component-b and ngDoCheck from component-a checks to see if the spec has been set. It comes back as undefined so the getSpec() function does not run, and no spec is returned. So I am not sure what I am missing, or why it would still be undefined in my SharedService after it has been set. Should the shared service keep a reference to what was set? Or am I completely misunderstanding this concept?
I have also explored ways of sharing this data via promises/observables. However I have not had any luck with that either. And the majority of the examples I have found use HTTP, which I really do not need at this point.
Update:
Here is some more info.
Boot.ts
import {bootstrap} from 'angular2/platform/browser';
import {HTTP_PROVIDERS} from 'angular2/http';
import {
ROUTER_PROVIDERS,
APP_BASE_HREF,
Location,
LocationStrategy,
HashLocationStrategy,
PathLocationStrategy
} from 'angular2/router';
import {AppComponent} from './components/app.component';
import {SharedService} from './services/shared.service';
bootstrap(<any>AppComponent, [
ROUTER_PROVIDERS,
SharedService,
provide(LocationStrategy, {useClass: PathLocationStrategy})
]);
AppComponent.ts
import {AfterViewInit, Component, OnInit} from 'angular2/core';
import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router';
import {ComponentA} from './componentA';
#Component({
selector : 'body',
directives : [ComponentA, ROUTER_DIRECTIVES],
template : `
<app>
<header>
<component-a></component-a>
</header>
<div>
<router-outlet></router-outlet>
</div>
</app>
`
})
#RouteConfig([
{path: '/:appName/', name: 'ComponentB', component: ComponentB}
])
export class AppComponent
{
constructor(){}
}
Update 2:
Here is a plunker I created to try to isolate the issue. I removed the router stuff and simplified the whole thing. I am still seeing the same result..
https://plnkr.co/edit/kx6FWWGS1i04bH5J9DXM?p=preview
Watch the console.log()
Fixed:
This was the key.
Be sure to remove configurations in the providers attribute of your
two components.
Perhaps your service isn't actually shared. I mean you could have two instances according to the way you configured providers.
To be sure, just add the service when bootstrapping your application:
bootstrap(AppComponent, [ SharedService ]);
Be sure to remove configurations in the providers attribute of your two components.
If you're interested in hierarchical injectors of Angular2 (the concept behind this), you could have a look at this question:
What's the best way to inject one service into another in angular 2 (Beta)?