I am new to Angular and Ionic. I am looping through an array of content that is store in my Firestore database. When the app recompiles and loads, then I go to the settings page (that's where the loop is happening), I see the array of content just fine. I can update it on Firestore and it will update in real time in the app. It's all good here. But if I click "Back" (because Settings is being visited using "navPush"), then click on the Settings page again, the whole loop content will be gone.
Stuff is still in the database just fine. I have to recompile the project to make the content appear again. But once again, as soon as I leave that settings page, and come back, the content will be gone.
Here's my code:
HTML Settings page (main code for the loop):
<ion-list>
<ion-item *ngFor="let setting of settings">
<ion-icon item-start color="light-grey" name="archive"></ion-icon>
<ion-label>{{ setting.name }}</ion-label>
<ion-toggle (ionChange)="onToggle($event, setting)" [checked]="setting.state"></ion-toggle>
</ion-item>
</ion-list>
That Settings page TS file:
import { Settings } from './../../../models/settings';
import { DashboardSettingsService } from './../../../services/settings';
import { Component, OnInit } from '#angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
#IonicPage()
#Component({
selector: 'page-dashboard-settings',
templateUrl: 'dashboard-settings.html',
})
export class DashboardSettingsPage implements OnInit {
settings: Settings[];
checkStateToggle: boolean;
checkedSetting: Settings;
constructor(public dashboardSettingsService: DashboardSettingsService) {
this.dashboardSettingsService.getSettings().subscribe(setting => {
this.settings = setting;
console.log(setting.state);
})
}
onToggle(event, setting: Settings) {
this.dashboardSettingsService.setBackground(setting);
}
}
And my Settings Service file (the DashboardSettingsService import):
import { Settings } from './../models/settings';
import { Injectable, OnInit } from '#angular/core';
import * as firebase from 'firebase/app';
import { AngularFireAuth } from 'angularfire2/auth';
import { AngularFirestore, AngularFirestoreCollection, AngularFirestoreDocument } from 'angularfire2/firestore';
import { Observable } from 'rxjs/Observable';
#Injectable()
export class DashboardSettingsService implements OnInit {
settings: Observable<Settings[]>;
settingsCollection: AngularFirestoreCollection<Settings>;
settingDoc: AngularFirestoreDocument<Settings>;
public checkedSetting = false;
setBackground(setting: Settings) {
if (this.checkedSetting == true) {
this.checkedSetting = false;
} else if(this.checkedSetting == false) {
this.checkedSetting = true;
};
this.settingDoc = this.afs.doc(`settings/${setting.id}`);
this.settingDoc.update({state: this.checkedSetting});
console.log(setting);
}
constructor(private afAuth: AngularFireAuth,private afs: AngularFirestore) {
this.settingsCollection = this.afs.collection('settings');
this.settings = this.settingsCollection.snapshotChanges().map(changes => {
return changes.map(a => {
const data = a.payload.doc.data() as Settings;
data.id = a.payload.doc.id;
return data;
});
});
}
isChecked() {
return this.checkedSetting;
}
getSettings() {
return this.settings;
}
updateSetting(setting: Settings) {
this.settingDoc = this.afs.doc(`settings/${setting.id}`);
this.settingDoc.update({ state: checkedSetting });
}
}
Any idea what is causing that?
My loop was in a custom component before, so I tried putting it directly in the Dashboard Settings Page, but it's still not working. I have no idea what to check here. I tried putting the :
this.dashboardSettingsService.getSettings().subscribe(setting => {
this.settings = setting;
})
...part in an ngOninit method instead, or even ionViewWillLoad, and others, but it's not working either.
I am using Ionic latest version (3+) and same for Angular (5)
Thank you!
From the Code you posted i have observed two findings that might be the potential cause for the issue ,
Calling of the Service method in the constructor :
When your setting component is created , then that constructor will be called but but if you were relying on properties or data from child components actions to take place like navigating to the Setting page so move your constructor to any of the life cycle hooks.
ngAfterContentInit() {
// Component content has been initialized
}
ngAfterContentChecked() {
// Component content has been Checked
}
ngAfterViewInit() {
// Component views are initialized
}
ngAfterViewChecked() {
// Component views have been checked
}
Even though you add your service calling method in the life cycle events but it will be called only once as you were subscribing your service method in the constructor of the Settings service file . so just try to change your service file as follows :
getSettings() {
this.settingsCollection = this.afs.collection('settings');
this.settingsCollection.snapshotChanges().map(changes => {
return changes.map(a => {
const data = a.payload.doc.data() as Settings;
data.id = a.payload.doc.id;
return data;
});
});
}
Update :
Try to change the Getsettings as follows and please do update your question with the latest changes
getSettings() {
this.settingsCollection = this.afs.collection('settings');
return this.settingsCollection.snapshotChanges().map(changes => {
return changes.map(a => {
const data = a.payload.doc.data() as Settings;
data.id = a.payload.doc.id;
return data;
});
});
}
I'm not certain, but I suspect the subscription to the settings observable settings: Observable<Settings[]> could be to blame. This may work on the first load because the DashboardSettingsService is being created and injected, therefore loading the settings, and then emitting an item (causing your subscription event in DashboardSettingsPage to fire).
On the second page load, DashboardSettingsService already exists (services are created as singletons by default) - this means that the constructor does not get called (which is where you set up your observable) and therefore it does not emit a new settings object for your component.
Because the Observable does not emit anything, the following event will not be fired, meaning your local settings object is never populated:
this.dashboardSettingsService.getSettings().subscribe(setting => {
this.settings = setting;
console.log(setting.state);
})
You could refactor your service with a method that provides the latest (cached) settings object, or a new Observable (dont forget to unsubscribe!!), rather than creating a single Observable which will only be triggered by creation or changes to the underlying storage object.
Here's a simple example that doesnt change your method signature.
import { Settings } from './../models/settings';
import { Injectable, OnInit } from '#angular/core';
import * as firebase from 'firebase/app';
import { AngularFireAuth } from 'angularfire2/auth';
import { AngularFirestore, AngularFirestoreCollection, AngularFirestoreDocument } from 'angularfire2/firestore';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
#Injectable()
export class DashboardSettingsService implements OnInit {
settings: Observable<Settings[]>;
cachedSettings: Settings[];
settingsCollection: AngularFirestoreCollection<Settings>;
settingDoc: AngularFirestoreDocument<Settings>;
public checkedSetting = false;
setBackground(setting: Settings) {
if (this.checkedSetting == true) {
this.checkedSetting = false;
} else if(this.checkedSetting == false) {
this.checkedSetting = true;
};
this.settingDoc = this.afs.doc(`settings/${setting.id}`);
this.settingDoc.update({state: this.checkedSetting});
console.log(setting);
}
constructor(private afAuth: AngularFireAuth,private afs: AngularFirestore) {
this.settingsCollection = this.afs.collection('settings');
this.settings = this.settingsCollection.snapshotChanges().map(changes => {
return changes.map(a => {
const data = a.payload.doc.data() as Settings;
data.id = a.payload.doc.id;
this.cachedSettings = data;
return data;
});
});
}
isChecked() {
return this.checkedSetting;
}
getSettings() {
return Observable.of(this.cachedSettings);
}
updateSetting(setting: Settings) {
this.settingDoc = this.afs.doc(`settings/${setting.id}`);
this.settingDoc.update({ state: checkedSetting });
}
}
Related
I'm having this isue only when i deploy to android (didn't tried on iOS), if i run ionic serve to view if all is fine, console doesn't throw me any error and working fine!, but when i try it in android, i have the issue:
Cannot read property 'next' of undefined
ok, let's make a description, first of all, i'm using the integrated ionic starter template side_menu, i have made some style modifications, (but only that), so let's view each component needed to reproduce this issue:
app.component.html:
here i only put an ionDidClose event in the ion-menu element, (other things in the document are not neccesary at all):
<ion-menu class = "shorted_menu" (ionDidClose) = "setDisplayMenuInfo('basicInfo')">
<!--More code here...-->
</ion-menu>
in app.component.ts i have:
import { Component } from '#angular/core';
import { Platform } from '#ionic/angular';
import { SplashScreen } from '#ionic-native/splash-screen/ngx';
import { StatusBar } from '#ionic-native/status-bar/ngx';
import { enableProdMode } from '#angular/core';
import { MenuController } from '#ionic/angular';
import { Storage } from '#ionic/storage';
import { Router} from '#angular/router';
import { OneSignal } from '#ionic-native/onesignal/ngx';
import { AppPages } from '../global_modules/app_pages';
import { showInfo, setComponentBehaviorSubject } from '../global_modules/menu_functionality';
import { BehaviorSubject, Observable, Subscription } from 'rxjs';
enableProdMode();
#Component({
selector: 'app-root',
templateUrl: 'app.component.html'
})
export class AppComponent {
public appPages;
public showInfo;
public currentDisplayMenu = 'basicInfo';
public behaviorSubject: BehaviorSubject<string>;
public behaviorSubjectObservable: Observable<any>;
public behaviorSubjectSubscription: Subscription;
public setComponentBehaviorSubject;
constructor(
private platform: Platform,
private splashScreen: SplashScreen,
private statusBar: StatusBar,
private oneSignal: OneSignal,
private storage: Storage,
private router: Router,
public menu: MenuController
)
{
this.initializeApp();
}
async setup(){
this.appPages = AppPages.pages;
this.showInfo = showInfo;
this.setComponentBehaviorSubject = setComponentBehaviorSubject;
this.userData = await this.getUserData();
this.userAvatar = this.userData.data.avatar_src.src && this.userData.data.avatar_src.src != "" ?
`${this.imagesRoute}${this.userData.data.avatar_src.src}`:
this.userAvatar;
this.behaviorSubject = new BehaviorSubject<string>('basicInfo');
this.behaviorSubjectObservable = this.behaviorSubject.asObservable();
this.setComponentBehaviorSubject(this.behaviorSubject);
this.behaviorSubjectSubscription = this.behaviorSubjectObservable.subscribe(data =>{
this.currentDisplayMenu = data;
});
}
ionViewWillLeave(){
this.behaviorSubjectSubscription.unsubscribe();
}
setDisplayMenuInfo(str){
this.showInfo(str);
}
async getUserData(){
return await this.storage.get('session_storage');
}
clearUserSession(){
this.oneSignal.removeExternalUserId();
this.storage.set('session_storage', null);
}
initializeApp() {
this.platform.ready().then(() => {
this.statusBar.styleLightContent();
this.splashScreen.hide();
this.setup();
if(this.platform.is('cordova')){
this.setupPush();
}
this.storage.get('session_storage').then((res)=>{
if(res == null){
this.router.navigateByUrl('log-in');
}
});
});
}
setupPush(){
this.oneSignal.startInit(oneSignalData.appId, oneSignalData.googleProjectNumber);
this.oneSignal.inFocusDisplaying(this.oneSignal.OSInFocusDisplayOption.Notification);
this.oneSignal.handleNotificationReceived().subscribe(data => {
//Do something when notification received...
/*let msg = data.payload.body;
let title = data.payload.title;
let additionalData = data.payload.additionalData;*/
});
this.oneSignal.handleNotificationOpened().subscribe(data => {
let additionalData = data.notification.payload.additionalData;
//Actions to take when notification opened...
});
this.getUserData().then(res =>{
if(res && res.data.username != "" && res.data.type_user != ""){
this.oneSignal.setExternalUserId(`${res.data.username};${res.data.type_user}`);
}else{
this.oneSignal.removeExternalUserId();
}
})
this.oneSignal.endInit();
}
}
where AppPages is simply another class imported by app.component.ts and inside i having the public static property pages, this is simply an array of objects, and inside each object i have some menu display properties, like the title and icon of each menu item, also, having another property, called detailTag, this tag allows me to easily show or hide some content of the menu depending to the property:
currentDisplayMenu
of app.component.ts, so some menu info is clasified by 'basicInfo' inside detailTag property, this means that when currentDisplayMenu have content 'basicInfo', i will only show the menu items that have the detailTag matching by 'basicInfo', the other clasification is 'accountInfo'.
Well, other file that is needed is menu_functionality.ts, which looks like:
import { BehaviorSubject } from 'rxjs';
var componentBehaviorSubject:BehaviorSubject<string>;
export function showInfo(tag){
switch(tag){
case 'basicInfo':
return componentBehaviorSubject.next('basicInfo');
break;
case 'accountInfo':
let CBS = componentBehaviorSubject.next('accountInfo');
this.menu.open();
return CBS;
break;
}
}
export function setComponentBehaviorSubject(behaviorSubject:BehaviorSubject<string>){
componentBehaviorSubject = behaviorSubject;
}
The reason of why i'm calling the this.menu.open(); function only when the tag is 'accountInfo', is because, the app.component.html and app.component.ts are working globaly in the app and if the user clicks only in the sidemenu button to open it there is no problem and no need to put it, but here is the thing and the real reason of why i'm using BehaviorSubject:
App.component.html and app.component.ts are shared, so there are no problems if the user hits in the menu opener button in one or other page of the app, but... the way i'm showing other info like 'accountInfo' is using an avatar which is not inside of app.component.html (is not shared) i wanted to put in another place instead of putting it in the menu, this is because i didn't know how to make it globally usable like app.component.html, so i have to write that html in each page.html that i want to use it.
and when user hits the avatar i need to only show the 'accountInfo' items in the menu and obviously open it, (this is why i only call this.menu.open when the tag is accountInfo), i don't know if there is another better way to make this.
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 am programming an Angular2 application and I want to handle the back and forward button from the browser.
The idea is to write in the console a message on "back" click and different message on "forward" click.
I used this code:
import { Location } from '#angular/common';
export class AppComponent implements OnInit {
constructor(private location: Location) {}
ngOnInit() {
this.location.subscribe(x => { [custom message] });
}
}
The Problem is: I cannot recognize the click if it is back or forward to write the correct message in the console.
How can I check it in angular2? I don't know what should I exactly search on google. All the answers were about to handle the event but to differentiate it.
P.S. it works for me if it is in javascript.
Thank you.
I needed to differentiate between back and forward buttons in Angular (5) also, in my case for animating route transitions. I couldn't find a solution, so here's one I came up with.
Add the following to a service.
private popState: boolean = false;
private urlHistory: string[] = [];
private popSubject: Subject<boolean> = new Subject();
constructor(private location: Location, private router: Router) {
location.subscribe(event => {
let fwd = false;
if (this.urlHistory.lastIndexOf(event.url)) {
this.urlHistory.push(event.url);
}
else {
fwd = true;
this.urlHistory.pop();
}
this.popState = true;
this.popSubject.next(fwd);
})
router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
if (!this.popState)
this.urlHistory = [this.router.url];
this.popState = false;
}
})
}
get popEvent$() {
return this.popSubject.asObservable();
}
Imports:
import { Location } from '#angular/common';
import { NavigationEnd, Router } from '#angular/router';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
Remove popSubject and popEvent$ if you don't need to listen for the event externally.
I am trying to pass the string value of this.title from my LandingPage.component to my ResultPage.component.
I retrieve the list.show value, and send it to my TitleService in like so in my:
landingpage.component.html
<ol>
<li (click)="selectShow(list.show)" [routerLink]="['/details', list.id]" *ngFor="let list of shows">{{list.show}}
</li>
</ol>
landingpage.component.ts
import { TitleService } from '../../services/title.service';
constructor(private TitleService: TitleService) {}
selectShow(show) {
this.TitleService.fetchTitle(show)
}
The above sends the list.show value to my:
title.service.ts
// this gives us the name of the clicked show, which we send to TitleResolver
#Injectable()
export class TitleService {
fetchTitle(title) {
console.log("title is " + title); // this outputs correctly
return title;
}
}
And here is how I manage the routing in my:
app-routing.module.ts
import { TitleService } from './services/title.service';
const routes: Routes = [
{ path: '', component: LandingPage },
{
path: 'details/:id', component: ResultPage
}
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
providers: [TitleService]
})
My question
Once I receive the title.show value in my service component, I'm unsure how to then send it to my receiving component (resultpage.component)
How can I send my title value from my service to my ResultPage.component?
Make the title a public property of the service like this:
// this gives us the name of the clicked show, which we send to TitleResolver
#Injectable()
export class TitleService {
selectedTitle: string;
fetchTitle(title) {
console.log("title is " + title); // this outputs correctly
this.selectedTitle = title;
return title; // No need to return it.
}
}
Then any other component can inject this service and access this.titleService.selectedTitle
In title.service.ts you can declare a variable called title and have setter and getter:
title: string ="";
// replace fetchTitle with setTitle
// remember to change it in the component too
setTitle(title) {
this.title = title;
}
getTitle() {
return this.title;
}
Then, when ResultPage.component is initialized, call getTitle() from TitleService and set the result to a variable declared in the component.
Here's an example of sharing data via shared services.
Separation of concerns... Your landing page is used to select the list item and navigate to the result page. Let it do just that and only that. Let the ResultPage.component do the rest. Note: Other answers recommend storing the value of the last title in the TitleService. It's not a good idea to store state in a service. Then TitleService cannot be used as a generic way to get any title separate from your current navigation, without side effects.
Remove (click) event. Add 'show' as a QueryParam.
landingpage.component.html
<li [routerLink]="['/details', list.id]"
[queryParams]="{show: list.show}"
*ngFor="let list of shows">
{{list.show}}
</li>
Subscribe to router params and queryparams to get the id and show.
resultpage.component.ts
import { Component, OnInit, OnDestroy } from '#angular/core';
import { ActivatedRoute, Router } from '#angular/router';
import { TitleService } from '../../services/title.service';
#Component({
...
})
export class ResultPageComponent implements OnInit, OnDestroy {
itemId: string;
show: string;
subParams: any; // infinite Observable to be unsubscribed
subQueryParams: any; // infinite Observable to be unsubscribed
constructor(
...
private TitleService: TitleService,
protected route: ActivatedRoute,
protected router: Router,
...
) {}
ngOnInit() {
this.subParams = this.route.params.subscribe(this.onParams);
this.subQueryParams = this.route.queryParams(this.onQueryParams);
}
ngOnDestroy() {
// Delete active subscribes on destroy
this.subParams.unsubscribe();
this.subQueryParams.unsubscribe();
}
onParams = (params: any) => {
this.itemId = params['id'];
}
onQueryParams = (data: any) => {
this.show = data.show;
if(this.show) {
this.TitleService.fetchTitle(this.show)
}
}
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