Angular - communication from child-component to parent - javascript

I don't get i, how to communicate between components and services.. :(
I have read and tried a lot about even if some examples somehow work, I do not understand why (?)
what I want to achieve:
I have one parent and two child-components:
dashboard
toolbar
graph
in the toolbar-component I have a searchfield, which gets it's result from a external source (works via service).. when the result arrives, I need to trigger the updateGraph()-Method in the graph-component
toolbar.component.ts
import { Component, OnInit, Output, EventEmitter } from '#angular/core';
import { FormControl } from '#angular/forms';
import { WebsocketsService } from '../../../services/websockets/websockets.service';
import { DataService } from '../../../services/data/data.service';
#Component({
selector: 'toolbar',
templateUrl: './toolbar.component.html',
styleUrls: ['./toolbar.component.scss'],
providers: [WebsocketsService, DataService]
})
export class ToolbarComponent implements OnInit {
#Output() newGraphData: EventEmitter<boolean> = new EventEmitter();
searchField: FormControl;
search: string;
private isNewGraph = false;
constructor(private _websocketsService: WebsocketsService, private _dataService: DataService) {
}
ngOnInit() {
this.searchField = new FormControl();
this.searchField.valueChanges
.subscribe(term => {
this.search = term;
});
}
private applySearch() {
const res = this._websocketsService.sendQuery(this.search);
this._dataService.setGraphData(res);
this.newGraphData.emit(true);
this.search = '';
this.searchField.reset();
}
}
graph-component.ts
import { Component, OnInit} from '#angular/core';
import { HttpService } from '../../../services/http/http.service';
import { DataService } from '../../../services/data/data.service';
#Component({
selector: 'graph',
templateUrl: './graph.component.html',
styleUrls: ['./graph.component.scss'],
providers: [HttpService, DataService]
})
export class GraphComponent implements OnInit, AfterViewInit {
constructor( private _httpService: HttpService, private _dataService: DataService ) {
}
ngOnInit() {
}
public renderResult() {
console.log( this._dataService.getGraphData() );
}
}
data.service.ts
import { Injectable } from '#angular/core';
import { Subject } from 'rxjs/Subject';
#Injectable()
export class DataService {
private graphData: Subject<string> = new Subject<string>();
public setGraphData(data) {
this.graphData.next( data );
}
public getGraphData() {
return this.graphData;
}
constructor() { }
}
I simply want ´renderResult()´to be executed after the searchresult has been written to ´graphData´. please help i am confused.

If I understand, you want communication between components and service.
A[component] (make a information) -----(notification)-----> B[service] ----(send)----> C[component] (consume the information)
It's correct? Let's go.
You need create a subscription of graphData(data.service.ts) in GraphComponent.
import { Subscription } from 'rxjs/Subscription';
export class GraphComponent implements OnInit, AfterViewInit {
constructor( private _httpService: HttpService, private _dataService: DataService ) {
}
private subscription: Subscription;
ngOnInit() {
this.subscription = this._dataService.getGraphData().asObservable().subscribe((data) => {
console.log(data);
});
}
}
Look here to help you.
http://jasonwatmore.com/post/2016/12/01/angular-2-communicating-between-components-with-observable-subject

Short answer, I think you need to subscribe to the getGraphData subject, something like this (NOT RECOMMENDED):
public renderResult() {
this._dataService.getGraphData().subscribe(d => {
console.log(d)
});
}
It is not recommended as per the lead of RxJS says: https://medium.com/#benlesh/on-the-subject-of-subjects-in-rxjs-2b08b7198b93
Better answer, create an observable in your service and subscribe to that instead.
data.service.ts
graphObservable = this.graphData.asObservable();
graph-component.ts
public renderResult() {
this._dataService.graphObservable().subscribe(d => {
console.log(d)
});
}

Related

Property '' does not exist on type 'Object'

I was working all day in angular. Everything worked fine all day.
Restarted the server (ng serve). And now suddenly there are alot of errors.
I managed to fix most but I am stuck with this one.
This is the main part of the component .ts file:
import { Component, OnInit } from '#angular/core';
import { HttpService } from '../http.service';
#Component({
selector: 'app-playboard',
templateUrl: './playboard.component.html',
styleUrls: ['./playboard.component.scss']
})
export class PlayboardComponent implements OnInit {
brews: Object;
constructor(private _http: HttpService) { }
ngOnInit() {
this._http.myMethod().subscribe(data => {
this.brews = data;
this.dices = this.brews.myBox;
this.diceSeed = this.brews.boxID;
console.log(this.brews);
});
}
And this is the http.service.ts file:
import { Injectable } from '#angular/core';
import {HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class HttpService {
constructor(private http: HttpClient) { }
myMethod() {
return this.http.get<Object>('https://localhost:44398/api/boggle');
}
myWordMethod(word) {
var url = 'https://localhost:44398/api/wordpoints/' + word;
return this.http.get<Object>(url);
}
}
It was working all day and suddenly these strange errors appear.
Does anyone have a clue of what could be wrong? Thanks alot!
Remove Object from your http calls. Using the generic is optional, especially if you haven't typed out your response.
import { Injectable } from '#angular/core';
import {HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class HttpService {
constructor(private http: HttpClient) { }
myMethod() {
return this.http.get('https://localhost:44398/api/boggle');
}
myWordMethod(word) {
var url = 'https://localhost:44398/api/wordpoints/' + word;
return this.http.get(url);
}
}
On brews, declare it as any:
import { Component, OnInit } from '#angular/core';
import { HttpService } from '../http.service';
#Component({
selector: 'app-playboard',
templateUrl: './playboard.component.html',
styleUrls: ['./playboard.component.scss']
})
export class PlayboardComponent implements OnInit {
brews: any;
constructor(private _http: HttpService) { }
ngOnInit() {
this._http.myMethod().subscribe(data => {
this.brews = data;
this.dices = this.brews.myBox;
this.diceSeed = this.brews.boxID;
console.log(this.brews);
});
}
You can ignore these by simply delcaring them as the any type. For instance;
myWordMethod(word: any) {
..
}
this._http.myMethod().subscribe(data: any => {
..
});
That said declaring the actual type for TypeScript is often preferred. For Instance if your API sends back a common object with particular properties then declare it as such;
interface MyMethodResponse {
someProperty: string;
someNumber: number;
someArray: string[];
}
this._http.myMethod().subscribe((myMethodResponse: MyMethodResponse) => {
// TypeScript now knows that these properties exists on the response object
console.log(myMethodResponse.someArray);
console.log(myMethodResponse.someNumber);
console.log(myMethodResponse.someProperty);
});

ANGULAR. Send array data get it of Itunes API; from component-search to component-main, via service

In angular 7. I need to send an Array information get it from Itunes Api, which is included in a component called "search", to another component called "catalog". I've understand that in this case I've to use a service which allows to share the info between them. Here's some code. What's wrong?
I've tried with viewchild, input, output, but there's no result; because both components aren't "relatives".
"search"
"search"
import { Component, OnInit, Output, EventEmitter } from '#angular/core';
import { RequestService } from '../../services/request/request.service';
import {DataShareService} from '../../services/dataShare/data-share.service';
import { Music } from '../../models/music';
#Component({
selector: 'search',
styleUrls: ['./ion-searchbar.component.sass'],
templateUrl: './ion-searchbar.component.html',
providers: [RequestService, DataShareService],
})
export class IonSearchBarComponent implements OnInit {
public searchResults: Music[];
public searchValue: string;
constructor(public _requestService: RequestService, private _dataShareService: DataShareService) {}
ngOnInit() {
this._dataShareService.$sendDataObservable.subscribe(
data => {
this.searchResults = data
})
}
sendData(searchResults: Music[]){
console.log("executat");
this._dataShareService.sendData(searchResults);
}
search(){
this._requestService.getMusic(this.searchValue).subscribe(
result => {
this.searchResults = result.results;
console.log(result.results);
this.sendData(this.searchResults);
},
error =>{
console.log(<any>error);
}
);
}
}
"service"
import { Injectable } from '#angular/core';
import { Music } from '../../models/music';
import { Subject } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class DataShareService {
private _sendDataSubject = new Subject<Music[]>();
$sendDataObservable = this._sendDataSubject.asObservable();
constructor() { }
sendData(data: Music[]){
this._sendDataSubject.next(data);
console.log(data);
}
}
"catalog"
import { Component, OnInit, Input } from '#angular/core';
import {RequestService} from '../../services/request/request.service';
import {DataShareService} from '../../services/dataShare/data-share.service';
import { Music } from '../../models/music';
#Component({
selector: 'catalog',
templateUrl: './catalog.component.html',
styleUrls: ['./catalog.component.sass'],
providers: [RequestService, DataShareService]
})
export class CatalogComponent implements OnInit {
public title: any;
public InfoLlegada: any;
constructor(private _dataShareService: DataShareService) {}
ngOnInit() {
console.log(this.InfoLlegada)
this._dataShareService.$sendDataObservable.subscribe(
data => {
this.InfoLlegada = data
console.log(data);
});
}
}
Not sure if this is the actual cause, but there an issue with your this binding in getMusic subscription in search component. Try this.sendData.call(this, result.results);

Call Parent Component function through Nested Component

I have an issue with my Angular code. I want to call a function of the Parent component, from the Nested component which is created by the Component() Angular function.
Please see my code below:
import {
Compiler, Component, ComponentRef, Injector, NgModule, NgModuleRef, ViewChild, ViewContainerRef
} from '#angular/core';
import { ActivatedRoute } from "#angular/router";
import { FormsModule, NgForm } from "#angular/forms";
import { HttpService } from './ht.service';
#Component({
selector: 'app-module-routing',
templateUrl: './module-routing.component.html'
})
export class ModuleRoutingComponent {
#ViewChild('vc', {read: ViewContainerRef}) vc: ViewContainerRef;
private cmpRef: ComponentRef<any>;
private module_name: string;
private module_link: any;
private module_links = [
{"access": "salessalquoent", "link": "sales\/sales_order_entry.php?NewQuotation=Yes"},
];
constructor(private compiler: Compiler,
private injector: Injector,
private m: NgModuleRef<any>,
private route: ActivatedRoute,
private httpService: HttpService) {}
test() { //<-- Want to Call this function
alert('function called successfully');
}
printPage(template, httpService, link) {
const styles = [`input { width: 100px, display: block }`];
const tmpCmp = Component({ template, styles }) (
class {
OnSubmit(form: NgForm) {
console.log(form);
this.ModuleRoutingComponent.test(); //<-- Want to call Parent Component function here
httpService.getPage(link, form.value)
.subscribe(
data => this.instance.printPage(data, httpService, link)
);
return false;
};
}
);
const tmpModule = NgModule({
imports: [FormsModule],
declarations: [tmpCmp]
})(class {});
this.compiler.compileModuleAndAllComponentsAsync(tmpModule)
.then((factories) => {
const f = factories.componentFactories[0];
this.cmpRef = f.create(this.injector, [], null, this.m);
this.cmpRef.instance.name = 'someForm';
this.vc.insert(this.cmpRef.hostView);
});
}
}
Please see my comments within code, you will see what I actually mean:
//<-- Want to Call this function
and
//<-- Want to call Parent Component function here

(Angular2) JSON data (http.get()) is undefined, and data is not updated in the component

My http-data.service accepts json for output in the component template. Initially, the console shows that the first few calls are given undefined, and the following calls are already taking json, but also if you check the component, then the component shows that the method that outputs the data to the component is called only once and since the data has not yet arrived it writes undefined , But not updated after the arrival of json. Help please understand why? Thank you
My http-data.service:
import {Injectable} from '#angular/core';
import {Http} from '#angular/http';
import {Response} from '#angular/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
#Injectable()
export class HttpService{
constructor(private http: Http) {}
getDataOrganizations(): Observable<any[]>{
return this.http.get('http://localhost:3010/data')
.map((resp:Response)=>{
let dataOrganizations = resp.json().organization;
return dataOrganizations;
});
}
getDataModules(): Observable<any[]> {
return this.http.get('http://localhost:3010/data')
.map((resp: Response)=> {
let dataModules = resp.json().modules;
return dataModules;
});
}
getDataPresets(): Observable<any[]> {
return this.http.get('http://localhost:3010/data')
.map((resp: Response)=> {
let dataPresets = resp.json().presets;
return dataPresets;
});
}
getDataModuleItems(): Observable<any[]> {
return this.http.get('http://localhost:3010/data')
.map((resp: Response)=> {
let dataModuleItems = resp.json().module_items;
return dataModuleItems;
});
}
}
My data-all.service
import { Injectable, EventEmitter } from '#angular/core';
import {Response} from '#angular/http';
import { ModuleModel } from './model-module';
import { ModuleItemsModel } from './model-module-items';
import data from '../data/data-all';
import { PriceService } from './price.service';
import { HttpService } from './http-data.service';
#Injectable()
export class ModuleDataService {
constructor(private priceService: PriceService, private httpService: HttpService){
this.dataMinMaxSum = {minSum: 0, maxSum: 0}
}
private currentPopupView: EventEmitter<any> = new EventEmitter<any>();
private dataModules: ModuleModel[] = this.getDataModules();
private dataMinMaxSum: {};
private dataCalculateVariationOrg: any[];
private dataChangeExecutor: any[];
subscribe(generatorOrNext?: any, error?: any, complete?: any) {
this.currentPopupView.subscribe(generatorOrNext, error, complete);
}
calculte(){
return this.priceService.getDataPrice();
}
getDataModules(){
this.httpService.getDataModules().subscribe(((modules)=>{this.dataModules = modules; console.log(this.dataModules);}));
console.log('dataModules');
console.log(this.dataModules);
return this.dataModules;
}
---------------------------------------------------------------------------
}
My left-block.component
import { Component, OnInit} from '#angular/core';
import { ModuleDataService } from '../../service/data-all.service';
import { ModuleModel } from '../../service/model-module';
#Component({
moduleId: module.id,
selector: 'modules-left-block',
templateUrl: './modules-left-block.html',
styleUrls: ['modules-left-block.css']
})
export class ModuleLeft implements OnInit{
modules: ModuleModel[];
constructor(private modulesAll: ModuleDataService){}
ngOnInit(){
this.modules = this.modulesAll.getDataModules();
console.log("view");
console.log(this.modulesAll.getDataModules());
}
onToggle(module: any){
this.modulesAll.toggleModules(module);
}
}
My left-block.component.html
<div class="modules-all">
<div class="modules-all-title">Все модули</div>
<div class="module-item" *ngFor="let module of modules" [ngClass]="{ 'active': module.completed }" (click)="onToggle(module)">{{module?.title}}</div>
</div>
In the component this.modulesAll.getDataModules () method is why it is executed only once without updating (write in console => undefined), if there are any thoughts, write, thanks.
This behaviour is due to the .subscribe() method does not wait for the data to arrive and I'm guessing you already know this. The problem you're facing is because, you have .subscribe to the getDataModules() service in the wron place. You shouldn't subscribe to a service in another service (at leat in this case). Move the subscribe method to the left-block.component and it should work.
getDataModules() {
this.httpService.getDataModules().subscribe(((modules) => {
this.dataModules = modules;
console.log(this.dataModules);
}));
console.log('dataModules');
console.log(this.dataModules);
return this.dataModules;
}
It should look somethig like this:
#Component({
moduleId: module.id,
selector: 'modules-left-block',
templateUrl: './modules-left-block.html',
styleUrls: ['modules-left-block.css']
})
export class ModuleLeft implements OnInit {
modules: ModuleModel[] = new ModuleModel();
constructor(private modulesAll: ModuleDataService, private httpService: HttpService) {}
ngOnInit() {
this.getDataModles();
//this.modules = this.modulesAll.getDataModules();
console.log("view");
//console.log(this.modulesAll.getDataModules());
}
onToggle(module: any) {
this.modulesAll.toggleModules(module);
}
getDataModules(): void {
this.httpService.getDataModules().subscribe(((modules) => {
this.modules = modules;
console.log(this.dataModules);
}));
}
}

Broadcast data to multiple unrelated components in Angular2 through single service

I have two unrelated components which uses a single #injectable service.
When specific service method is called. It emits an even. Second components has subscribed that event.
my code is as follow:
Component Bot2:
import { Component, OnInit, NgZone, EventEmitter} from '#angular/core';
import { SpeechEngine} from '../../services/common/Speechengine';
#Component({
selector: 'bot2',
template: '<h3>bot2</h3> <input type="button" value="Emmit" (click)="testEmmiter()"/>',
providers: [],
})
export class Bot2 {
_speechEngine: any
constructor(private zone: NgZone) {
this._speechEngine = new SpeechEngine(this.zone);
this._speechEngine.BotActivation$.subscribe(obj => { this.AutoBotActivation(obj.speechActive) })
}
testEmmiter() {
this._speechEngine.testEmiter();
}
AutoBotActivation(speechActive) {
alert(" Bot2 subscribed function called.")
}
}
#Component({
selector: 'bot3',
template: '<h3>bot3</h3> <input type="button" value="Emmit" (click)="testEmmiter()"/>',
providers: [],
})
export class Bot3 {
_speechEngine: any
constructor(private zone: NgZone) {
this._speechEngine = new SpeechEngine(this.zone);
this._speechEngine.BotActivation$.subscribe(obj => { this.AutoBotActivation(obj.speechActive) })
}
testEmmiter() {
this._speechEngine.testEmiter();
}
AutoBotActivation(speechActive) {
alert(" Bot3 subscribed function called.")
}
}
Service:
#Injectable()
export class SpeechEngine{
BotActivation$: EventEmitter<any> = new EventEmitter<any>()
constructor(private zone: NgZone) { }
testEmiter() {
this.BotActivation$.next({
speechActive: false
});
}
}
my service is added at appModule Providers.
providers: [SpeechEngine]
Problem is when i invoke testEmmiter() from bot2, service emits function and subscription in bot2 catches it. but bot3 is not catching. and voice versa with bot3.
if i am using emitter wrongly, Can someone suggest how to get this functionality. my components are not in any (parent/child) relation. one can be sibling of grand grand grand parent of other.
First create a global publish subscribe Service
import { Injectable, EventEmitter } from '#angular/core';
#Injectable()
export class PubSubService {
emitter: EventEmitter<any> = new EventEmitter();
constructor( ) { }
subscribe(callback) {
return this.emitter.subscribe(callback);
}
publish(event, data?) {
let payload = {
type: event,
data: data
};
this.emitter.emit(payload);
}
}
Subscribe in your component(any component)
constructor( private pubSubService: PubSubService) { }
ngOnInit() {
this.pubSubService.subscribe(event => {
if (event.type === 'event_1') {
// do something
} else if (event.type === 'event_2') {
// do something
}
});
}
Publish event from service/component
this.pubSubService.publish('event_1', "what ever message");

Categories

Resources