Shared Service and asynchronous data in Angular 2 - javascript

I have a problem with getting data via Shared Service
I have a Shared Service
#Injectable()
export class SharedService {
public title;
constructor() {
this.title = "";
}
public setData(val: string): void {
this.title = val;
}
public getUrlHistoryObj(): string {
return this.title;
}
}
A component FillComponent in which I get data from DataService (it works, it gets data and it actually sets data, tested it with console.log)
export class FillComponent implements OnInit {
#Input() title: any;
constructor(public info: InfoComponent, public shared: SharedService) {
}
ngOnInit() {
this.shared.setData(this.title); }
}
I get data from PartComponent
export class Part2Component implements OnInit {
#ViewChild(FillInBlankComponent) private fill: FillComponent;
#ViewChild(InfoComponent) private info: InfoComponent;
public title: string;
constructor(public dataService: DataService, public shared: SharedService) {
this.dataService.get().subscribe(data => {
const d = this.dataService.convert(data, 2);
this.title = d[0];
});
}
Till now everything works fine.
But the problem is here, in InfoComponent, when I try to get data it gives me empty result.
#Injectable()
export class InfoComponent implements OnChanges, OnInit, OnDestroy {
public title: string;
constructor(public shared: SharedService) {
this.title = this.shared.getUrlHistoryObj();
}
ngOnInit() {
console.log('i am title from info and i am boos')
console.log(this.title)
}
}
I guess the problem is in asynchronous loading. How could I fix it?

On info component, move this line outside the constructor, to the ngOnInit:
this.title = this.shared.getUrlHistoryObj();

Related

How to fix "Cannot read property '...' of undefined" when calling angular service method inside template

I created a new service in my project and I added some functions to it.
When I tried to call a service function from my component template I got this error "Cannot read property 'isCompanyEligible' of undefined"
I tried to create new function inside my component and assign the service function to it but I got the same error.
This is my service:
import { FinancialHealth } from 'src/app/shared/models/financial-health';
import { LocalStoreService } from 'src/app/shared/services/local-store.service';
import {Application} from './../models/application';
import {Injectable} from '#angular/core';
import { NgbDateParserFormatterService} from './ngb-date-parser-formatter.service ';
#Injectable({
providedIn: 'root'
})
export class EligibilityService {
application: Application;
activityAreas = [];
areasEligibility = [];
legalForms = [];
jobPositions = [];
constructor(
private ls: LocalStoreService,
private dateService: NgbDateParserFormatterService
) {
this.application = this.ls.getItem('application');
const {
activity_areas,
legal_forms,
job_positions,
areas_eligiblity
} =
this.ls.getItem('shared_data').data;
this.activityAreas = activity_areas;
this.legalForms = legal_forms;
this.jobPositions = job_positions.filter(job => job.is_management_position ==
1);
this.areasEligibility = areas_eligiblity;
}
public isCompanyEligible(application ? ) {
if (application) {
this.application = application;
}
if (!this.application || (!this.application.company)) {
return null;
}
const company = this.application.company;
let age;
if (typeof this.application.company.established_at == 'object') {
const date =
this.dateService.format(this.application.company.established_at);
age = this.getAge(date);
} else {
age = this.getAge(company.established_at)
}
return this.legalForms.includes(company.legal_form) && (age >= 2 && age <=
5);
}
growthRate(firstYear, secondYear) {
if (!firstYear || !secondYear) {
return 0;
}
return Math.round(((secondYear - firstYear) / firstYear) * 100);
}
}
This is my component.ts:
import { Component, OnInit } from '#angular/core';
import { CustomValidators } from 'ng2-validation';
import { FormGroup, FormBuilder, FormControl } from '#angular/forms';
import { ToastrService } from 'ngx-toastr';
import { DataLayerService } from 'src/app/shared/services/data-layer.service';
import { BreadcrumbService } from '../../../shared/services/breadcrumb.service';
import { EligibilityService } from 'src/app/shared/services/eligibility.service';
#Component({
selector: 'app-form-sommaire',
templateUrl: './sommaire.component.html',
styleUrls: ['./sommaire.component.scss']
})
export class SommaireFormComponent implements OnInit {
formBasic: FormGroup;
loading: boolean;
radioGroup: FormGroup;
sharedData: any;
isValid: Boolean = false;
application: any;
breadcrumb: { label: string; route: string; }[];
title: String = 'Sommaire';
constructor(
private fb: FormBuilder,
private toastr: ToastrService,
private ls: LocalStoreService,
private appService: ApplicationService,
private data: BreadcrumbService,
public eligibility: EligibilityService
) { }
}
This is my HTML template:
<div class="col-lg-2">
<i *ngIf="eligibility.isCompanyEligible()" class="icon ion-ios-checkmark-circle large-success"></i>
<i *ngIf="eligibility.isCompanyEligible() === false" class="icon ion-ios-close-circle large-danger"></i>
<i *ngIf="eligibility.isCompanyEligible() == null" class="icon ion-md-alert large-warning"></i>
</div>
Anything marked as private cannot be accessed by the component's template either. (Private members can be accessed when using JIT, such as at development time, but not when using AOT, such as for production.)
Actually, best practice is to wrap any service properties/methods in a component property/method and have the template bind to/call the component's property or method to access the service data.
Something like this:
get isCompanyEligible(): boolean {
return this.eligibility.isCompanyEligible();
}
and use it in your template: - <i *ngIf="isCompanyEligible()"
OR
Make the EligibilityService injection public in constructor of component, to access inside template:
constructor(
private fb: FormBuilder,
private toastr: ToastrService,
private ls: LocalStoreService,
private appService: ApplicationService,
private data: BreadcrumbService,
public eligibility: EligibilityService
) { }

share data from service to component after render the function in angular 4

i have service, in service, I have a "cohortTabsResult" method whitch sets the charts array. i want to use this arry in "chart.component"
export class CohortService {
public charts: Array<any>;
cohortTabsResult(obj){
this.charts = []
const subscription = this.cohortDataReq(obj).subscribe(res => {
if(res.status !== 500){
const dataObj = {
definedChart: obj.graph_type,
definedChartData: []
};
this.charts.push(dataObj);
const response = res.json()
//console.log(response)
if (response.error) {
//this.isLoaded = false;
}
else{
Array.prototype.forEach.call(response.data, dataRes => {
const newData = this.getChartDataFormat(dataRes, obj.graph_type, "userType")
dataObj.definedChartData = _.cloneDeep(newData);
});
}
}
});
}
}
and this is my chart.component here I am getting the empty array.
export class ChartCohortComponent implements OnInit{
charts: any;
constructor(private cohortService: CohortService, private route:
Router, public activatedRoute: ActivatedRoute) {
this.charts = this.cohortService.charts;
}
ngOnInit(){
console.log("ch", this.charts)
}
}
import CohortService to your component, add it to the providers in #component, now you can access the variables inside the service. :D
import { CohortService } from '../../cohort.services'; // whatever the path is..
#Component({
selector: '',
templateUrl: '',
styleUrls: [''],
providers: [CohortService]
})
export class ChartCohortComponent implements OnInit{
charts: any;
constructor(private cohortService: CohortService, private route:
Router, public activatedRoute: ActivatedRoute) {
this.charts = this.cohortService.charts;
}
ngOnInit(){
console.log("ch", this.charts)
}
}

Angular - communication from child-component to parent

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)
});
}

Angular 4 - (onclick) pass parameter to a service

I am using Angular 4 and I was wondering how to pass a parameter value to a Service.
For example:
<button (onClick)="doSomething('myParameter')">Send this to Service</button>
Then the service would get it.
I currently have this:
import { Injectable } from '#angular/core';
#Injectable()
export class MessageService {
constructor() { }
message() {
return 'This data goes to the component';
}
}
and then get is like this:
export class AppComponent implements OnInit {
constructor(private messageService: MessageService) {}
ngOnInit() {
console.log(this.messageService.message);
}
}
but this only sends data to the component.
How do I do this?
Your template should talk to your component class and your component class should talk to your service.
I see you have a doSomething method in your template that is not defined in your component?
You need something like this:
Component 1
export class AppComponent implements OnInit {
constructor(private messageService: MessageService) {}
ngOnInit() {
}
doSomething(message: string): void {
this.messageService.message = message;
}
}
Service
import { Injectable } from '#angular/core';
#Injectable()
export class MessageService {
message: string;
constructor() { }
}
Component 2
export class AppComponent implements OnInit {
get message(): string {
return this.messageService.message;
}
constructor(private messageService: MessageService) {}
ngOnInit() {
}
}

myworkout: Property does not exist on type

Got a problem. everything is fine except for this line of code:
"this.workoutService.deleteWorkout(workoutId).subscribe(data => {
this.result = data;"
Specifically, "workoutService"...it says "Property 'workoutService' does not exist on type 'WorkoutDetailsPage'."
from this code (WorkoutDetailsPage):
import { Component } from '#angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { WorkoutService } from '../../app/services/workout.service';
import { WorkoutsPage } from '../workouts/workouts'
#Component({
selector: 'workout-details',
templateUrl: 'workout-details.html'
})
export class WorkoutDetailsPage {
public workout: any;
public result: any;
constructor(public navCtrl: NavController, public params:NavParams, workoutService:WorkoutService) {
this.workout = params.get('workout');
}
deleteWorkout(workoutId){
this.workoutService.deleteWorkout(workoutId).subscribe(data => {
this.result = data;
});
this.navCtrl.push(WorkoutsPage);
}
}
The outcome is this:
enter image description here
Any parameters to the constructor that do not have access modifiers will not be added as a class member. Simply add private or public to your workout service parameter in the constructor:
constructor(public navCtrl: NavController, public params: NavParams, private workoutService: WorkoutService)

Categories

Resources