I am new in angular working on a project.My problem is that i want to transfer data from one component to other. Actually i want to show data in text field from database and then have to update it. I have one component name ricerca.component.ts in which data in table is showing. now when i click on specific line(row) then data for that specific record i have to show in my other component name as generatecontract.comonent.ts. I don't know how to perform this.
I made a model name ContractDblist assign all these value to that model but unfortunatelly not solved the problem in other component
this is my ricercacomponnet code
if(tag === 'Item1'){
this.router.navigate(['/workflow/rigester' ]);
}
}
public lstContractRecordDbValue :any[];
getContractRecordbyParameter(selecteditem: any, index: number) { this.workFlowService.getContractRecordbyParameter(selecteditem).subscribe(data => {
this.lstContractRecordDbValue = data;
this.contractdblist.cnt_num=this.lstContractRecordDbValue[0].CNT_NUM;
this.contractdblist.contract=this.lstContractRecordDbValue[0].CONTRACT; this.contractdblist.contacttype=this.lstContractRecordDbValue[0].CONTRACT_TYPE; this.contractdblist.contractno=this.lstContractRecordDbValue[0].CONTRACT_NO;
this.loading = false;
}, error => {
console.error('getAllTickets', error);
this.loading = false;
})
}
You can use Subject to do that
import { Injectable } from "#angular/core";
import { Subject } from "rxjs";
#Injectable()
export class MessageService {
private subject = new Subject<any>();
constructor() {}
sendMessage(message: any) {
this.subject.next(message);
}
getData() {
return this.subject.asObservable();
}
}
So you can call MessageService class method sendMessage() to send data
I defined 2 method here. The first method using next() to send message to the next subcriber. So in your component you just need to simply subscribe like this to get the data
private subscription$: Subscription;
public ngOnInit(): void {
this.subscription$ = this.messageervice
.getData()
.subscribe(data => { console.log(data); })
}
public ngOnDestroy(): void {
this.subscription$.unsubscribe();
}
There are many ways to do so some of them are
using input decorator when passing data from parent to child component.
using output decorator with event emitter when passing data from child to parent component.
using subjects for components not related to each other.
using a service to set and get data to be passed.
you can refer their official website for all the above ways.
Related
I want to send message from ComponentA to ComponentB. And I am using service for that. Here is the code-
My problem is if I call sendInfoToB() from componentA's html file (event hooked to a button click), then I'm recieving the message in componentB /getting
console.log(this.check); and console.log(message); 's values in the console.. but when I call this.sendInfoToB(true); from componentA's ngOnInit() then I get no message in console for componentB. I want the message when I call from componentA's ngOnInit. How can I achieve that? Please help. Thank you in advance.
ComponentA.ts
constructor(private siblingService: SiblingService,) {}
public dataX: boolean = false;
someFunc(){
//some calculation returning true
this.dataX = true;
}
ngOnInit() {
this.someFunc();
this.sendInfoToB();
}
sendInfoToB() {
this.siblingService.communicateMessage(dataX);
}
message.service.ts
export class SiblingService {
sendMessage = new Subject();
constructor() {}
communicateMessage(msg) {
this.sendMessage.next(msg);
}
}
ComponentB.ts
constructor(private sibService: SiblingService,) {}
ngOnInit() {
this.sibService.sendMessage.subscribe((message) => {
this.check = message;
console.log(this.check);
console.log(message);
});
}
More than likely this has to do with order of operations. Component A is created and sends the message, then Component B gets created and subscribes to new messages. Since you are using a Subject it only gives you messages sent after you subscribe to it.
The easiest strategy to this is to use a BehaviorSubject.
export class SiblingService {
sendMessage = new BehaviorSubject();
constructor() {}
communicateMessage(msg) {
this.sendMessage.next(msg);
}
}
The other way is to send the message after the init happens, like on a click event.
I have some data that I want to be shared with my entire app so I have created a service like so..
user.service
userDataSource = BehaviorSubject<Array<any>>([]);
userData = this.userDataSource.asObservable();
updateUserData(data) {
this.userDataSource.next(data);
}
then in my component Im getting some data from an api and then sending that data to userDataSource like so..
constructor(
private: userService: UserService,
private: api: Api
){
}
ngOnInit() {
this.api.getData()
.subscribe((data) => {
this.userService.updateUserData(data);
})
}
now that all works but.. I want to be able to add data to the end of the array inside the userDataSource so basically the equivalent of a .push am I able to just call the updateUserData() function and add more data or will doing that overwrite what is currently in there?
Any help would be appreciated
You can add a new method to your service like addData in which you can combine your previous data with new data like.
import {Injectable} from '#angular/core';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
#Injectable()
export class UserService {
userDataSource: BehaviorSubject<Array<any>> = new BehaviorSubject([]);
userData = this.userDataSource.asObservable();
updateUserData(data) {
this.userDataSource.next(data);
}
addData(dataObj) {
const currentValue = this.userDataSource.value;
const updatedValue = [...currentValue, dataObj];
this.userDataSource.next(updatedValue);
}
}
For someone that may come accross this issue with a BehaviorSubject<YourObject[]>.
I found in this article a way to properly add the new array of YourObject
import { Observable, BehaviorSubject } from 'rxjs';
import { YourObject} from './location';
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class ObjService {
private theObjData: BehaviorSubject<YourObject[]> = new BehaviorSubject<YourObject[]>(null);
constructor() {
}
public SetObjData(newValue: YourObject[]): void {
this.theObjData.next(Object.assign([], newValue));
}
}
How to update data:
// inside some component
this.api.userData().subscribe((results:YourObject) =>
this.objService.SetObjData(results);
)
How to observe changes on other component
// inside another component
ngOnInit() {
this.objService.GetAccountStatements().subscribe((results) =>
...
)
}
Normally Observables and Subjects are meant to be streams of data, not an assignment of data. BehaviorSubjects are different because they hold their last emitted value.
Normally Subjects or BehaviorSubjects inside of a contained class (like a Service) do not want to expose themselves publicly to any other classes, so it's best practice to access their properties with getters or methods. This keeps the data stream cold to all subscribers.
However, since the BehaviorSubject holds the last emitted value, there's a few options here. If all subscribers need a concatenated stream of data from every emission, you could access the last emitted value and append to it:
userDataSource = BehaviorSubject<any[]>([]);
userData = this.userDataSource.asObservable();
updateUserData(data) {
this.userDataSource.next(this.userDataSource.value.push(data));
}
...or, in what might be considered better practice, Subscribers to this Subject could do their own transformation on the stream:
this.api.userData()
.scan((prev, current) => prev.push(current). [])
.subscribe((data) => {
this.concatenatedUserData = data;
});
Use concat to add object
userDataSource = BehaviorSubject<Array<any>>([]);
updateUserData(data) {
this.userDataSource.next(this.userDataSource.value.concat(data));
}
Use filter to remove object
removeUserData(data) {
this.userDataSource.next(this.userDataSource.value.filter(obj => obj !== data));
}
I'm working on a simple project using nodejs and angular 2.
In my client project I have a component which has a form and a submit event. When I throw this event all data from the form is properly sent to my node application.
But I have another component which has a table where I list all registers located on my database.
Everything works fine. But I should make my table load in the same time after I've sent my submit.
I have no idea how I can do this.
I tried implement something like this:
export class EmployeeListComponent implements OnInit {
public employees: string[];
constructor(private employeeService : EmployeeService) {
this.employeeService.employeeRequest().subscribe(employees => {
this.employees = employees;
})
}
ngOnInit() {
}
}
And in my register component I did this method:
onRegister(){
const Employee = {
name : this.name,
familyName: this.familyName,
participation: this.participation
}
if (!this.validateService.validateRegister(Employee)){
this.alertMsg = JSON.stringify({'msg': 'All fields must be filled'});
console.log(this.alertMsg);
return false;
} else {
this.registerService.employeeRegister(Employee).subscribe(data => {
this.alertMsg = JSON.stringify({'msg': 'Employee registered successfully'});
console.log(this.alertMsg);
return this.router.navigate(['/list']);
});
};
};
My tests show that my code works fine, but my table just load properly at first submit. After that I have to refresh manually the browser to load my table again.
Is there someone who know what I'm doing wrong or can tell me some way to code that?
Try to change your constructor to a function, and than you call it on ngOninit, so every time your list component initialize your list of employees will load again, something like this:
export class EmployeeListComponent implements OnInit {
public employees: string[];
constructor(private employeeService : EmployeeService) { }
ngOnInit() {
this.loadAllEmployees();
}
loadAllEmployees() {
this.employeeService.employeeRequest().subscribe(data => {
this.employees = data;
});
}
}
Also see Angular life cycle hooks documentation to understand more about ngOnInit and others:
https://angular.io/guide/lifecycle-hooks
Well. After I got the suggestions I tried another strategies. First I've simplify my two components as a single component. Then I moved my logic from the constructor to a method called dashCall() which I call inside my constructor and in the final of onRegister() method.
The final code looks like this:
export class EmployeeRegisterComponent {
public name: string;
public familyName: string;
public participation: number;
public alertMsg: any;
public employees: string[];
constructor(private validateService : ValidateService,
private registerService : EmployeeService,
private employeeService : EmployeeService) {
this.dashCall();
}
onRegister(){
const Employee = {
name : this.name,
familyName: this.familyName,
participation: this.participation
}
if (!this.validateService.validateRegister(Employee)){
this.alertMsg = JSON.stringify({'msg': 'All fields must be filled'});
return false;
} else {
this.registerService.employeeRegister(Employee).subscribe(data => {
this.alertMsg = JSON.stringify({'msg': 'Employee registered successfully'});
this.dashCall();
});
};
};
dashCall(){
this.employeeService.employeeRequest().subscribe(employees => {
this.employees = employees;
});
}
}
I know it's not the best way to implement this. But in the end I got what I needed.
I have an Angular 2/4 service which uses observables to communicate with other components.
Service:
let EVENTS = [
{
event: 'foo',
timestamp: 1512205360
},
{
event: 'bar',
timestamp: 1511208360
}
];
#Injectable()
export class EventsService {
subject = new BehaviorSubject<any>(EVENTS);
getEvents(): Observable<any> {
return this.subject.asObservable();
}
deleteEvent(deletedEvent) {
EVENTS = EVENTS.filter((event) => event.timestamp != deletedEvent.timestamp);
this.subject.next(EVENTS);
}
search(searchTerm) {
const newEvents = EVENTS.filter((obj) => obj.event.includes(searchTerm));
this.subject.next(newEvents);
}
}
My home component is able to subscribe to this service and correctly updates when an event is deleted:
export class HomeComponent {
events;
subscription: Subscription;
constructor(private eventsService: EventsService) {
this.subscription = this.eventsService.getEvents().subscribe(events => this.events = events);
}
deleteEvent = (event) => {
this.eventsService.deleteEvent(event);
}
}
I also have a root component which displays a search form. When the form is submitted it calls the service, which performs the search and calls this.subject.next with the result (see above). However, these results are not reflected in the home component. Where am I going wrong? For full code please see plnkr.co/edit/V5AndArFWy7erX2WIL7N.
If you provide a service multiple times, you will get multiple instances and this doesn't work for communication, because the sender and receiver are not using the same instance.
To get a single instance for your whole application provide the service in AppModule and nowhere else.
Plunker example
Make sure your Component is loaded through or using its selector. I made a separate component and forgot to load it in the application.
To pass data around few components I created a service:
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
#Injectable()
export class Services {
private messageSource = new BehaviorSubject<string>("lol");
currentMessage = this.messageSource.asObservable();
constructor() {
}
changeMessage(message: string) {
this.messageSource.next(message);
console.log(message);
}
}
I create string messagesource for contain the passing data, and current message for Observable. And after that I create function to change this data.
So now, In ngOnInit() in one of component, I write:
this.data.currentMessage.subscribe(message => this.message = message);
and define in component message:string save there message.
In function I make:
selectNews(news) {
this.data.changeMessage("lol3"); // string for test
}
And after that, I want to get this string in other component
So again in ngOnInit, I copy the same line and define the message. But the consolelog here show me the string before function make action....
So were is the problem?
Edit
Fiddle with all whole code :
https://jsfiddle.net/fywdzz51/
you are providing the service separately for each component. this creates different instances in each component. you should provide it in one place for the whole module