I want to pass the array value from Search component to History component to display the history of the searches done.
I have written the code in this manner -
search-page.component.ts
export class SearchPageComponent implements OnInit {
constructor( private dataService :DataService) { }
githubSearch(username:any){
return new Promise((resolve, reject) => {
this.httpClient.get("----")
.pipe(map(Response => Response))
.subscribe((res: any) => {
this.searchResultObject = res;
this.allSearchResultArray.push(this.searchResultObject);
this.dataService.changeParam(this.allSearchResultArray)
resolve(this.searchResultObject );
});
});
}
passDataToService(){
this.dataService.allPassedData.next(this.allSearchResultArray);
}
}
data.service.ts
export class DataService {
allPassedData: any
constructor() { }
storePassedObject(passedData:any){
this.allPassedData.next(passedData);
}
retrievePassedObject(){
return this.allPassedData;
}
}
history-page.component.ts
export class HistoryPageComponent implements OnInit {
historyData : any = [];
constructor(private dataService: DataService) { }
ngOnInit(): void {
this.historyData = this.dataService.retrievePassedObject()
}
}
I am unable to retrieve data via this designed code.
First create subject in service and make it as observable
data.service.ts
export class DataService {
private allPassedData = new Subject<any>();
allPassedData$ = this.allPassedData.asObservable();
constructor() { }
setPassedData(retrievedData: any) {
this.allPassedData.next(retrievedData);
}
}
Now set the data in the observable
search-page.component.ts
passDataToService() {
this.dataService.setPassedData(this.allSearchResultArray);
}
history-page.component.ts
ngOnInit(): void {
// for retrieval of data in history component
this.dataService.allPassedData$.subscribe((data) => {
this.historyData = data
})
}
Related
I have a angular 8 application and a service, like this:
export class ProfileUserService {
user$ = this.authService.loginStatus().pipe(take(1));
constructor(private profileService: ProfileService, private authService: AuthService) {}
getProfile(): Observable<ProfileApi> {
return this.user$.pipe(mergeMap(({ profile }) => this.profileService.get(profile.participant)));
}
}
And I have a component where I use the service where I call the method, like this:
export class SettingsAccountComponent extends FormCanDeactivate implements OnInit, OnDestroy {
constructor(
private profileUserService: ProfileUserService){}
ngOnInit() {
this.innerWidth = window.innerWidth;
this.profileSubscription = this.profileUserService.getProfile().subscribe((profile: ProfileApi) => {
this.profile = profile;
this.deletePicture = false;
this.buildForm();
});
}
}
But I want to call directly in the component SettingsAccountComponent : this service:
private profileService: ProfileService
But the problem is this:
user$ = this.authService.loginStatus().pipe(take(1));
Because I need that for getting the participantId. But so my question is, how to combine the ProfileService, like this
this.profileSubscription = this.profileService.get().subscribe((profile: ProfileApi) => {
this.profile = profile;
this.deletePicture = false;
this.buildForm();
});
witht the:
user$ = this.authService.loginStatus().pipe(take(1));
because now in the get() method it expecs a ParticipantId
So what I have to change?
Thank you
I think a switchMap can help you.
Try:
import { switchMap } from 'rxjs/operators';
...
this.profileSubscription = this.profileService.user$.pipe(
switchMap(({ profile }) => this.profileService.get(profile.participant))
).subscribe((profile: profileAPI) => {
this.profile = profile;
this.deletePicture = false;
this.buildForm();
});
I see you've already done mergeMap in your service, switchMap is very similar.
I my global service I instiante a behaviourSubject variable
dataWorkFlowService:
export class CallWorkflowService {
url = 'http://localhost:3000/';
selectedNode : BehaviorSubject<Node> = new BehaviorSubject(new Node(''))
dataflow : BehaviorSubject<any> = new BehaviorSubject<any>({});
constructor(private http: HttpClient) {}
getDataflow() {
return this.http.get(this.url);
}
updateNode(node :Node) {
this.selectedNode.next(node);
}
}
In my component ReteComponent I set behaviourSubject value using
this.dataFlowService.selectedNode.next(node);
Im my second component I subscribe to the BehaviourSubject
export class ComponentsMenuComponent implements OnInit {
constructor(private callWorkflowService:CallWorkflowService) { }
selectedNode:Node = new Node('');
dataFlow:any;
nxtElements:String[]=[]
ngOnInit() {
this.callWorkflowService.dataflow.subscribe(data=> {
this.dataFlow=data
})
this.callWorkflowService.selectedNode.subscribe( (node) => {
this.selectedNode=node; <=== ###### Subscription is not triggered
if(this.dataFlow) {
this.nxtElements=this.dataFlow[node.name].next;
}
})
}
When I trigger new value to selectedNode my subscription does not work
But in another component it's working well
export class AppComponent {
opened:boolean=false;
events: string[] = [];
constructor(private callWorkflowService:CallWorkflowService) { }
ngOnInit() {
this.callWorkflowService.selectedNode.pipe(
skip(1)
)
.subscribe( (node) => {
this.opened=true; <== subscription is working
})
}
}
I have noticed in that in ComponentsMenuComponent when I change it to
export class ComponentsMenuComponent implements OnInit {
constructor(private callWorkflowService:CallWorkflowService) { }
selectedNode:Node = new Node('');
dataFlow:any;
nxtElements:String[]=[]
ngOnInit() {
this.callWorkflowService.getDataflow().subscribe(data=> {
this.dataFlow=data;
}) ####CHANGE HERE ### <== using `getDataFlow` method which is not observable
this.callWorkflowService.selectedNode.subscribe( (node) => {
this.selectedNode=node; ### <=== subscription is triggered
if(this.dataFlow) {
this.nxtElements=this.dataFlow[node.name].next;
}
})
}
the selectNode subscription is working.
Update
I have tried to change how I proceed
In my service I added a method that return last value
updateDataFlow() {
return this.dataflow.getValue();
}
In ComponentsMenuComponent
this.callWorkflowService.node.subscribe( (node) => {
this.dataFlow = this.callWorkflowService.updateDataFlow();
this.selectedNode=node;
if(this.dataFlow) {
this.nxtElements=this.dataFlow[node.name].next;
}
})
Here again subscription is not working..
I have tried to comment the line
this.dataFlow = this.callWorkflowService.updateDataFlow();
And here surprise.. subscription works.
I don't know why it don't subscribe when I uncomment the line that I have mentioned
You must be providing your CallWorkflowService incorrectly and getting a different instance of the service in different components. If one component is working and another is not then I would guess that they are not both subscribed to the same behavior subject.
How are you providing the service? Is it provided in a module, component or are you using provided in?
I know this question has been asked several times, but problem is that nobody tried to make a some fiddle or show results of code. This is what i have, i need to update values in other component based on value in some other component, but that is not just value,I have call function again in some other component.
I have some component that goes to database and update values, on second hand I have other component that read those values from database from service.
This is example of my code
tasks.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import { environment } from '../../environments/environment';
import { Tasks } from './tasks';
#Injectable()
export class TasksProvider {
constructor(private http: HttpClient) { }
createNewTask(name: Name) : Observable<any> {
return this.http.post(environment.apiUri + 'tasks', { name, finished: false },
{ responseType: 'text' });
}
updateTask(id: Id, name: Name, finished: boolean) : Observable<any> {
return this.http.put(environment.apiUri + 'tasks/' + id, { name, finished },
{ responseType: 'text' });
}
getAllTasks(): Observable<Tasks[]> {
return this.http.get(environment.apiUri + 'tasks')
.map<any, Tasks[]>(data => data.map(Tasks.fromObject));
}
}
app.component.html
<app-tasks-list></app-tasks-list>
<app-tasks-add-new></app-tasks-add-new>
As you may see I have not child components, that is my main problem
tasks-list.component.ts
import {Component} from '#angular/core';
import { Tasks } from '../services/tasks';
import { TasksProvider } from '../services/tasks.service';
#Component({
selector: 'app-tasks-list',
templateUrl: './tasks-list.component.html',
styleUrls: ['./tasks-list.component.scss']
})
export class TasksListComponent {
tasks: Array<Tasks>;
constructor(private tasksProvider: TasksProvider) { }
ngOnInit() {
this.getTasksList();
}
displayedColumns: string[] = ['id', 'name', 'finished'];
private getTasksList() {
this.tasksProvider.getAllTasks()
.subscribe(tasks => {
this.tasks = tasks;
});
}
public updateCheckboxValue(id: number, name: string, event: any){
this.tasksProvider.updateTask(id, name, event.checked).subscribe(
result => {},
() => {
alert('Something went wrong');
})
}
}
tasks-add-new.component.ts
import { Component, OnInit, Inject } from '#angular/core';
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '#angular/material';
import { Tasks } from '../services/tasks';
import { TasksProvider } from '../services/tasks.service';
export interface DialogData {
name: string;
}
#Component({
selector: 'app-tasks-add-new',
templateUrl: './tasks-add-new.component.html',
styleUrls: ['./tasks-add-new.component.scss']
})
export class TasksAddNewComponent implements OnInit {
ngOnInit() {
}
constructor(public dialog: MatDialog, private tasksProvider: TasksProvider) {}
openDialog(): void {
const dialogRef = this.dialog.open(TasksAddNewDialog, {
width: '250px',
data: {name: this.animal}
});
dialogRef.afterClosed().subscribe(result => {
this.name = result
this.tasksProvider.createNewTask(this.name).subscribe(
result => {},
() => {
alert('Something went wrong');
})
}
}
}
#Component({
selector: 'tasks-add-new-dialog',
templateUrl: 'tasks-add-new-dialog.html'
})
export class TasksAddNewDialog {
constructor(
public dialogRef: MatDialogRef<TasksAddNewDialog>,
#Inject(MAT_DIALOG_DATA) public data: DialogData) {}
onNoClick(): void {
this.dialogRef.close();
}
}
You see now when i call function in tasks-add-new.component.ts like
this.tasksProvider.createNewTask(this.name).subscribe(
result => {},
() => {
alert('Something went wrong');
})
I need to call again function in tasks-list.component.ts
private getTasksList() {
this.tasksProvider.getAllTasks()
.subscribe(tasks => {
this.tasks = tasks;
});
}
Does any body have idea how i can do that the best practice?
On of the possible approach is to use Subjects.
1) Store task list on the service and provide subscribable Subject
private tasks: Array<Task>;
public $tasks: BehaviorSubject<Array<Task>>;
constructor(private http: HttpClient) {
this.$tasks = new BehaviorSubject([]);
...
}
getAllTasks() {
this.http.get(environment.apiUri + 'tasks')
.subscribe(data => {
this.tasks = data;
this.$tasks.next(this.tasks);
});
}
updateTask(params) {
this.http.post(/* params */).subscribe((task) => {
this.tasks = this.tasks.map(t => t.id !== task.id ? t : task);
this.$tasks.next(this.tasks);
});
}
createTask(...) {
// again, do a request, update this.tasks and call $tasks.next
...
}
2) Make one service Subject subscription on the component instead of multiple service methods Observable listeners and update component's list automatically each time the service source has been changed
tasks: Array<Tasks>;
constructor(private tasksProvider: TasksProvider) {
this.tasksProvider.$tasks.subscribe(tasks => this.tasks = tasks);
}
ngOnInit() {
this.tasksProvider.getAllTasks();
}
public updateCheckboxValue(id: number, name: string, event: any){
this.tasksProvider.updateTask(id, name, event.checked);
}
I need to get array from JSON API and then iterate it. I still can't understand how it works. Thank you for help.
This is how looks my service.
import {Injectable} from '#angular/core';
import { Http } from "#angular/http";
import "rxjs/Rx";
#Injectable()
export class PlayersService {
roster:Roster[];
constructor(private http: Http){
this.roster = [];
}
getPlayer(id) {
for (let player of this.roster) {
console.log(player["id"]);
}
}
getRoster(season,category) {
this.roster.push(this.http.get("http://API JSON LIST OF ID")
.map(res => res.json()));
}
}
interface Roster {
id:number
}
This how I call it
ngOnInit() {
this.getRoster();
this.getPlayers();
}
Where is the fail please?
This should do what you want:
#Injectable()
export class PlayersService {
roster:Roster[];
constructor(private http: Http){
this.roster = [];
}
getPlayer(id) {
for (let player of this.roster) {
console.log(player["id"]);
}
}
getRoster(season,category) {
return this.http.get("http://API JSON LIST OF ID")
.map(res => res.json())
.do(val => this.roster.push(val)); // the do operator should be used for side effects (eg modifying an existing array)
}
}
ngOnInit() {
this.playerService.getRoster().subscribe(val => this.playerService.getPlayer());
}
I plan to do such architecture:
component store
-- nested-component book
in store - i have an service call, which get data from service, and i do a subscription on result. Like it was described in angular2 docs (http).
And i want to use this data in nested components: in forms (formBuilder), in material-design elements etc.
Which way is the best, to do this? I'm new to angular2.
Store:
book: IBook;
constructor(private bookService: BookService) { }
ngOnInit() {
this.bookService.getBook('1')
.subscribe((book) => {
this.book = book;
});
}
BookService:
...
getBook (id): Observable<IBook> {
return this.http.get(this.url + '/' + id)
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
let body = res.json();
return body || { };
}
...
Book:
#Input() book:IBook;
constructor() {}
ngOnInit() {
/*How here can i subscribe on book http data get?, so that i can use async value in forms etc?*/
});
Because, if i use async book everywhere (not formBuilder) - all is ok, but formBuilder is in need to update values, after data is loaded in parent component. How can i do this?
What about passing the bookID to the BookComponent and letting the BookComponent handle the async http get in ngInit?
export class Book implements OnInit {
#Input() bookID: number;
private book: IBook;
constructor(private bookService: BookService) {}
ngOnInit() {
this.bookService.getBook(this.bookID)
.subscribe((book) => {
this.book = book;
});
}
}
Otherwise you have a few options which are explained in https://angular.io/docs/ts/latest/cookbook/component-communication.html
I'll briefly highlight two ways which I think you could use.
Intercept input property changes with ngOnChanges
export class Book implements OnChanges {
#Input() book: IBook;
ngOnChanges(changes: {[propKey: string]: SimpleChange}) {
for (let propName in changes) {
// handle updates to book
}
}
}
more info https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html
Parent and children communicate via a service
#Injectable()
export class BookService {
books = new Subject<IBook>();
getBook(id): Observable<IBook> {
return this.http.get(this.url + '/' + id)
.map(d => {
let book = this.extractData(d);
this.books.next(book);
return book;
})
.catch(this.handleError);
}
...
}
#Component({
selector: 'book',
providers: []
})
export class Book implements OnDestroy {
book: IBook
subscription: Subscription;
constructor(private bookService: BookService) {
this.subscription = bookService.books.subscribe(
book => {
this.book = book;
});
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
#Component({
selector: 'store',
providers: [BookService]
})
export class Store {
book: IBook;
constructor(private bookService: BookService) { }
ngOnInit() {
this.bookService.getBook('1')
.subscribe((book) => {
this.book = book;
});
}
}