I am new in angular 6, I am creating the project using angular 6. I am coming to the problem while sharing the data.
Here is my code:
1) Component Sidebar:
selectedCategory(type:any) {
this.loginService.categoryType = type; // need to pass this data
}
2) List Comp:
export class ListPostsComponent implements OnInit {
ngOnInit() {
// here I need the data
}
}
3) Service:
export class LoginService {
categoryType:any;
}
In your service make categoryType a Subject and call the next() when you need to pass data to another component:
#Injectable({
providedIn: 'root',
})
export class LoginService {
private categoryType: Subject<any> = new Subject<any>();
public categoryType$ = this.categoryType.asObservable();
public sendData(data: any){
this.categoryType.next(data);
}
}
Now in your Component Sidebar, you need to inject the service LoginService and call the sendData method:
constructor(private loginService: LoginService ){ }
selectedCategory(type:any) {
this.loginService.sendData(type);
}
Since a Subject is both an Observer and an Observable you can subscribe to the Subject and listen for changes in the component you wish to receive the data:
export class ListPostsComponent implements OnInit {
constructor(private loginService: LoginService ){ }
ngOnInit() {
this.loginService.categoryType$.subscribe((data) => {
//use your data here
});
}
}
Here is a working example of the above solution in Stackblitz: https://stackblitz.com/edit/angular-2sld4k?file=src%2Fapp%2Floginservice.service.ts
Related
i want find the params in previous route in angular typescript .
i use this code :
private previousUrl: string = undefined;
private currentUrl: string = undefined;
constructor(private router: Router) {
this.currentUrl = this.router.url;
router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
this.previousUrl = event.url;
this.currentUrl = this.currentUrl;
}
});
}
but i can not access to the params of this url :
http://localhost:4200/claims-manager/200/edit
i want ti access 200 . how can i find params in url ????
You can do it in your component file but It is a best practice to do it in a service (using rxjs) to pass data and call it in your component file
In your service
export class myService {
constructor() { }
private param = new BehaviorSubject("");
sharedParam = this.param.asObservable();
paramToPass(param:string) {
this.param.next(param)}
}
In your component class that set param
export class ComponentSetParam {
param: string
constructor(private myService: Service)
this.myService.setParam(this.param);
}
in your appModule
#NgModule({
declarations: [YourComponents]
imports: [ AppRoutingModule, YourModules...],
providers: [ShareService],
})
export class AppModule {}
Component that you want to pass data
export class ComponentGetParam {
paramFromService: string
constructor(private myService: Service) {
this.shareService.sharedData.subscribe(data : string => {
this.paramFromService = data;
})
}
}
Try this:
readonly _destroy$: ReplaySubject<boolean> = new ReplaySubject<boolean>(1);
constructor(
private activatedRoute: ActivatedRoute,
) {
this.activatedRoute.parent.paramMap
.pipe(
distinctUntilChanged(),
takeUntil(this._destroy$)
)
.subscribe((params: ParamMap) => {
const id = params.get('id');
});
}
ngOnDestroy() {
this._destroy$.next(true);
this._destroy$.complete();
}
Where 'id' is a name, that you use in the routing, e.g.
path: '/claims-manager/:id/'
Demo You can do it in service
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs';
#Injectable()
export class ShareService {
constructor() { }
private paramSource = new BehaviorSubject("");
sharedData = this.paramSource.asObservable();
setParam(param:string) { this.paramSource.next(param)}
}
in constructors
constructor(private shareService: ShareService)
in component in ngOnDestroy set this like this.shareService.setParam(param);
in appmodule
providers:[ShareService ]
in new component in ngOnInit or in constructor get like
this.shareService.sharedData.subscribe(data=> { console.log(data); })
I am can't get my Angular template to update after i sent out a postrequest,
Here's the component:
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'example',
templateUrl: './example',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ExampleComponent implements AfterViewInit, OnInit {
public mailResult: String;
constructor(private apiService: ApiService) {
this.mailResult = 'notsent'; //updating in template
}
onSubmit() {
this.mailResult = 'pending'; // updating in template
this.apiService.testPostRequest().subscribe((res)=>{
console.log("res", res); // working fine loging res
this.mailResult = 'requestsucess'; // not update in template
});
}
}
and that's the template:
<div class="example-component">
<h1>stateTest {{this.mailResult}}</h1>
</div>
and the apiService
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { of } from 'rxjs';
#Injectable()
export class ApiService {
constructor(private http: HttpClient) {}
testPostRequest () {
return this.http.post('http://localhost:1337/email', {});
}
}
All I need is to update this.mailResult in my Template after the request was successful, all is working fine, but the value in the template just won't update after the request. Any Ideas where the Issue might be hidden?
It's not working because you have your component's change detection set to 'onPush' and mailResult is not decorated with #Input (which it obviously shouldn't).
So, to fix this, you first need to add a changeDetector to your class:
constructor(private apiService: ApiService, private changeDetector: ChangeDetectorRef) {
this.mailResult = 'notsent'; //updating in template
}
And then you use that changeDetector's markForCheck function to let angular know that something has changed and it needs to update the view:
this.apiService.testPostRequest().subscribe((res)=>{
console.log("res", res); // working fine loging res
this.mailResult = 'requestsucess'; // not update in template
this.changeDetector.markForCheck();
});
I created a directive in Angular 6 named 'DeleteDirective' and reference to a service 'DeleteService' to make sure I can delete an item from my application. After the item is marked as deleted (in PHP back-end), I'll show an Undo element via the 'UndoComponent' that I dynamically added in the DeleteService. No problems so far.
#Directive({
selector: '[appDelete]'
})
export class DeleteDirective {
constructor(
#Inject(ViewContainerRef) viewContainerRef,
renderer: Renderer2
) {
service.renderer = renderer;
service.setRootViewContainerRef(viewContainerRef);
service.addUndoElement();
}
#HostListener('click') onClick() {
// (Some code to execute deletion)
this.deleteService.showUndoElement();
}
#Injectable({
providedIn: 'root'
})
export class DeleteService {
constructor(
rendererFactory: RendererFactory2,
private factoryResolver: ComponentFactoryResolver,
private appRef: ApplicationRef,
) {
this.renderer = rendererFactory.createRenderer(null, null);
this.factoryResolver = factoryResolver;
}
setRootViewContainerRef(viewContainerRef) {
this.rootViewContainer = viewContainerRef;
}
addUndoElement() {
const factory = this.factoryResolver.resolveComponentFactory(UndoComponent);
const component = factory.create(this.rootViewContainer);
// this.rootViewContainer.insert(component.hostView);
this.appRef.attachView(component.hostView);
const domElem = (component.hostView as EmbeddedViewRef<any>)
.rootNodes[0] as HTMLElement;
document.body.appendChild(domElem);
}
}
Now, in the UndoComponent HTML I created a link to undo the action, named restoreItem. I would like to use another service named ListService to get some data again.
#Injectable()
export class UndoComponent implements OnInit {
constructor(private listService: ListService) {
}
restoreItem() {
this.currentList = this.listService.getSelectedList();
console.log(this.currentList); // null
}
}
It seems I cannot reference to the ListService (or any other service) from this dynamically added component to the DOM. It returns null. Any ideas how I can access a service from a dynamically added Component? Thanks so much for any directions!
Edit: added Listservice stub code for clarification
#Injectable({
providedIn: 'root'
})
export class ListService {
lists: List[];
list: List[];
currentList: List;
constructor(private http: HttpClient) { }
setSelectedList(list: List): void {
this.currentList = list;
}
getSelectedList(): List {
return this.currentList;
}
private handleError(error: HttpErrorResponse) {
console.log(error);
return throwError('Error! something went wrong.');
}
}
Are you setting the value of currentList in ListService in anyway.
setSelectedList in ListService is never called which is being used to set value of currentList. So currentList remains null.
I have encountered a project in progress, let multiple unrelated components notify each other of the update data, is there a cleaner coding method?
There are 3 components (more likely later) and a common-data component. They have no parent-child relationship with each other and only show on the same screen.
The desired effect is to press the button of any component, update the contents of common-data, and notify yourself and other components to fetch new messages from common-data.
At present, my approach is to use Rx's Observable and Subscription, but they must be imported in the component.ts and service.ts files of each component, and a lot of duplicate code appears, it is very messy, I don't know what is better. practice?
Thanks!
My code :
The sample name is test-a-comp (a.b.c and so on, the code is the same)
test-a-comp.html
<p>
{{ownMessage}}
</p>
<button (click)="sendChange()">update</button>
test-a-comp.component
import { Component, OnInit } from '#angular/core';
import { Subscription } from 'rxjs/Subscription';
import { CommonData } from '../common-data/common-data';
import { TestACompService } from './test-a-comp.service';
import { TestBCompService } from '../test-b-comp/test-b-comp.service';
import { TestCCompService } from '../test-c-comp/test-c-comp.service';
#Component({
selector: 'app-test-a-comp',
templateUrl: './test-a-comp.component.html',
styleUrls: ['./test-a-comp.component.css']
})
export class TestACompComponent implements OnInit {
subscription: Subscription;
ownMessage;
constructor(
private testAService: TestACompService,
private testBService: TestBCompService,
private testCService: TestCCompService,
) {
this.subscription = this.testAService.getMessage()
.subscribe((test) => {
CommonData.message = test;
});
this.subscription = this.testBService.getMessage()
.subscribe(() => {
this.ownMessage = CommonData.message;
});
this.subscription = this.testCService.getMessage()
.subscribe(() => {
this.ownMessage = CommonData.message;
});
}
ngOnInit() {
}
sendChange() {
this.testAService.sendMessage();
}
}
test-a-comp.service:
import { Injectable } from '#angular/core';
import {Subject} from 'rxjs/Subject';
import {Observable} from 'rxjs/Observable';
import {Subscription} from 'rxjs/Subscription';
#Injectable()
export class TestACompService {
subscription: Subscription;
private subject = new Subject<any>();
constructor() {
}
getMessage(): Observable<any> {
return this.subject.asObservable();
}
sendMessage(): void {
this.subject.next('update message from A');
}
}
As far as i understand & you've mentioned in the above, there is a button in one of the component (test-a-component.html). If you update the button, you need to send message to other components which are subscribed.
The Components which have no Parent-Child relationship can communicate via a service:
Create a single service file (In your case: test-a-comp.service)
Create a Subject on what data you need to communicate via this service:
export class testMessageService {
constructor() {}
// Observable string sources
private message = new Subject<string>();
//Observable string streams
testMessage$ = this.message.asObservable();
constructor() {}
// Method to send message when a button is clicked
sendMessage(message: string) {
this.message.next(message);
}
/* You don't need "getMessage()" method as you've already subscribed to
the observables. There subscribed Observable string streams are
injected in your components (As below point 3) to display / do other
operation on the message. */
}
In your other Components, where you want to receive messages, do the following:
export class TestComponent 1 {
myMessage1: string;
constructor(private TestMessageService: testMessageService) {}
TestMessageService.testMessage$.subscribe(message => {
this.myMessage1 = message;
});
}
export class TestComponent 2 {
myMessage2: string;
constructor(private TestMessageService: testMessageService) {}
TestMessageService.testMessage$.subscribe(message => {
this.myMessage2 = message;
});
}
export class TestComponent 3 {
myMessage3: string;
constructor(private TestMessageService: testMessageService) {}
TestMessageService.testMessage$.subscribe(message => {
this.myMessage3 = message;
});
}
For more information/guidance refer Component interaction via a common
service: https://angular.io/guide/component-interaction
Hope this helps!
My target is to send data from Angular component to service and use service methods to work on it. Example:
export class SomeComponent {
public data: Array<any> = MyData;
public constructor(private myService: MyService) {
this.myService.data = this.data;
}
}
and service:
#Injectable()
export class TablePageService {
public data: Array<any>;
constructor() {
console.log(this.data);
// undefined
}
}
Getting data is undefined. How to make it works?
An example if interaction between service and component could be:
Service:
#Injectable()
export class MyService {
myMethod$: Observable<any>;
private myMethodSubject = new Subject<any>();
constructor() {
this.myMethod$ = this.myMethodSubject.asObservable();
}
myMethod(data) {
console.log(data); // I have data! Let's return it so subscribers can use it!
// we can do stuff with data if we want
this.myMethodSubject.next(data);
}
}
Component1 (sender):
export class SomeComponent {
public data: Array<any> = MyData;
public constructor(private myService: MyService) {
this.myService.myMethod(this.data);
}
}
Component2 (receiver):
export class SomeComponent2 {
public data: Array<any> = MyData;
public constructor(private myService: MyService) {
this.myService.myMethod$.subscribe((data) => {
this.data = data; // And he have data here too!
}
);
}
}
Explanation:
MyService is managing the data. You can still do stuff with data if you want, but is better to leave that to Component2.
Basically MyService receives data from Component1 and sends it to whoever is subscribed to the method myMethod().
Component1 is sending data to the MyService and that's all he does.
Component2 is subscribed to the myMethod() so each time myMethod() get called, Component2 will listen and get whatever myMethod() is returning.
There is a small issue with the receiver component in #SrAxi s reply as it can't subscribe to the service data. Consider using BehaviorSubject instead of Subject. It worked for me!
private myMethodSubject = new BehaviorSubject<any>("");