Manoz Manoz - 1 month ago 8
AngularJS Question

Transferring data between non-nested components

Basically , What I desire is to transfer data b/w components.

I have one angular2 component on master page for partial view of login -

<loginpartial></loginpartial>


This is initially rendered through this html template with child component-

<ul [hidden]="!item.isAuthenticated">
<li><a href="javascript:;">Hello! {{item.userName}}</a></li>
<li><a href="javascript:;">LogOff</a></li>
</ul>
<ul [hidden]="item.isAuthenticated">
<li><a href="javascript:;">Hello! User</a></li>
<li><a href="javascript:;">Log In</a></li>
</ul>


Child Component -

@Component({
selector: 'loginpartial',
templateUrl: '../Templates/LoginPartial.html'
})

export class LoginPartialComponent implements OnInit {
public item: any = { isAuthenticated: false, userName: ' ' }
constructor() {
this.item.isAuthenticated = false;
}

ngOnInit() {
this.item.isAuthenticated = false;
}
}


I hope this makes sense till now. Now What my need is as soon as user is logged in , I want to get username in this partial view transferred from parent component.

Parent Component

import { Component, ChangeDetectionStrategy, OnInit} from '@angular/core';
import {LoginPartialComponent} from '../loginpartialview/loginpartial.component.ts';
import {SharedService} from '../sharedService/app.sharedService.ts';

@Component({
selector: 'loginmodel',
templateUrl: '../Templates/Login.html',
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [LoginPartialComponent,SharedService]
})
export class LoginComponent implements OnInit {
item: any = {
isAuthenticated: false, userName: ' '
};
constructor(private sharedService: SharedService,
private loginComp: LoginPartialComponent) {
}

onSubmit(item: any): void {
if (this.myForm.valid) {
var userObject = {
email: item.email,
password: item.password
};
this.sharedService.getLogin(userObject).map(response => response.json())
.subscribe(
data => this.handleResult(data),
error => console.log(error)
);
}
}

private handleResult(data) {
if (data.success) {
this.item.isAuthenticated = true;
this.item.userName = data.userName;
this.item = this.loginComp.item;
}
else {

}
}
}


As you can see from this parent component when
onSubmit
function is called which is my login form submission I am calling
handleResult
that is setting data from ajax call from the shared service.

This is not letting the child component -
LoginPartialComponent
refresh. I tried with
@Input()
type parameters too but didn't help me.

Update -

As @Camaron said in his answer I created a dependency for this login purpose only with event emitters. But this doesn't work.

LoginPartialComponent

import { Component, OnInit} from '@angular/core';
import {LoginPartialModel} from '../loginpartialview/loginpartial.model.ts';
import {SharedService} from '../sharedService/app.sharedService.ts';

import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';

@Component({
selector: 'loginpartial',
templateUrl: '../Templates/LoginPartial.html',
providers: [SharedService]
})

export class LoginPartialComponent {
item: LoginPartialModel = new LoginPartialModel();
constructor(private service: SharedService) {
this.service.onLoginSuccess.subscribe((loginData: any) => this.item == loginData.item);
}

}


LoginComponent

import { Component, OnInit} from '@angular/core';
import {SharedService} from '../sharedService/app.sharedService.ts';

@Component({
selector: 'loginmodel',
templateUrl: '../Templates/Login.html',
providers: [SharedService]
})
export class LoginComponent {

constructor(private sharedService: SharedService) {
}

onSubmit(item: any): void {
var userObject = {
email: item.email,
password: item.password
};
this.sharedService.getLogin(userObject).map(response => response.json())
.subscribe(
data => this.handleResult(data),
error => console.log(error)
);
}
private handleResult(data) {
if (data.success) {
this.close();
this.sharedService.onLoginSuccess.emit(data);
}
else {

}
}
}


Shared Service (dependency)

import { Component, Injectable, EventEmitter} from '@angular/core';

@Injectable()
export class SharedService {

onLoginSuccess: EventEmitter<any> = new EventEmitter<any>();
constructor() {
}

notifyLoginSuccess(item: any): void {
this.onLoginSuccess.emit({ item: item });
}
}


This didn't work.

Answer

Try to use a service to establish this communication subscribe the LoginPartialComponent.

@Injectable()
export class LoginService {

    onLoginSuccess: EventEmitter<any>() = new EventEmitter<any>();

    constructor() {
    }

    notifyLoginSuccess(item:any):void {
        this.onLoginSuccess.emit({item: item});
    }

}

And then Inject this service on both components. In your LoginPartialComponent subscribe to this service event.

constructor(public loginService:LoginService) {
    this.loginService.onLoginSuccess.subscribe((loginData: any) => this.item = loginData.item);
}

Then in your handleResult function make a call to loginService.notifyLoginSuccess and send the item.

With this solution you can remove the dependency of your components so the LoginComponent don't need to know that there is a LoginPartialComponent.