Angular2 Subscribe to a global variable - html

I'm fairly new to Angular 2 and I have a little problem.
I have a header component, in the header I want to use an ngIf, cause in the login-screen I will hide the header(navbar).
Furthermore, I want to hide some more things from the header, depending on the users-profile.
To store, if a user is logged in, I have a global service named variables.ts, which looks like this:
import { Injectable } from '#angular/core';
#Injectable()
export class Variables {
private url = "...";
private username;
private password;
private isLoggedIn = false;
constructor() {}
setUrl(val) {
this.url = val;
}
getUrl() {
return this.url;
}
setUsername(val) {
this.username = val;
}
getUsername() {
return this.username;
}
setPassword(val) {
this.password = val;
}
getPassword() {
return this.password;
}
setIsLoggedIn(val) {
this.isLoggedIn = val;
}
getIsLoggedIn() {
return this.isLoggedIn;
}
}
My header-component looks like this:
import { Component } from '#angular/core';
import { Router } from '#angular/router';
import { Variables } from '../../services/variables';
#Component({
selector: 'app-header',
moduleId: module.id,
templateUrl: 'header.component.html'
})
export class HeaderComponent {
constructor(private variables: Variables) {}
isLoggedIn() {
return this.variables.getIsLoggedIn();
}
console.log(loggedIn);
}
And last but not least, in the header.component.html I did this:
<nav class="navbar navbar-default navbar-static-top" *ngIf="isLoggedIn()">
My problem now is, that the header-component do not automatically update the var loggedIn, so the header is hidden if I'm logged in.
How can i make it functional?

I updated my original post, so that it is functional now ;)
Thanks for your help!
Solution: DonĀ“t bind it directly to a variable, but to a function and in the "ngIf" just ask the function ;)

Related

catch paste events on a dropdown

I'm trying to catch paste event occuring on input fields.
It works perfectly on textarea and input but not on dropdowns. Select.
Here is my directive, the console.log is never called.
import { Directive, HostListener } from '#angular/core';
#Directive({ selector: '[catchPasteEvents]' })
export class CatchPastEvent {
#HostListener('onpaste') onPaste(event) {
console.log('Paste', event);
}
}
I created this directive that set a listener on document paste (as suggested by Sergey) but only when the select element is focused.
#Directive({ selector: 'select[selectPaste]' })
export class SelectPasteDirective implements OnDestroy {
#Output()
public paste: EventEmitter<ClipboardEvent> = new EventEmitter();
private listener: (event: ClipboardEvent) => void = this.handlePaste.bind(
this,
);
public ngOnDestroy(): void {
document.removeEventListener('paste', this.listener);
}
#HostListener('focus')
public onFocusedItem() {
document.addEventListener('paste', this.listener);
}
#HostListener('blur')
public onBlurItem() {
document.removeEventListener('paste', this.listener);
}
private handlePaste(event: ClipboardEvent) {
this.paste.emit(event);
}
}

How to convert this API get() result into JSON object?

API endpoint returning an observable. When I am trying to retrieve any property of the returned object, it is showing that the property does not exist on type {}
This is the endpoint result
{
"base": "EUR",
"date": "2018-04-08",
"rates": {
"CAD": 1.565,
"CHF": 1.1798,
"GBP": 0.87295,
"SEK": 10.2983,
"EUR": 1.092,
"USD": 1.2234,
}
}
service.ts
import { Injectable } from '#angular/core';
import { HttpClient, HttpResponse } from '#angular/common/http';
import { Observable } from 'rxjs';
import { ConvertResultModel } from './converter/convert-result-model';
#Injectable({
providedIn: 'root'
})
export class ServiceProviderService {
private baseUrl = 'https://api.exchangeratesapi.io/latest';
constructor(private http: HttpClient) { }
getLatest():Observable<ConvertResultModel>{
return this.http.get<ConvertResultModel>(this.baseUrl);
}
}
converter.component.ts
import { ServiceProviderService } from './../service-provider.service';
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-converter',
templateUrl: './converter.component.html',
styleUrls: ['./converter.component.css']
})
export class ConverterComponent implements OnInit {
constructor(private serviceProvider: ServiceProviderService) { }
private resultSet = {};
ngOnInit()
{
this.serviceProvider.getLatest().subscribe(data => this.resultSet = data);
console.log(this.resultSet.base);
}
}
convert-result-model.ts
export interface ConvertResultModel {
base: number;
date: string;
rates: any[];
}
ERROR in src/app/converter/converter.component.ts(17,32): error TS2339: Property 'base' does not exist on type '{}'.
Its all about type checking in typescript. Which is something good but sometimes you don't want to define type of everything.
So you may want to replace
private resultSet = {};
With something like
private resultSet:any = {};
// or
//private resultSet:any = null;
Or define a class or interface and set type of resultSet to that class or interface. Something like:
public interface ResultSet{
base: String;
// etc
}
and then
private resultSet:ResultSet= {} as ResultSet;
// or
//private resultSet:ResultSet= null;
But my suggestion is try to practice using power of typescript which helps you catch some errors in compile time instead of runtime

angular4 directive not working inside HTML SPAN tag

I have written a directive in angular4, which works on input fields.
When I apply that on SPAN tag, it is not working.
Can we apply the directives on SPAN TAG, or is there any work around.
<span dirTemp>45789</span>
dirTemp actually corrects the value to 45,789
import { Directive, HostListener, ElementRef, OnInit, AfterViewInit, AfterViewChecked, AfterContentChecked } from '#angular/core';
#Directive({
// tslint:disable-next-line:directive-selector
selector: '[dirTemp ]',
})
export class FormatterDirective implements AfterViewChecked {
private el: HTMLInputElement;
constructor(
private elementRef: ElementRef,
private cPipe: MyPipe
) {
this.el = this.elementRef.nativeElement;
}
// ngOnInit() {
// this.el.value = this.cPipe.transform(this.el.value);
// }
ngAfterViewChecked(): void {
this.el.value = this.cPipe.parse(this.el.value);
this.el.value = this.cPipe.transform(this.el.value);
}
#HostListener('focus', ['$event.target.value'])
onFocus(value) {
console.log('in formatter directive:', value);
this.el.value = this.cPipe.parse(value);
}
#HostListener('focusout', ['$event.target.value'])
onFocusout(value) {
this.el.value = this.cPipe.transform(value);
}
}
Workaround: span doesn't have value but has innerText or innerHTML. So, On ngOnInit you can do:
ngOnInit() {
if(this.el.tagName.toUpperCase() !== 'INPUT') {
// Apply your tranform here:
var originalValue = this.el.innerText;
this.el.innerText = this.cPipe.transform(originalValue);
}
}

How would one access this from the Class inside a function in an object using TypeScript / Angular2

In my angular2 project I have a DataService class.
I want to have a DataService.await.get() and DataService.await.put() but I'm having trouble getting the correct 'this' inside those methods.
This is what I have now:
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs/Observable';
import { ReplaySubject } from 'rxjs/ReplaySubject';
#Injectable()
export class DataService {
public await = {
get(req): Observable<any> {
return this.getIt(req); // I need 'this' to be the DataService
},
put(req, data): boolean {
return this.putIt(req, data); // I need 'this' to be the DataService
}
constructor() {}
private getIt(req: string): Observable<any> {
return new ReplaySubject(1).AsObservable();
}
private putIt(req: string, data: any): boolean {
return true;
}
}
I have seen some examples using arrow functions for functions within functions, but not for functions within an object...
How do I get 'this' to be a reference to the class?
You could change your property to a function that returns an object and use a little trick like this:
public await() {
let that = this;
return {
get(req): Observable<any> {
return that.getIt(req);
},
put(req, data): boolean {
return that.putIt(req, data);
}
};
}
or you could initialize the await property in the constructor:
await: { get(req): Observable<any>, put(req, data): boolean };
constructor() {
let that = this;
this.await = {
get(req): Observable<any> {
return that.getIt(req);
},
put(req, data): boolean {
return that.putIt(req, data);
}
};
}
I managed to solve it using arrow after all, appearantly all this time I was trying with get= instead of get:
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs/Observable';
import { ReplaySubject } from 'rxjs/ReplaySubject';
#Injectable()
export class DataService {
public await = {
get: (req): Observable<any> => {
return this.getIt(req); // I need 'this' to be the DataService
},
put: (req, data): boolean => {
return this.putIt(req, data); // I need 'this' to be the DataService
}
constructor() {}
private getIt(req: string): Observable<any> {
return new ReplaySubject(1).AsObservable();
}
private putIt(req: string, data: any): boolean {
return true;
}
}

Getting data from Web API in Angular 2

Thanks to tutorial on Angular 2 page called "Tour of Heroes", I managed to create a simple Angular 2 application. Then using Enitity Framework I decided to create a database. And fill the list of heroes from it (not from the file). I created Web Api Controller and added simple get method.
Then in hero.service.ts I call this method in order to get list of heroes. When I lunch my app it shows the list of heroes but without any values (name and id are blank). When I debug my application in the browser I can see this.heroes object in heroes.component.ts contains right data. So what is going on? Why aren't name and id showing?
hero.service.ts:
import {Injectable} from 'angular2/core';
import {HEROES} from './mock-heroes';
import {Hero} from './hero';
import {Http, Response} from 'angular2/http';
import 'rxjs/Rx';
import {Observable} from 'rxjs/Observable';
#Injectable()
export class HeroService {
public values: any;
constructor(public _http: Http) { }
private _heroesUrl = 'http://localhost:61553/api/values'; // URL to web api
getHeroes() {
return this._http.get(this._heroesUrl)
.map(res => <Hero[]>res.json())
.catch(this.handleError);
}
private handleError(error: Response) {
console.error(error);
return Observable.throw(error.json().error || 'Server error');
}
}
heroes.component.ts:
import {Component, OnInit} from 'angular2/core';
import {Router} from 'angular2/router';
import {Hero} from './hero';
import {HeroDetailComponent} from './hero-detail.component';
import {HeroService} from './hero.service';
#Component({
selector: 'my-heroes',
templateUrl: 'templates/heroes.component.html',
styleUrls: ['styles/heroes-component.css'],
directives: [HeroDetailComponent]
})
export class HeroesComponent implements OnInit {
constructor(private _heroservice: HeroService, private _router: Router) { }
errorMessage: string;
public heroes: Hero[];
selectedHero: Hero;
ngOnInit() {
this.getHeroes();
}
onSelect(hero: Hero)
{
this.selectedHero = hero;
}
getHeroes() {
this._heroservice.getHeroes()
.subscribe(
value => this.heroes = value,
error => this.errorMessage = <any>error);
}
gotoDetail() {
this._router.navigate(['HeroDetail', { id: this.selectedHero.Id }]);
}
}
heroes.component.html:
<h2>My Heroes</h2>
<ul class="heroes">
<li *ngFor="#hero of heroes" [class.selected]="hero === selectedHero" (click)="onSelect(hero)">
<span class="badge">{{hero.Id}}</span> {{hero.Name}}
</li>
</ul>
<div *ngIf="selectedHero">
<h2>
{{selectedHero.Name | uppercase}} is my hero
</h2>
<button (click)="gotoDetail()">View Details</button>
</div>
hero.ts:
export class Hero {
Id: number;
Name: string;
}
Web API Controller:
using Microsoft.AspNet.Mvc;
using System.Collections.Generic;
using TestApplicationDataAccess;
using TestApplicationDataAccess.Entities;
namespace WebApplication2.Controllers
{
[Route("api/[controller]")]
public class ValuesController : Controller
{
private readonly TestAppDbContext _dbContext;
public ValuesController(TestAppDbContext dbContext)
{
_dbContext = dbContext;
}
// GET: api/values
[HttpGet]
public IEnumerable<Hero> Get()
{
return _dbContext.Heroes;
}
}
}
Hero Entity:
namespace TestApplicationDataAccess.Entities
{
public class Hero
{
public int Id { get; set; }
public string Name { get; set; }
}
}
JSON retrieved from WEB API Controller:
[{"Id":1,"Name":"Superman"}]
getHeroes() {
this._heroservice.getHeroes()
.subscribe(res=>{
this.heroes=res;
console.log(this.heroes); // make sure you get data here.
},
(err)=>console.log(err),
()=>console.log("Done")
);
}
Try this :public heroes: Hero[] = [];
In my case the issue was related to the visual studio 2015 bug. There was nothing wrong with the code itself. Sometimes changes made in vs were not refreshed in the browser. Updating vs to the latest version helped.