问题
My application is built this way :
- some basic components (home, login, about, ...) in my main app.module
- some other modules for each part of the application
I have a component, ToastComponent, that I may need to use everywhere. I works fine for basic components, but not for those included in a module.
I read many pages about how to share a service, however (I do not understand all I admit in angular2), I still can't figure out how to make it works in my case. (I even tried a sharedmodule but it was worse)
The issue I have is that the message given to setMessage (see end of code) is displayed in the console, but not on the screen !?!
Hope someone could point me on proper way to code it. TIA
JP
Here are the code after I revert back to a known stage (after many tries)...
The ToastComponent :
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-toast',
templateUrl: './toast.component.html',
styleUrls: ['./toast.component.css']
})
export class ToastComponent {
@Input() message = { body: '', type: '' };
setMessage(body, type, time = 5000) {
this.message.body = body;
this.message.type = type;
console.log('ToastComponent %o' , this.message);
setTimeout(() => { this.message.body = ''; }, time);
}
}
app.module
import { ToastComponent } from './_shared/toast.component';
...
import { LivresModule } from './livres/livres.module'; // where toast will be used
import { ExampleComponent } from './example.component'; // where toast is working fine
...
@NgModule({
imports: [ ... , LivresModule ],
providers: [ ToastComponent, ... ],
declarations: [ AppComponent, ToastComponent, ... ]
exports: [ ToastComponent ],
schemas: [ CUSTOM_ELEMENTS_SCHEMA ],
bootstrap: [ AppComponent ],
})
...
livres.module.ts
...
import { ToastComponent } from '../_shared/toast.component';
import { AuteursComponent } from './auteurs.component'; // where to use toast effectively
...
@NgModule({
...
providers: [ ToastComponent, ... ]
declarations: [
// ToastComponent, // error as declared twice with app.module : OK so commented
...
auteurs.component
...
import { ToastComponent } from '../_shared/toast.component';
...
constructor(private http: Http, private authorService: AuthorService,
private toast: ToastComponent ) { }
...
addAuthor() {
...
this.toast.setMessage('Auteur ajouté', 'success');
}
auteurs.component.html
...<app-toast [message]="toast.message"></app-toast>...
auteurs.component.* is a copy of a component part of app.module that works fine.
NEW INFO : I am recreating a light app that mimics the one I am building, and I had this error for the page in a module :
Unhandled Promise rejection: Template parse errors:
Can't bind to 'message' since it isn't a known property of 'app-toast'.
1. If 'app-toast' is an Angular component and it has 'message' input, then verify that it is part of this module.
2. If 'app-toast' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message.
("<app-toast [ERROR ->][message]="toast.message"></app-toast>
<p> page2 works! </p>
<button (click)="displayMsg()"> Click !"): Page2Component@0:11
That is why I added "schemas: [ CUSTOM_ELEMENTS_SCHEMA ]" (I've forgotten this), but in fact it hides an error at compile time that I have at runtime !
Converting to a service does not bring html code and css with it.
回答1:
As mentioned in comment above, shared Service might be what you need. Here is below a simple implementation of a shared service, which I hope will help you understand shared services, since you mentioned you had trouble understanding it :)
So for you you would implement this shared service where you have the setMessage
method, then in your auteurs.component
, you would inject that service in your constructor, and then you would call that method in the service when you want to change the value of the message, like so:
this.sharedService.sharedMessage = // your new message here
And just retrieve that message in all your components you need it, like:
this.message = this.sharedService.sharedMessage;
and that's how you would have access to it. But look at the example below!
Here I have implemented a parent and child component, just to show how they both are affected of changes done in either component. I've taken some to reference to your code, as the "type" and "body" you want to manipulate in you app. You could implemented it like I have in this example, that it always gets manipulated in the service, and therefore all components that use this service will have the same value as is present in the service! I'll add some step by step pictures as well :) You could make your ToastComponent
as a service where you access it from where you want :)
So first off, an interface:
export interface IShared {
body: string;
type: string;
}
In the service we set up the sharedMessage
that both components will share. We also have the method of setting new content for that sharedMessage
@Injectable()
export class SharedService {
sharedMessage;
sharedMessage: IShared = {
body: 'old body',
type: 'old type',
};
setMessage(body, type) {
this.sharedMessage.body = body;
this.sharedMessage.type = type;
}
constructor() { }
}
Your parent and child components are practically identical in this case I present. In both we have in the constructor (yes, rather do it in OnInit
though) so that we get the current value of message from the service. Here we also have method to manipulate that value. Methods that will call the method in the shared service that does the manipulation of the value. So this is actually not that difficult, once you understand it. Here follows the components and html views of both parent and child.
Your parent component:
html:
<h2>Hey, let's play with shared service!</h2>
<button (click)="setMessage('new Body', 'new Type')">Set new (parent)</button>
<h4>This message is in parent component: <b>{{message.body}}, {{message.type}}</b></h4>
<br>
<child-component></child-component>
Component:
message;
setMessage(body, type) {
this.message.body = body;
this.message.type = type;
this.sharedService.sharedMessage = this.message;
}
constructor(private sharedService: SharedService) {
this.message = this.sharedService.sharedMessage;
}
Your child component:
html:
<button (click)="setMessage('newest Body', 'newest Type')">Set newest (child)</button>
<h4>This message is in child component: <b>{{message.body}}, {{message.type}></b></h4>
Component:
message;
setMessage(body, type) {
this.message.body = body;
this.message.type = type;
this.sharedService.sharedMessage = this.message;
}
constructor(private sharedService: SharedService) {
this.message = this.sharedService.sharedMessage;
}
And lastly, let present the view of this. First off we show the value we get from the shared service upon navigating to the parent that also shows the childcomponent. So we display the current values and have buttons to manipulate the value.
Then when we click the button of the parent component, we get the new values set for both parent and child, since they share the same service.
And lastly we have clicked the child component's button :)
Hope this helps! :) :)
来源:https://stackoverflow.com/questions/41414938/how-to-use-a-shared-component-with-angular2