I want to make GET by web app on angular dart, but I have error in console when I try to open page with app:
Uncaught Error: Invalid argument(s): No provider found for Client0.
And this entrypoint
void main() {
bootstrap(AppComponent, [BrowserClient]);
}
And I have only one component from and one default component, because I use AngularDart Web App - a web app with material design component template from Web Storm:
#Component(
selector: 'watch-counter',
styleUrls: const [
'package:angular_components/app_layout/layout.scss.css',
'watch_counter_component.css'],
templateUrl: 'watch_counter_component.html',
directives: const [
CORE_DIRECTIVES,
materialDirectives,
],
providers: const [UserService]
)
class WatchCounterComponent implements OnInit {
final UserService userService;
WatchCounterComponent(this.userService);
int tabIndex = 0;
void onTabChange(TabChangeEvent event) {
tabIndex = event.newIndex;
}
final loginModalTabs = const<String>[
'Login',
'Registration'
];
#override
Future<Null> ngOnInit() async {
}
}
And with this service
#Injectable()
class UserService {
final Client http;
UserService(this.http);
dynamic extractData(Response resp) => JSON.decode(resp.body)['data'];
Future login(String login, String password) async {
print("login");
}
void register() {
print("register");
}
}
All failings when I add http Client into service.
You are providing BrowserClient but injecting a Client.
Change your bootstrap to:
bootstrap(AppComponent, [
provide(Client, useClass: BrowserClient),
]);
I don't believe BrowserClient is marked with #Injectable(), so you might need:
bootstrap(AppComponent, [
provide(Client, useFactory: () => new BrowserClient()),
]);
Or add in the bootstrap (or the Componente providers list):
const clientProvider = [
ClassProvider(Client, useClass: BrowserClient),
];
Related
This ABCService class perform some initialization on service startup
class ABCService {
public init() : void {
some stuff...
}
export const service = new ABCService();
I am using this class as loader
import { MicroframeworkLoader, MicroframeworkSettings } from 'microframework-w3tec';
import { service } from '../ABCService';
export const serviceLoader: MicroframeworkLoader = (settings: MicroframeworkSettings | undefined) => {
service.init();
};
I am using this serviceLoader in bootstrapMicroframework loaders of APP.ts file.
bootstrapMicroframework({
loaders: [
serviceLoader
],
}).then(() => ... )
.catch(error => log.error('Application is crashed: ' + error));
Now I have another Service class annotated with #Service
#Service()
export public class XYZService {
constructor(private userRepository: UserRepository, private dependency2: Dependency2){
}
public doSomeThing(): Promise<any> {
....
....
}
}
I want to inject this XYZService class in ABCService with all dependencies in XYZService being injected by the container. How can I achieve that?
I got to know that It's possible to get an instance of a service class in a non service classes using typedi's
Container.get<ServiceClassType>(ServiceClassType);
I'm trying to create a service to share the data between two components. I injected the service into root module to make it accessible throughout the application by doing DI into the root module provider. My code looks roughly like this.
Service
#Injectable(){
export class ForumService{
forum: any;
setForum(object){
this.forum = object;
}
getForum(){
return this.forum;
}
}
Root Module
.......
import { ForumService } from 'forumservice';
.......
#NgModule({
declarations: [.....],
imports: [.....],
providers: [....., ForumService],
bootstrap: [AppComponent]
})
export class AppModule{}
Component One
//A bunch of import statements
import { ForumService } from 'forumservice'; //Without this Angular throws a compilation error
#Component({
selector: 'app-general-discussion',
templateUrl: './general-discussion.component.html',
styleUrls: ['./general-discussion.component.css'],
providers: [GeneralDiscussionService] //Not injecting ForumService again
})
export class GeneralDiscussionComponent implements OnInit{
constructor(private forumService: ForumService){}
ngOnInit(){
helperFunction();
}
helperFunction(){
//Get data from backend and set it to the ForumService
this.forumService.forum = data;
console.log(this.forumService.forum); //prints the data, not undefined
}
}
Component Two
//A bunch of import statements
import { ForumService } from 'forumservice'; //Without this Angular throws a compilation error
#Component({
selector: 'app-forum',
templateUrl: './forum.component.html',
styleUrls: ['./forum.component.css'],
providers: []
})
export class ForumComponent implements OnInit {
forumData: any;
constructor(private forumService: ForumService){}
ngOnInit(){
this.forumData = this.forumService.forum; // returns undefined
}
}
Once I navigate from Component One to Component Two I'm expecting "This is a string". However I get undefined. Is it because of the import statements in the component? If I remove that I see a compilation error saying that ForumService is not found.
Instead of using getter and setter, use the object (not primitibe such as string) directly In your components.
Your service
#Injectable(){
export class ForumService{
forum:any = {name:string};
}
Component one
export class GeneralDiscussionComponent implements OnInit{
constructor(private forumService: ForumService){}
ngOnInit(){
this.forumService.forum.name="This is a string";
}
}
Component two
export class ForumComponent implements OnInit {
// forumTitle: string; // do not need this anymore
forum:any; // use the forum.name property in your html
constructor(private forumService: ForumService){}
ngOnInit(){
this.forum = this.forumService.forum; // use the
}
}
I know encapsulating is preferable, and with your current code you are probably encountering some timing problems. But when working with shared data in a service you can two-way bind the variable like above, and your components will be in sync.
EDIT:
Also an important notice, the variable you want to sync between components needs to be an object. instead of forumTitle:string, make it forumTitle:any = {subject:string} or something similar.
Otherwise you need to make your components as listeners for data when data changes in your service.
I'd use BehaviorSubject in this case, should be something like that:
#Injectable(){
export class ForumService{
private _forum: BehaviorSubject<any> = new BehaviorSubject<any>(null);
public forum: Observable<any> = this._forum.asObservable();
setForum(object){
this._forum.next(object);
}
}
Then just bind it in template with async pipe: {{forumService.forum|async}} or subscribe to it.
I would like to have custom errors in my Angular2 app. Thus I have extended ErrorHandler in my component:
import { Component, ErrorHandler, OnInit } from '#angular/core';
import { GenericError } from './generic-error.component';
#Component({
selector: 'custom-error-handler',
templateUrl: 'app/error-handler/custom-error-handler.component.html?' + +new Date()
})
export class CustomErrorHandler extends ErrorHandler {
errorText: string;
constructor() {
super(false);
}
ngOnInit() {
this.errorText = 'Initial text!';
}
public handleError(error: any): void {
if (error.originalError instanceof GenericError) {
console.info('This is printed to console!');
this.errorText = "I want it to print this in the template!";
}
else {
super.handleError(error);
}
}
}
My template simply contains:
<span style="color:red">{{errorText}}</span>
First I see "Initial text!" in the template as set in ngOnInit. That's as expected.
I can then throw a new exception like this from a different component:
throw new GenericError();
and it hits the code with handleError and prints to console but it doesn't update my template errorText with:
"I want it to print this in the template!"
It's like it ignores my template, when inside the handleError function.
What could be the problem here?
* ADDED MORE INFORMATION *
I thought I should add some more information. So here is the module I made for CustomErrorHandler (maybe the problem is with the providers?):
import { NgModule, ErrorHandler } from '#angular/core';
import { CommonModule } from '#angular/common';
import { CustomErrorHandler } from './custom-error-handler.component';
#NgModule({
declarations: [
CustomErrorHandler
],
imports: [
CommonModule
],
exports: [
CustomErrorHandler
],
providers: [
{ provide: ErrorHandler, useClass: CustomErrorHandler }
]
})
export class CustomErrorModule { }
There is indeed only one instance of the CustomErrorHandler (I checked with the Augury Chrome plugin).
For completeness, here is is the GenericError component:
export class GenericError {
toString() {
return "Here is a generic error message";
}
}
The solution was to add a service as suggested in the question's comment track. This way I can set the property in the component and eventually show it in the template.
I created the service, so that it has a function which takes one parameter. Injected the service, call the service's function from the handleError in the component function, and send the text I want in the template as the parameter. Then I use an observable, to get the text back to the component.
In the constructor of the component, I added this observer.
let whatever = this.cs.nameChange.subscribe((value) => {
setTimeout(() => this.errorText = value);
});
I needed to add the setTimeout, or else it would not update the template before the second time the observable was changed.
Phew! The Angular team should make this global exception handling easier in future releases.
I am having a hard time using a async object in a html composition.
Here is my model:
export class Version {
isGood: boolean;
constructor(isGood: boolean) {
this.isGood= isGood;
}
}
This model is called by a component as follows:
#Injectable()
export class MyComponent {
public version: Version;
constructor(private _myService: VersionService) {}
getVersion(): void {
// async service that gets the versions
this._myService.getVersion().subscribe(
data => this.version= data,
error=> console.log(error),
() => console.log("getting all items complete")
);
}
}
My template references to the version variable as follows:
<button (click)="getVersion()">Get Version</button>
<hr>
<p style="color:red">{{error}}</p>
<h1>Version</h1>
<p>{{version.isGood}}</p>
However, I get an exception:
Cannot read property 'isGood' of undefined
From scavenging the internet, I see that my problem is because the version object is null. If I do something like:
<p>{{version | json}}</p>
I can see the correct version
If I do something like
<p>{{version.isGood | async}}</p>
I see nothing
If I edit MyComponent, and set
public version: Version = new Version();
I can execute the .isGood property fetch, but it is always empty.
Is there a different way I am supposed to load a property if I am using it in an asynchronous manner?
Use the ? operator or use an *ngIf.
<p>{{version?.isGood}}</p>
<p *ngIf="version">{{version.isGood}}</p>
Try this:
<p>{{version?.isGood}}</p>
This tells Angular to protect against version.isGood being undefined or null until you click and fetch the data for version through your service.
First me correct you. #Injectable() makes a normal typescript class as injectable service where you can share data.
To make a component you need to use #Component decoratore.
The process of data sharing between component and within the application is to create a service and add that as provides in module. And then its singleton object will available everyshere.
//module
import {NgModule} from '#angular/core';
import {YourService} from "./services/your-service";
#NgModule({
imports: [
BrowserModule
],
declarations: [
AppComponent
],
providers: [
YouService
],
bootstrap: [AppComponent]
})
export class AppModule {
}
//this is your component
import {Component} from '#angular/core';
import {YourService} from "../../services/your-service";
#Component({
selector: 'component-app',
templateUrl: '../../views/app.component.html',
})
export class HeaderComponent {
constructor(public yourService: YourService) {
}
}
//your service
import {Injectable} from "#angular/core";
#Injectable()
export class YourService {
private _message: string = 'initial message';
private _style: string = 'success';
get message(): string {
return this._message;
}
set message(value: string) {
this._message += value;
}
get style(): string {
return this._style;
}
set style(value: string) {
this._style = value;
}
}
//finally your view
<div class="row">
<div [class]=""><h1>{{swapService.message}}</h1></div>
</div>
Observable Data services.
#Injectable()
export class MyComponent {
public version = new ReplaySubject<Version>();
constructor(private _myService: VersionService) {}
init(): void {
// async service that gets the versions
this._myService.getVersion().subscribe(
data => this.version.next(data),
error=> console.log(error),
() => console.log("getting all items complete")
);
}
getVersion(): void {
this.version.asObservable();
}
}
In the template
<button (click)="init()">Get Version</button>
<hr>
<p style="color:red">{{error}}</p>
<h1>Version</h1>
<p>{{(version |async)?.isGood}}</p>
Until RC5 we could declare providers at component level like this:
#Component({
providers: [SomeService]
})
And every component would get a new instance of SomeService, but now with RC5 the component providers as been deprecated so how we achieve this effect?
One way would be to add a factory method to your service that returns a new instance.
export class SomeService {
constructor(private http: Http) {}
create() {
return new SomeService(this.http);
}
}
That is very much a hack and requires you to call create in your components.
It seems the subscribed solution is to use a Factory Provider.
Essentially you create factory method and provider object:
import { Http } from '#angular2/core';
import { SomeService } from './SomeService';
let someServiceFactory = (http: Http) => {
return new SomeService(http);
};
export let SomeServiceProvider =
{ provide: SomeService,
useFactory: someServiceFactory,
deps: [Http]
};
So now you inject SomeService as you did before, and you will always get a new transient instance.
Import the provider into your module or component and register it as providers: [someServiceProvider]
Or inline it as:
providers: [{
provide: SomeService,
useFactory: (http: Http) => { return new SomeService(http)},
deps: [Http]
}]
According to the quick start here services have not really changed. Still need the 4 core things
A service is created via injectable
2.import that service into component
3.provide that service
4 and construct it in the export