Passing/binding data from app component to other components in Angular 2 - javascript

EDIT: Comment by OP:
"Sorry , but I think I had had slight typo in enviroment/environment, sorry for wasting your time ,it seems to work now"
I have having trouble passing data from app components to child component in angular 2 . I recently started toying with angular 2 and trying to understand how it works. I tried to used the concept shown in this tutorial to do pass data to child component
https://angular.io/docs/ts/latest/tutorial/toh-pt3.html
But I think I am missing something
Here is my project: App component:
import { Component, ViewChild } from '#angular/core';
import { WorkflowService } from './components/workflow_display/workflow.service';
import { WorkflowDisplayComponent } from './components/workflow_display/workflow-display.component';
import { PropertyService } from './shared/property.service';
import '../../public/css/styles.css';
#Component({
selector: 'my-app',
template: require('./app.component.html')
})
export class AppComponent {
title = 'Hello World';
#ViewChild("taskDisplay") workflowDisplay: WorkflowDisplayComponent;
myEnvironment: String; //the variable I am trying to bind from
errorMessage: String;
workbenchBaseUrl : String = 'workbenchBaseUrl';
public selectedNavID : String = 'workspace_control_workStreamView';
public isWorkOrdersCollapsed = false;
public isWorkStreamsCollapsed = false;
constructor(private _propertyService : PropertyService){
}
ngOnInit(): void {
this._propertyService.getValue(this.workbenchBaseUrl)
.subscribe(environment => this.myEnvironment = environment,
error => this.errorMessage = <any>error);
}
}
app.component.html
<div>
<div>
<div>
<!--some html-->
<main class="col-sm-9 offset-sm-3 col-md-10 offset-md-2 pt-3 mh-100">
<workflow-display [environment] ="myEnvironment" #taskDisplay></workflow-display>
</main>
</div>
</div>
</div>
WorkDisplay component
import { Component, Input} from '#angular/core';
import { OnInit } from '#angular/core';
import { IGrcTask } from './grc-task';
import { WorkflowService } from './workflow.service';
import { PropertyService } from '../../shared/property.service';
#Component({
selector: 'workflow-display',
template: require('./workflow-display.component.html')
})
export class WorkflowDisplayComponent implements OnInit {
taskMode: string = 'workstream'; // 'workorder' or 'workstream' to currently identify the columns to display
taskQuery: string = 'process=workstream&taskStatus=RUNNING'; // the query parameters to pass to the tasks web service
workbenchUrl: string = 'http://localhost:8081'; // workbench URL
workbenchTaskPage: string = 'wsIndex'; // workbench page to use to open tasks
infoMessage: string;
errorMessage: string;
tasks: IGrcTask[];
currentTask: IGrcTask;
#Input()
environment: String; //the variable I am trying to bind to
workbenchBaseUrl : String = 'workbenchBaseUrl';
constructor() {
}
//called when user clicks a row
openTask(event: any, task: any) {
// this.environment is still undefined
window.open(this.environment + this.workbenchTaskPage + "?taskId=" + task.taskId + "&activitiWorkflow=true");
}
}
WorkDisplay.component.html
<--!some html-->
<tbody *ngIf='(taskMode == "workorder") && tasks && tasks.length'>
<ng-container *ngFor='let task of tasks; let i=index'>
<tr (click)="setCurrentTask($event, task)" (dblclick)="openTask($event, task)"
<--!some html-->
Property.service.ts
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/map';
/**
* Service return Property value/values from the project property file
*
*/
#Injectable()
export class PropertyService {
//ReST Url for the PopertyService on the back end
private _url = '/grcworkflow/resources/grcWorkflow/environment/';
constructor(private _http: Http) {}
/**
* Method return an Observable<String -> Value> for any property
* Method make an http get call to the server to fetch the property
* #Param key for the property in the property file
*/
getValue(key: String): Observable<String> {
return this._http.get(this._url+key)
.map((response: Response) => <String> response.text())
.do(data => console.log('All: ' + data))
.catch(this.handleError);
}
private handleError(error: Response) {
return Observable.throw(error.json().error || 'Server error');
}
}
NOTE I have removed some function definitions and variable from the components which might be irrelevant.
I am trying to bind myEnviroment value of the app.component enviroment value. myEnviroment get set when proerty service returns a string. Although enviroment value still stays undefined .
I am looking for one way binding i.e when myEnvironment(parent) changes environment(child) should change too. But this doesn't seem to happen. Please help out here

Related

Extracting data from model to variables

I'm new to typescript and angular and I was trying to fetch some data from firebase using angularfire2 and assign it to variables to use in some other functions later. I'm only familiar with javascript dot notation where I access members of the object using dot notation seems like it doesn't work with angular can somebody please help me with extracting data from the model to variables, please
I'm still having a hard time understanding Observable and subscribes too.
code
model
export class Reacts {
sad?: number;
happy?: number;
neutral?: number;
}
service
import { Injectable } from "#angular/core";
import {
AngularFirestore,
AngularFirestoreCollection,
AngularFirestoreDocument
} from "angularfire2/firestore";
import { Reacts } from "../models/reacts";
import { Observable } from "rxjs";
#Injectable({
providedIn: "root"
})
export class ReactService {
mapCollection: AngularFirestoreCollection<Reacts>;
reacts: Observable<Reacts[]>;
constructor(public afs: AngularFirestoreDocument) {
this.reacts = this.afs.collection("reacts").valueChanges();
}
getItems() {
return this.reacts;
}
}
component
import { Component, OnInit } from "#angular/core";
import { Reacts } from 'src/app/models/reacts';
import { ReactService } from 'src/app/services/react.service';
#Component({
selector: "app-reacts",
templateUrl: "./reacts.component.html",
styleUrls: ["./reacts.component.css"]
})
export class ReactsComponent implements OnInit {
react: Reacts[];
happy: number;
sad: number;
neutral:number;
constructor(private reactsService: ReactService ) {}
ngOnInit(): void {
this.reactsService.getItems().subscribe(reacts => {
this.react = reacts;
console.log(reacts); //this works print an array object of data from database
this.happy= reacts.happy// what i'm trying to achieve
});
}
}
Ok, I'll break it down for you. You are trying to access .happy but it is actually an array of React[]
ngOnInit(): void {
this.reactsService.getItems().subscribe((reacts:Reacts[]) => { // Note I have defined its model type
this.react = reacts;
console.log(reacts); //this works print an array object of data from database
//this.happy= reacts.happy // Now VS code will show you error itself
this.happy = reacts[0].happy;
});
}
The power of typscript comes as it is strongly typed language. If you'll make changes as below in service, the VS Code will itself explain you the error:
export class ReactService {
mapCollection: AngularFirestoreCollection<Reacts>;
reacts: Observable<Reacts[]>;
constructor(public afs: AngularFirestoreDocument) {
this.reacts = this.afs.collection("reacts").valueChanges();
}
getItems(): Observable<Reacts[]> { // added return type
return this.reacts;
}
}
Once I provide return type of getItems() , you dont even have to define type in .subscribe((reacts:Reacts[]) as I have done in your component.

Asynchronous call in angular using event emitter and services for cross-component communication

cannot store the value received from subscribe method in a template variable.
photo-detail component
import { Component, OnInit, Input } from "#angular/core";
import { PhotoSevice } from "../photo.service";
import { Photo } from "src/app/model/photo.model";
#Component({
selector: "app-photo-detail",
templateUrl: "./photo-detail.component.html",
styleUrls: ["./photo-detail.component.css"]
})
export class PhotoDetailComponent implements OnInit {
url: string;
constructor(private photoService: PhotoSevice) {
this.photoService.photoSelected.subscribe(data => {
this.url = data;
console.log(this.url);
});
console.log(this.url);
}
ngOnInit() {
}
}
the outside console.log gives undefined, and nothing is rendered in the view, but inside the subscibe method i can see the value.So, how can i display it in my view?
photos component
import { Component, OnInit } from "#angular/core";
import { ActivatedRoute, Params, Router } from "#angular/router";
import { FnParam } from "#angular/compiler/src/output/output_ast";
import { AlbumService } from "../service/album.service";
import { Photo } from "../model/photo.model";
import { PhotoSevice } from "./photo.service";
#Component({
selector: "app-photos",
templateUrl: "./photos.component.html",
styleUrls: ["./photos.component.css"]
})
export class PhotosComponent implements OnInit {
selectedAlbumId: string;
photoList: Photo[] = [];
photoSelected: Photo;
isLoading: Boolean;
constructor(
private rout: ActivatedRoute,
private albumService: AlbumService,
private router: Router,
private photoService: PhotoSevice
) { }
ngOnInit() {
this.isLoading = true;
this.rout.params.subscribe((params: Params) => {
this.selectedAlbumId = params["id"];
this.getPhotos(this.selectedAlbumId);
});
}
getPhotos(id: string) {
this.albumService.fetchPhotos(this.selectedAlbumId).subscribe(photo => {
this.photoList = photo;
this.isLoading = false;
});
}
displayPhoto(url: string, title: string) {
console.log(url);
this.photoService.photoSelected.emit(url);
this.router.navigate(["/photo-detail"]);
}
}
please explain me how this works and how to work around it so that i can store and display the value received from subscribing and asynchronous call in a template view.
here are the views of the two components---
photo.component.html
<div *ngIf="isLoading">
<h3>Loading...</h3>
</div>
<div class="container" *ngIf="!isLoading">
<div class="card-columns">
<div *ngFor="let photo of photoList" class="card">
<img
class="card-img-top"
src="{{ photo.thumbnailUrl }}"
alt="https://source.unsplash.com/random/300x200"
/>
<div class="card-body">
<a
class="btn btn-primary btn-block"
(click)="displayPhoto(photo.url, photo.title)"
>Enlarge Image</a
>
</div>
</div>
</div>
</div>
photo-detail.component.ts
<div class="container">
<div class="card-columns">
<div class="card">
<img class="card-img-top" src="{{ url }}" />
</div>
</div>
</div>
photo.service.ts
import { Injectable } from "#angular/core";
import { EventEmitter } from "#angular/core";
#Injectable({ providedIn: "root" })
export class PhotoSevice {
photoSelected = new EventEmitter();
// urlService: string;
}
here is a link to my github repo, i have kept the code in comments and used a different approach there.
If you check the albums component there also i have subscribed to http request and assigned the value in the template variable of albums component.
there also the value comes as undefined oustide the subscibe method, but i am able to access it in template.
https://github.com/Arpan619Banerjee/angular-accelerate
here are the details of albums component and service
pls compare this with the event emitter case and explain me whats the difference--
albums.component.ts
import { Component, OnInit } from "#angular/core";
import { AlbumService } from "../service/album.service";
import { Album } from "../model/album.model";
#Component({
selector: "app-albums",
templateUrl: "./albums.component.html",
styleUrls: ["./albums.component.css"]
})
export class AlbumsComponent implements OnInit {
constructor(private albumService: AlbumService) {}
listAlbums: Album[] = [];
isLoading: Boolean;
ngOnInit() {
this.isLoading = true;
this.getAlbums();
}
getAlbums() {
this.albumService.fetchAlbums().subscribe(data => {
this.listAlbums = data;
console.log("inside subscibe method-->" + this.listAlbums); // we have data here
this.isLoading = false;
});
console.log("outside subscribe method----->" + this.listAlbums); //empty list==== but somehow we have the value in the view , this doesn t work
//for my photo and photo-detail component.
}
}
albums.component.html
<div *ngIf="isLoading">
<h3>Loading...</h3>
</div>
<div class="container" *ngIf="!isLoading">
<h3>Albums</h3>
<app-album-details
[albumDetail]="album"
*ngFor="let album of listAlbums"
></app-album-details>
</div>
album.service.ts
import { Injectable } from "#angular/core";
import { HttpClient, HttpParams } from "#angular/common/http";
import { map, tap } from "rxjs/operators";
import { Album } from "../model/album.model";
import { Observable } from "rxjs";
import { UserName } from "../model/user.model";
#Injectable({ providedIn: "root" })
export class AlbumService {
constructor(private http: HttpClient) {}
albumUrl = "http://jsonplaceholder.typicode.com/albums";
userUrl = "http://jsonplaceholder.typicode.com/users?id=";
photoUrl = "http://jsonplaceholder.typicode.com/photos";
//get the album title along with the user name
fetchAlbums(): Observable<any> {
return this.http.get<Album[]>(this.albumUrl).pipe(
tap(albums => {
albums.map((album: { userId: String; userName: String }) => {
this.fetchUsers(album.userId).subscribe((user: any) => {
album.userName = user[0].username;
});
});
// console.log(albums);
})
);
}
//get the user name of the particular album with the help of userId property in albums
fetchUsers(id: String): Observable<any> {
//let userId = new HttpParams().set("userId", id);
return this.http.get(this.userUrl + id);
}
//get the photos of a particular album using the albumId
fetchPhotos(id: string): Observable<any> {
let selectedId = new HttpParams().set("albumId", id);
return this.http.get(this.photoUrl, {
params: selectedId
});
}
}
I have added console logs in the even emitters as told in the comments and this is the behavior i got which is expected.
Question's a two-parter.
Part 1 - photos and photo-detail component
EventEmitter is used to emit variables decorated with a #Output decorator from a child-component (not a service) to parent-component. It can then be bound to by the parent component in it's template. A simple and good example can be found here. Notice the (notify)="receiveNotification($event)" in app component template.
For your case, using a Subject or a BehaviorSubject is a better idea. Difference between them can be found in my other answer here. Try the following code
photo.service.ts
import { Injectable } from "#angular/core";
import { BehaviorSubject } from 'rxjs';
#Injectable({ providedIn: "root" })
export class PhotoSevice {
private photoSelectedSource = new BehaviorSubject<string>(undefined);
public setPhotoSelected(url: string) {
this.photoSelectedSource.next(url);
}
public getPhotoSelected() {
return this.photoSelectedSource.asObservable();
}
}
photos.component.ts
export class PhotosComponent implements OnInit {
.
.
.
displayPhoto(url: string, title: string) {
this.photoService.setPhotoSelected(url);
this.router.navigate(["/photo-detail"]);
}
}
photo-detail.component.ts
constructor(private photoService: PhotoSevice) {
this.photoService.getPhotoSelected().subscribe(data => {
this.url = data;
console.log(this.url);
});
console.log(this.url);
}
photo-detail.component.html
<ng-container *ngIf="url">
<div class="container">
<div class="card-columns">
<div class="card">
<img class="card-img-top" [src]="url"/>
</div>
</div>
</div>
</ng-container>
Part 2 - albums component and service
The call this.albumService.fetchAlbums() returns a HTTP GET Response observable. You are subscribing to it and updating the member variable value and using it in the template.
From your comment on the other answer:
i understand the behaviour and why the outside console.log is
underfined, its beacuse the execution context is diff for async calls
and it first executes the sync code and then comes the async code
I am afraid the difference between synchronous and asynchronous call is not as simple as that. Please see here for a good explanation of difference between them.
albums.components.ts
getAlbums() {
this.albumService.fetchAlbums().subscribe(data => {
this.listAlbums = data;
console.log("inside subscibe method-->" + this.listAlbums); // we have data here
this.isLoading = false;
});
console.log("outside subscribe method----->" + this.listAlbums); //empty list==== but somehow we have the value in the view , this doesn t work
//for my photo and photo-detail component.
}
albums.component.html
<div *ngIf="isLoading">
<h3>Loading...</h3>
</div>
<div class="container" *ngIf="!isLoading">
<h3>Albums</h3>
<app-album-details
[albumDetail]="album"
*ngFor="let album of listAlbums"
></app-album-details>
</div>
The question was to explain why the template displays the albums despite console.log("outside subscribe method----->" + this.listAlbums); printing undefined. In simple words, when you do outside console log, this.listAlbums is actually undefined in that it hasn't been initialized yet. But in the template, there is a loading check *ngIf="!isLoading". And from the controller code, isLoading is only set to false when listAlbums is assigned a value. So when you set isLoading to false it is assured that listAlbums contains the data to be shown.
I think you are trying to display a selected image in a photo detail component which gets the photo to display from a service.
The question doesn't mention how you are creating the photo detail component.
Is the component created after a user selects a photo to dislay?
Is the component created even before user selects a photo to display?
I think the first is what you are trying to do.
If so there are two things...
When you are subscribing inside the constructor, the code inside the subscribe runs after some time when the observable emits. in the mean time the code after the subscription i.e console.log(url) (the outside one) will run and so it will be undefined.
If the subscription happens after the event is emitted i.e you have emitted the event with url but by then the component didn't subscribe to the service event. so the event is lost and you don't get anything. For this you can do few things
a. Add the photo whose details are to be shown to the url and get it in the photo details component.
b. Convert the subject / event emitter in the service to behavioural subject. This will make sure that even if you subscribe at a later point of time you still get the event last emitted.
c. If the photo details component is inside the template of the photo component send the url as an input param (#Input() binding).
Hope this helps

_co.photo is undefined console error and error context, but code works as expected

I got problem with angular component.
When I make my component with selector, it works as expected: execute httpget, and render photo with title.
But in console I got two errors:
ERROR TypeError: "_co.photo is undefined"
View_PhotoHolderComponent_0 PhotoHolderComponent.html:2
and
ERROR CONTEXT
...
PhotoHolderComponent.html:2:8
View_PhotoHolderComponent_0 PhotoHolderComponent.html:2
I got html:
<div class="photo-holder">
<h2>{{photo.title}}</h2>
<img src="{{photo.url}}">
</div>
and ts:
import { Component, OnInit } from '#angular/core';
import { Photo } from './photo'
import { PhotoDeliveryService } from '../photo-delivery-service.service'
#Component({
selector: 'app-photo-holder',
templateUrl: './photo-holder.component.html',
styleUrls: ['./photo-holder.component.css']
})
export class PhotoHolderComponent implements OnInit {
photo:Photo
constructor( private photoService : PhotoDeliveryService) {
}
ngOnInit() {
this.photoService.getRandomPhoto().subscribe((data: Photo) => this.photo = {...data})
}
}
and service :
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Photo } from './photo-holder/photo'
#Injectable({
providedIn: 'root'
})
export class PhotoDeliveryService {
value : Number
url : string
constructor(private http: HttpClient) {
this.url = "https://jsonplaceholder.typicode.com/photos/";
this.value = Math.floor(Math.random() * 10) + 1;
}
getRandomPhoto() {
return this.http.get<Photo>(this.getUrl())
}
getUrl(){
return this.url + this.value;
}
}
I suspect that could be made by binding property before query results was returned.
How can I rid off this problem, can I wait for this query, or this is different kind of problem ?
You are getting the error because before your service could resolve, the template bindings are resolved and at that time photo object is undefined.
first thing, you can initialize the photo object but then you might have to detect the changes using ChangeDetectorRef to reflect the value returned by the service.
photo:Photo = {
title:'',
url:''
};
constructor( private photoService : PhotoserviceService, private cdr:ChangeDetectorRef) {
}
ngOnInit() {
this.photoService.getRandomPhoto().subscribe((data: Photo) => {
this.photo = data;
this.cdr.detectChanges();
});
}

Unable to build angular project - Proper does not exist on component

I am having an issue I do not understand at all. I am fairly new angular so it may be something small but never the less.
When I try to build my project to publish it to a github page, the HTML components are failing on the build as the properties from the component do not exist. All of the errors relate to the HTML components not being away of the object properties. (Which are provided via an API service anyway!)
I have attempted to provide the minimum required code to illustrate the problem.
Error Dump:
ERROR in src\app\users\users.component.html(4,20): : Property 'queryString' does not exist on type 'UsersComponent'.
src\app\users\users.component.html(9,7): : Property 'queryString' does not exist on type 'UsersComponent'.
src\app\users\users.component.html(4,20): : Property 'queryString' does not exist on type 'UsersComponent'.
src\app\details\details.component.html(1,5): : Property 'name' does not exist on type 'Object'.
src\app\details\details.component.html(4,32): : Property 'RunnerName' does not exist on type 'Object'.
src\app\details\details.component.html(5,29): : Property 'LastTime' does not exist on type 'Object'.
src\app\details\details.component.html(6,29): : Property 'LastDistance' does not exist on type 'Object'.
src\app\details\details.component.html(7,29): : Property 'date' does not exist on type 'Object'.
user.component.html
<h1>Runners</h1>
<div>
<input type="text" [(ngModel)]="queryString" placeholder = "Search Runner Name">
</div>
<ul>
<li *ngFor = "let user of users | filterdata: queryString : 'RunnerName' ; let i = index">
<a routerLink = "/details/{{ user.RunnerId }}">{{ user.RunnerName }}</a>
<ul>
<li><strong>Runner ID: {{ user.RunnerId }}</strong></li>
</ul>
</li>
</ul>
user.component.ts
import { Component, OnInit } from '#angular/core';
//Importing my users service, up one level in project structure from here.
import { DataService } from '../data.service';
//RXJS will hold the data which is returned from the API...
//RESEARCH RXJS
import { Observable } from 'rxjs';
import { FormsModule } from '#angular/forms';
import { Pipe, PipeTransform } from '#angular/core';
#Component({
selector: 'app-users',
templateUrl: './users.component.html',
styleUrls: ['./users.component.scss']
})
//Export class implenets OnInit.
export class UsersComponent implements OnInit {
//Prop which holds returned API data
//of type obect.
users: Object;
//Creating instance of the service via dependancy injection.
constructor(private data: DataService) { }
//NG on init is one of the "lifecycle hooks" for angular components.
//Code in here will be executed when the component loads for ngOnInit.
ngOnInit() {
//Executing the method which is provided by the service.
//Adding data bind via subscribe.
this.data.getUsers().subscribe(
//returning the user data via single line return function
//passing the data value into the function.
(data) => {
//assinging the data to the user object.
this.users = data
//sorting the users object by runner ID.
//this.users.sort((a,b) => a.RunnerId - b.RunnerId);
}
);
}
}
data.service.ts
import { Injectable } from '#angular/core';
//Importing te angular HTTP Client
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
//Class which exports the service to the APP.
//We will import this class into the components when required.
export class DataService {
//Utilising the HTTP client import Class
//HTTP Client request expects JSON return data as default, their is no need to parse JSON anymore.
constructor(private http: HttpClient) {}
//Custom Method to return Users collection from the web API.
getUsers(){
//single line return statement.
return this.http.get('http://rundistance.azurewebsites.net/api/RunnerService')
}
//Function to return the detail of a single user, passing in the ID prop of currently selected target of objects master layer.
getUser(userId){
//single line return statement getting target object from API.
return this.http.get('http://rundistance.azurewebsites.net/api/RunnerService/'+userId)
}
//Returning posts from API.
getPosts(){
//single line return statement.
return this.http.get('https://jsonplaceholder.typicode.com/posts')
}
}
filterdata.pipe
import { Pipe, PipeTransform } from '#angular/core';
import { DataService } from './data.service';
#Pipe({
name: 'filterdata'
})
export class FilterdataPipe implements PipeTransform {
transform(items: any[], value: string, label:string): any[] {
if (!items) return [];
if (!value) return items;
if (value == '' || value == null) return [];
return items.filter(e => e[label].toLowerCase().indexOf(value) > -1 );
}
}

Cannot read property 'version' of undefined angular2

I am having a hard time using a async object in a html composition.
Here is my model:
export class Version {
isGood: boolean;
constructor(isGood: boolean) {
this.isGood= isGood;
}
}
This model is called by a component as follows:
#Injectable()
export class MyComponent {
public version: Version;
constructor(private _myService: VersionService) {}
getVersion(): void {
// async service that gets the versions
this._myService.getVersion().subscribe(
data => this.version= data,
error=> console.log(error),
() => console.log("getting all items complete")
);
}
}
My template references to the version variable as follows:
<button (click)="getVersion()">Get Version</button>
<hr>
<p style="color:red">{{error}}</p>
<h1>Version</h1>
<p>{{version.isGood}}</p>
However, I get an exception:
Cannot read property 'isGood' of undefined
From scavenging the internet, I see that my problem is because the version object is null. If I do something like:
<p>{{version | json}}</p>
I can see the correct version
If I do something like
<p>{{version.isGood | async}}</p>
I see nothing
If I edit MyComponent, and set
public version: Version = new Version();
I can execute the .isGood property fetch, but it is always empty.
Is there a different way I am supposed to load a property if I am using it in an asynchronous manner?
Use the ? operator or use an *ngIf.
<p>{{version?.isGood}}</p>
<p *ngIf="version">{{version.isGood}}</p>
Try this:
<p>{{version?.isGood}}</p>
This tells Angular to protect against version.isGood being undefined or null until you click and fetch the data for version through your service.
First me correct you. #Injectable() makes a normal typescript class as injectable service where you can share data.
To make a component you need to use #Component decoratore.
The process of data sharing between component and within the application is to create a service and add that as provides in module. And then its singleton object will available everyshere.
//module
import {NgModule} from '#angular/core';
import {YourService} from "./services/your-service";
#NgModule({
imports: [
BrowserModule
],
declarations: [
AppComponent
],
providers: [
YouService
],
bootstrap: [AppComponent]
})
export class AppModule {
}
//this is your component
import {Component} from '#angular/core';
import {YourService} from "../../services/your-service";
#Component({
selector: 'component-app',
templateUrl: '../../views/app.component.html',
})
export class HeaderComponent {
constructor(public yourService: YourService) {
}
}
//your service
import {Injectable} from "#angular/core";
#Injectable()
export class YourService {
private _message: string = 'initial message';
private _style: string = 'success';
get message(): string {
return this._message;
}
set message(value: string) {
this._message += value;
}
get style(): string {
return this._style;
}
set style(value: string) {
this._style = value;
}
}
//finally your view
<div class="row">
<div [class]=""><h1>{{swapService.message}}</h1></div>
</div>
Observable Data services.
#Injectable()
export class MyComponent {
public version = new ReplaySubject<Version>();
constructor(private _myService: VersionService) {}
init(): void {
// async service that gets the versions
this._myService.getVersion().subscribe(
data => this.version.next(data),
error=> console.log(error),
() => console.log("getting all items complete")
);
}
getVersion(): void {
this.version.asObservable();
}
}
In the template
<button (click)="init()">Get Version</button>
<hr>
<p style="color:red">{{error}}</p>
<h1>Version</h1>
<p>{{(version |async)?.isGood}}</p>

Categories