I am "at my wit's end" and haven't a clue what to do. I am close to crying!
I am trying to teach myself Angular2 after many happy years of using AngularJS - I have an Angular2 app that has top level component like so called App
@Component({
selector: 'app', // <app></app>
providers: [...FORM_PROVIDERS],
directives: [...ROUTER_DIRECTIVES],
template: require('./app.html')
})
@RouteConfig([
{path: '/', component: Home, name: 'Home'},
{path: 'about', component: About, name: 'About'},
{path: 'profile', component: Profile, name: 'Profile'},
{path: 'profile/:id', component: ForeignProfile, name: 'ForeignProfile'}
])
export class App {
userStatus: UserStatus;
userOnlineContacts: UserContact[];
constructor(private userData: UserData) {
this.userStatus = new UserStatus();
}
ngOnInit() {
Observable.forkJoin([
this.userData.getUserStatus(),
this.userData.getContacts()
]).subscribe( (t) => {
this.userStatus = t[0];
this.userOnlineContacts = t[1].onlineContacts;
});
// Polling thing for this.userOnlineContacts...
this.userData.pollContacts().subscribe(
(data) => {
this.userOnlineContacts = data.onlineContacts;
});
}
}
I looks like this in my index.html
<app>Loading...</app>
Now I am using the ng-router so within my app.html I have my <router-outlet></router-outlet> tags nested into my HTML. So my child components get injected into these tags - I never place my selector tags into the HTML (so I assume I can't pass the data using data-binding. Inside the <router-outlet></router-outlet> I access the child compinent when I navigate to the ForeignProfile component, the child component code is like so...
@Component({
selector: 'foreign-profile',
template: require('app/components/foreign-profile/foreign-profile.html'),
providers: [],
directives: [],
pipes: []
})
export class ForeignProfile implements OnInit {
userProfile: any;
routeId: string;
userPhotos: any;
userInfo: any;
constructor(private userData: UserData, private routeParams: RouteParams) {
this.routeId = routeParams.get('id');
this.userProfile = {}; // not sure why I need to put this here otherwise we have 'undefined' error
}
ngOnInit() {
// Use forkJoin as we don't need order in the calls
Observable.forkJoin([
this.userData.getUserPhotos(this.routeId),
this.userData.getUserInfo(this.routeId),
this.userData.getUserBaseData(this.routeId)])
.subscribe(t => {
this.userPhotos = t[0];
this.userInfo = t[1];
this.userProfile = t[2];
// do more stuff here
});
}
}
Inside this component I wish to access the properties of the App component, e.g. this.userStatus & this.userOnlineContacts. I don't want to create a service to make repeat HTTP calls I want to inject the parent properties directly into the child. In AngularJS I could have used something like $scope.$parent.userStatus. Now I looked into Injecting the parent (App) into the child (ForeignProfile) by amending the component:
this is the ForeignProfile Component
import {App} from '../../app'
@Component({
// blah blah...
})
export class ForeignProfile implements OnInit {
// code removed for example, easier to read
userStatus: any;
constructor(private userData: UserData, private routeParams: RouteParams, @Inject app:App) {
// code removed for example, easier to read
this.userStatus = app.userStatus;
}
And then with the parent...
import {Injectable, Component} from 'angular2/core';
@Injectable()
@Component({
selector: 'app', // <app></app>
This sent my console crazy. Can someone explain how exactly I could access the properties from the App component in my ForeignProfile Component? I have wasted hours on this so far! Thanks in advance.
$scopewas so useful. This puts any consumer of the shared service responsible for the logic necessary to leverage its API. This doesn't lend itself to DRY programming. There should be a reasonable way for a parent component to provide data to any children components without knowing implementation details. (e.g.vm.someProperty.someMethod(someVar)) This ought to be supported, IMO. - bodine$scopeyou need some contract so the client accesses a value using a predefined name. This is what service classes are for, a common contract. I think this is the right way. But that is how it's done in Java-like languages. In JS-world this is uncommon but currently there is a strong shift back from dynamic languares to typed languages. - Günter Zöchbauer