I am trying to learn how service injection works in Angular 2. I have created an app and a service. My service is as follows:
import {Injectable} from 'angular2/core';
#Injectable()
export class UserService {
logged: boolean;
users: Array<any>;
constructor () {
this.logged = false;
this.users = [
{username: 'david', password: 'password'}
]
}
checkLogin (username, password) {
this.users.forEach((user) => {
if (user.username == username && user.password == password) {
this.logged = true;
return true;
} else {
this.logged = false;
return false;
}
})
}
logOut () {
this.logged = false;
}
}
I am injecting this into the bootstrap so that I can access it throughout the application as follows:
import {bootstrap} from 'angular2/platform/browser'
import {AppComponent} from './components/app.component'
import {ROUTER_PROVIDERS} from 'angular2/router';
import {UserService} from './services/user.service';
bootstrap(AppComponent, [ROUTER_PROVIDERS, UserService]);
I have then tried to access this in one of my components views but cannot do so. I have tried to access it like this:
import {Component} from 'angular2/core';
import {ROUTER_DIRECTIVES} from "angular2/router";
#Component({
selector: 'navbar',
template: '<li><a>{{UserService.logged}}</a></li>',
directives: [ROUTER_DIRECTIVES],
})
export class NavbarComponent {
}
It does not allow me to access the variable, why is this?
You need to import the service in your component. In bootstrap you initialized/constructed it (made a singleton - meaning one instance for all components), but you have to import and assign it to the component property to be able to use it. Component's template only has access to component's properties and methods...
import {Component} from 'angular2/core';
import {ROUTER_DIRECTIVES} from "angular2/router";
import {UserService} from './services/user.service';
#Component({
selector: 'navbar',
template: '<li><a>{{userService.logged}}</a></li>',
directives: [ROUTER_DIRECTIVES],
})
export class NavbarComponent {
// this way you let TS declare it
constructor(public userService: UserService) {}
// this is same as:
// userService;
// constructor(userService: UserService) {
// this.userService = userService;
// }
}
Here is an alternative to Sasxa's answer. I use this approach when I need to do some other login or logout related actions.
UserService:
import {Injectable, EventEmitter} from 'angular2/core';
#Injectable()
export class UserService {
public doLoginUpdate: EventEmitter<boolean> = new EventEmitter();
logged: boolean;
users: Array<any>;
constructor () {
this.logged = false;
this.users = [
{username: 'david', password: 'password'}
]
}
checkLogin (username, password) {
this.users.forEach((user) => {
if (user.username == username && user.password == password) {
this.logged = true;
return true;
} else {
this.logged = false;
return false;
}
})
this.doLoginUpdate.emit(this.logged);
}
logOut () {
this.logged = false;
this.doLoginUpdate.emit(this.logged);
}
}
NavbarComponent:
import {Component} from 'angular2/core';
import {ROUTER_DIRECTIVES} from "angular2/router";
import {UserService} from './services/user.service';
#Component({
selector: 'navbar',
template: '<li><a>{{logged}}</a></li>',
directives: [ROUTER_DIRECTIVES],
})
export class NavbarComponent {
logged: boolean = false;
constructor(
private userService: UserService) {
this.userService.doLoginUpdate.subscribe((logged)=>{
this.logged = logged;
//do something important related to logging in or logging out
});;
}
}
Related
I have created an interface called user with an email property, password and photo url. When I load it in the ngOnInit() the value user (object) photo url says src = (unknown). I want to show the associated image (storage - when I register / create the user) on the header
//user.class.ts
export class User {
email: string;
password: string;
photoUrl: string;
}
//header.component.ts
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { AngularFireAuth } from '#angular/fire/auth';
import { AuthService } from 'src/app/service/auth.service';
import { User } from 'src/app/share/user.class';
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss'],
})
export class HeaderComponent implements OnInit {
user: User = new User();
constructor(
private router: Router,
private auth:AngularFireAuth,
private authSvc:AuthService
) { }
ngOnInit() {
this.authSvc.isAuth().subscribe(user => {
if(user) {
this.user.photoUrl = user.photoUrl;
console.log(this.user.photoUrl);
}
})
}
//auth.service.ts
isAuth(user: User) {
return this.auth.authState.pipe(map(user => user));
}
//header.html
<ion-avatar>
<img src="{{user.photoUrl}}" />
</ion-avatar>
I have made a web app with angular and firebase.
fUser is the user from firebase, and User is my interface
import { Component, OnInit } from '#angular/core'
import { AngularFireAuth } from '#angular/fire/auth'
import { Observable } from 'rxjs'
import { first } from 'rxjs/operators'
import { User as fUser } from 'firebase'
import { User } from '#models/User'
#Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.scss']
})
export class TestComponent implements OnInit {
public user$: Observable<fUser> = this.auth.user
public currentUser: User
constructor(
private auth: AngularFireAuth
) { }
ngOnInit() {
this.user$.pipe(first()).toPromise().then(user => {
this.currentUser = user as User
})
}
}
Im trying a simple profile app, and all the sudden Im getting error TS2554
ERROR in /app/components/profile/profile.component.ts(25,3): error TS2554: Expected 1 arguments, but got 0.
import { Component, OnInit } from '#angular/core';
import { AuthService } from '../../services/auth.service';
import { FlashMessagesService } from 'angular2-flash-messages';
import { Router } from '#angular/router';
#Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
user: Object;
constructor(
private auth: AuthService,
private flashMsg: FlashMessagesService,
private router: Router
) {
}
ngOnInit() {
this.auth.getProfile().subscribe( profile => {
this.user = profile.user;
},
err => {
return false;
});
}
}
auth.service.ts
import { Injectable } from '#angular/core';
import { Http, Headers } from '#angular/http';
import 'rxjs/add/operator/map';
import { tokenNotExpired } from 'angular2-jwt';
#Injectable()
export class AuthService {
authToken: any;
user: any;
constructor(
private http: Http
) {
}
getProfile(user) {
let headers = new Headers();
this.loadToken();
headers.append('Authorization', this.authToken);
headers.append('Content-Type','application/json');
return this.http.get('http://localhost:3000/users/profile', {headers:headers})
.map(res => res.json());
}
loadToken() {
const token = localStorage.getItem('id_token');
this.authToken = token;
}
}
Your getProfile is expecting an argument named user but you are not passing it from the component
You need to pass an argument as follows,
this.auth.getProfile(user).subscribe( profile => {
this.user = profile.user;
},
err => {
return false;
});
or if you don't need an argument , remove it from your service method.
I want to display the username on my NavbarComponent, the data coming from LoginComponent.
login.component.ts
import { Component, OnInit } from '#angular/core';
import { FormBuilder,FormGroup,Validators,FormControl } from '#angular/forms';
import { AuthService } from '../../services/auth.service';
import { Router } from '#angular/router';
import { FlashMessagesService } from 'angular2-flash-messages';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
form : FormGroup;
message;
messageClass;
constructor(
private formBuilder: FormBuilder,
private authService:AuthService,
private router: Router,
private flashMessagesService:FlashMessagesService
) {
this.createForm();
}
createForm(){
this.form=this.formBuilder.group({
username:['', Validators.required],
password:['', Validators.required]
})
}
onLoginSubmit(){
const user={
username: this.form.get('username').value,
password: this.form.get('password').value
}
this.authService.login(user).subscribe(data=>{
if(!data.success){
this.messageClass="alert alert-danger";
this.message=data.message;
}
else{
this.messageClass="alert alert-success";
this.message=data.message;
this.authService.storeUserData(data.token,data.user);
setTimeout(()=>{
this.router.navigate(['/profile']);
},2000);
this.flashMessagesService.show('Welcome to bloggy, '+ this.form.get('username').value +' !',{cssClass: 'alert-info'});
}
});
}
}
navbar.component.ts
import { Component, OnInit } from '#angular/core';
import { AuthService } from '../../services/auth.service';
import { Router } from '#angular/router';
import { FlashMessagesService } from 'angular2-flash-messages';
#Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.css']
})
export class NavbarComponent implements OnInit {
usernameNav;
constructor(
private authService:AuthService,
private router:Router,
private flashMessagesService:FlashMessagesService
) { }
onLogoutClick(){
this.authService.logout();
this.flashMessagesService.show('You are logged out',{cssClass: 'alert-info'});
this.router.navigate(['/']);
}
ngOnInit() {
}
}
I am sorry if there's too much code but basically i want to take data.user.username from LoginComponent in the onLoginSubmit() function, send it to NavbarComponent, use it in a variable and display it on the html.
I tried to import the NavbarComponent, didn't work.
Pretty Interesting question , basically solution to your problem is Observable/subscriber, you need to
listen when the value changes in the login component and send it back to navbar component to display.
you can use global Observable like this
let suppose you create one Observable in your global file like this
public loggedInObs: Rx.Subject<any> = new Rx.Subject<any>();
public loggedInVar: boolean = false;
for using this you have to import some dependency like this
import { Observable } from 'rxjs/Rx';
import * as Rx from 'rxjs/Rx';
import 'rxjs/add/observable/of';
import 'rxjs/Rx';
import 'rxjs/add/operator/map';
Than in your login component you tell angular that there are some changes occurred like user login successfully.
and fire observable , so that angular will able to listen in whole app where you set subscriber to listen that user
have logged in into app. code for this as below
this.authService.login(user).subscribe(data=>{
if(!data.success){
this.messageClass="alert alert-danger";
this.message=data.message;
}
else{
this.messageClass="alert alert-success";
this.message=data.message;
localStorage.setItem('user_info', JSON.stringify(data.user))
/*for Global level observable fire here*/
this.global_service.loggedInVar = true; //i assume global_service here as your Global service where we declared variables
this.global_service.loggedInObs.next(this.global_service.loggedInVar);
this.authService.storeUserData(data.token,data.user);
setTimeout(()=>{
this.router.navigate(['/profile']);
},2000);
this.flashMessagesService.show('Welcome to bloggy, '+ this.form.get('username').value +' !',{cssClass: 'alert-info'});
}
now you can listen to this using subscriber everywhere in the app like this in your navbar component
userdata = JSON.parse(localStorage.getItem('user_info')); // in case of normal loading page
this.userName = userdata.user_name
this.global_service.loggedInObs.subscribe(res => { // in case of when without refresh of page
console.log('changes here in login');
userdata = JSON.parse(localStorage.getItem('user_info'));
this.userName = userdata.user_name
})
if any doubt let me know.
My http-data.service accepts json for output in the component template. Initially, the console shows that the first few calls are given undefined, and the following calls are already taking json, but also if you check the component, then the component shows that the method that outputs the data to the component is called only once and since the data has not yet arrived it writes undefined , But not updated after the arrival of json. Help please understand why? Thank you
My http-data.service:
import {Injectable} from '#angular/core';
import {Http} from '#angular/http';
import {Response} from '#angular/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
#Injectable()
export class HttpService{
constructor(private http: Http) {}
getDataOrganizations(): Observable<any[]>{
return this.http.get('http://localhost:3010/data')
.map((resp:Response)=>{
let dataOrganizations = resp.json().organization;
return dataOrganizations;
});
}
getDataModules(): Observable<any[]> {
return this.http.get('http://localhost:3010/data')
.map((resp: Response)=> {
let dataModules = resp.json().modules;
return dataModules;
});
}
getDataPresets(): Observable<any[]> {
return this.http.get('http://localhost:3010/data')
.map((resp: Response)=> {
let dataPresets = resp.json().presets;
return dataPresets;
});
}
getDataModuleItems(): Observable<any[]> {
return this.http.get('http://localhost:3010/data')
.map((resp: Response)=> {
let dataModuleItems = resp.json().module_items;
return dataModuleItems;
});
}
}
My data-all.service
import { Injectable, EventEmitter } from '#angular/core';
import {Response} from '#angular/http';
import { ModuleModel } from './model-module';
import { ModuleItemsModel } from './model-module-items';
import data from '../data/data-all';
import { PriceService } from './price.service';
import { HttpService } from './http-data.service';
#Injectable()
export class ModuleDataService {
constructor(private priceService: PriceService, private httpService: HttpService){
this.dataMinMaxSum = {minSum: 0, maxSum: 0}
}
private currentPopupView: EventEmitter<any> = new EventEmitter<any>();
private dataModules: ModuleModel[] = this.getDataModules();
private dataMinMaxSum: {};
private dataCalculateVariationOrg: any[];
private dataChangeExecutor: any[];
subscribe(generatorOrNext?: any, error?: any, complete?: any) {
this.currentPopupView.subscribe(generatorOrNext, error, complete);
}
calculte(){
return this.priceService.getDataPrice();
}
getDataModules(){
this.httpService.getDataModules().subscribe(((modules)=>{this.dataModules = modules; console.log(this.dataModules);}));
console.log('dataModules');
console.log(this.dataModules);
return this.dataModules;
}
---------------------------------------------------------------------------
}
My left-block.component
import { Component, OnInit} from '#angular/core';
import { ModuleDataService } from '../../service/data-all.service';
import { ModuleModel } from '../../service/model-module';
#Component({
moduleId: module.id,
selector: 'modules-left-block',
templateUrl: './modules-left-block.html',
styleUrls: ['modules-left-block.css']
})
export class ModuleLeft implements OnInit{
modules: ModuleModel[];
constructor(private modulesAll: ModuleDataService){}
ngOnInit(){
this.modules = this.modulesAll.getDataModules();
console.log("view");
console.log(this.modulesAll.getDataModules());
}
onToggle(module: any){
this.modulesAll.toggleModules(module);
}
}
My left-block.component.html
<div class="modules-all">
<div class="modules-all-title">Все модули</div>
<div class="module-item" *ngFor="let module of modules" [ngClass]="{ 'active': module.completed }" (click)="onToggle(module)">{{module?.title}}</div>
</div>
In the component this.modulesAll.getDataModules () method is why it is executed only once without updating (write in console => undefined), if there are any thoughts, write, thanks.
This behaviour is due to the .subscribe() method does not wait for the data to arrive and I'm guessing you already know this. The problem you're facing is because, you have .subscribe to the getDataModules() service in the wron place. You shouldn't subscribe to a service in another service (at leat in this case). Move the subscribe method to the left-block.component and it should work.
getDataModules() {
this.httpService.getDataModules().subscribe(((modules) => {
this.dataModules = modules;
console.log(this.dataModules);
}));
console.log('dataModules');
console.log(this.dataModules);
return this.dataModules;
}
It should look somethig like this:
#Component({
moduleId: module.id,
selector: 'modules-left-block',
templateUrl: './modules-left-block.html',
styleUrls: ['modules-left-block.css']
})
export class ModuleLeft implements OnInit {
modules: ModuleModel[] = new ModuleModel();
constructor(private modulesAll: ModuleDataService, private httpService: HttpService) {}
ngOnInit() {
this.getDataModles();
//this.modules = this.modulesAll.getDataModules();
console.log("view");
//console.log(this.modulesAll.getDataModules());
}
onToggle(module: any) {
this.modulesAll.toggleModules(module);
}
getDataModules(): void {
this.httpService.getDataModules().subscribe(((modules) => {
this.modules = modules;
console.log(this.dataModules);
}));
}
}
I want to share an object from my first component to the second. I am able to log the 'strVal'(string) defined in the Login Component, in my Home Component but I am unable to log the value of 'abc'(Object) from the Login Component, in the HomeComponent. I am confused why one value from Login Component gets available to Home Component and other does not! The code for Login Component in below
Login.Component.ts
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { AuthenticationService } from '../_services/index';
import { User } from '../contract';
#Component({
moduleId: module.id,
templateUrl: 'login.component.html'
})
export class LoginComponent implements OnInit {
model: any = {};
loading = false;
error = '';
us: User[];
abc: any[];
strVal: string = "Rehan";
current: any;
constructor(
private router: Router,
private authenticationService: AuthenticationService) { }
ngOnInit() {
// reset login status
this.authenticationService.logout();
this.getUs();
}
login() {
this.loading = true;
this.authenticationService.login(this.model.username, this.model.password)
.subscribe(result => {
if (result) {
this.router.navigate(['/']);
}
else {
alert('Username and Password Incorrect');
this.loading = false;
this.model = [];
this.router.navigate(['/login']);
}
});
}
getUs() {
this.authenticationService.getUsers().subscribe(
res => this.us = res
);
}
chek() {
this.abc = this.us.filter(a => a.Login === this.model.username);
console.log(this.abc);
}
}
Home.Component.ts
import { Component, OnInit, Input } from '#angular/core';
import { AuthenticationService } from '../_services/index';
import { LoginComponent } from '../login/index';
import { User } from '../contract';
#Component({
moduleId: module.id,
templateUrl: 'home.component.html',
providers: [LoginComponent]})
export class HomeComponent implements OnInit {
users: User[];
constructor(private userService: AuthenticationService, private Log: LoginComponent) { }
ngOnInit() {
this.userService.getUsers().subscribe(
res => this.users = res
);
console.log(this.Log.strVal);
console.log(this.Log.abc);
}
}
Any hint or help will be appreciated. Thanks!