How subscribe to change variable? - javascript

Please help my subscribe to changed variable. I make simply spinner. Spinner state(true|false) storage in service:
import { Injectable } from '#angular/core';
import { Response, Headers, URLSearchParams } from '#angular/http';
import { Observable } from 'rxjs/Observable';
#Injectable()
export class GlobalVarsService {
private isVisibleSpinner: boolean = false;
getSpinnerState(): Observable<boolean> {
return this.isVisibleSpinner;
};
setSpinnerState(state): void {
console.log('setSpinnerState', state);
this.isVisibleSpinner = state;
};
}
In component-template i display spinner via condition:
<div class="nav">
<a [routerLink]="['/select']">select</a>
<a [routerLink]="['/output']">output</a>
</div>
<router-outlet></router-outlet>
<div class="spinner-backdrop" *ngIf="isVisibleSpinner"></div>
<div class="spinner-area" *ngIf="isVisibleSpinner">
<span class="spinner">loading...</span>
</div>
In component i try subscribe to change in service isVisibleSpinner variable:
import { Component } from '#angular/core';
import { Response } from '#angular/http';
import 'rxjs/add/operator/map'
import { GlobalVarsService } from './services/global-vars.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
private isVisibleSpinner: boolean;
constructor(private globalVarsService: GlobalVarsService) {
this.globalVarsService.getSpinnerState().subscribe(data => {
console.log(data);
this.isVisibleSpinner = data;
});
}
}
But console output follow eror message:
Type 'boolean' is not assignable to type 'Observable'.

because you are returning an observable and putting the value in boolean, you can change the type of your is variable to Observable and use the async pipe to get the value or map your "data" to boolean if thats what you want
export class AppComponent {
private isVisibleSpinner: Observable<boolean>;
constructor(private globalVarsService: GlobalVarsService) {
this.globalVarsService.getSpinnerState().subscribe(data => {
console.log(data);
this.isVisibleSpinner = data;
});
}
}
app.component.html
<div class="spinner-backdrop" *ngIf="isVisibleSpinner | async"></div>
<div class="spinner-area" *ngIf="isVisibleSpinner | async">
<span class="spinner">loading...</span>
</div>

Related

Angular: hiding a component with *ngIf doesn't work

I have just started with Angular and have already faced an issue: a button actually toggles the variable I need (show) but it doesn't affect the course.component
course.component must show app-csgo-course, boolean show is true because the component is visible, but after it toggles in navbar.component, nothing changes.
<app-csgo-course *ngIf="show"> </app-csgo-course>
import { NavbarComponent } from './../navbar/navbar.component';
import { Component, OnInit} from '#angular/core';
import { CourseService } from 'src/app/course.service';
#Component({
selector: 'app-course',
templateUrl: './course.component.html',
styleUrls: ['./course.component.css']
})
export class CourseComponent implements OnInit {
constructor() { }
ngOnInit(): void { }
service = new CourseService;
show = this.service.GetShow();
}
In navbar.component there's a button which toggles the "show" variable
<button (click)="ToggleShow()" >
<li class="nav-item active" id="csgo-logo">
<a href="#">
<img class="game-logo" src="assets\img\csgo-logo.png" title="Counter Strike: Global Offensive">
<!-- <a>CS:GO <span class="sr-only">(current)</span></a> -->
</a>
</li>
</button>
import { CourseService } from 'src/app/cheat.service';
import { Component, OnInit, Input, Output, } from '#angular/core';
#Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.css']
})
export class NavbarComponent implements OnInit {
service = new CourseService;
show = this.service.GetShow();
ngOnInit(): void {
}
public ToggleShow() {
this.service.show = this.service.ToggleShow();
console.log(this.service.show);
return this.service.show;
}
}
The course.service file
#Injectable({
providedIn: 'root'
})
export class CourseService {
show: boolean = true;
GetShow() {
return this.show;
}
ToggleShow() {
return this.show = !this.show
}
constructor() { }
}
}
Would appreciate your help!
Since you are new to Angular, let me break it down for you.
You need to create a BehaviorSubject to capture the event of toggle (this is called reactive programming which is a achieved using RxJS in Angular ).
Do not use new for a service, rather inject it in constructor.
course.service
#Injectable({
providedIn: 'root'
})
export class CourseService {
private show: boolean = true;
private toggle$ = new BehaviorSubject<boolean>(true);
constructor() { }
toggleEvent() {
return this.toggle$.asObservable();
}
toggleShow() {
this.show = !this.show
this.toggle$.next(this.show);
}
}
in NavbarComponent
import { CourseService } from 'src/app/cheat.service';
import { Component, OnInit, Input, Output, } from '#angular/core';
#Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.css']
})
export class NavbarComponent implements OnInit {
show = boolean;
// IMP: make sure to inject the service and not do "new CourseService;"
constructor(public service: CourseService){}
ngOnInit(): void {
this.service.toggleEvent().subscribe(showFlag => {
this.show = showFlag;
})
}
public ToggleShow(): void {
this.service.toggleShow();
}
}
in courseComponent
import { Component, OnInit} from '#angular/core';
import { CourseService } from 'src/app/course.service';
#Component({
selector: 'app-course',
templateUrl: './course.component.html',
styleUrls: ['./course.component.css']
})
export class CourseComponent implements OnInit {
show: boolean ;
// IMP: make sure to inject the service and not do "new CourseService;"
constructor(public service: CourseService){}
ngOnInit(): void {
this.service.toggleEvent().subscribe(showFlag => {
this.show = showFlag;
})
}
}
PS: I would suggest you to read about "how to unsubscribe an observable" and how it causes memory leaks. Once you get some idea, you should implement that in the above provided code as well. That's a best practice. Happy learning. Let me know if you have any more questions

check boolean value again and again

I am trying to build infinite scroll for my cards.
I am using a variable reload in data.service to check for need to load more data which is getting set to true when page end is getting reached.
The variable setting to true is done by app.component
The content population is done in post.component
And ```reload`` is present in data.service which is using http service to fetch for content from php server.
Curently I am using observable and trying to access reload status repeatedly but it is getting subscribed only once on Init.
app.component.ts
import { Component,HostListener } from '#angular/core';
import * as M from 'materialize-css';
import {DataService} from './current/posts/post-card/data.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent
{
title = 'cosmos';
constructor(private scrollSet: DataService){}
#HostListener('scroll', ['$event'])
onScroll(event:any)
{
if (event.target.offsetHeight + event.target.scrollTop >= event.target.scrollHeight-100)
{
console.log("noww");
this.scrollSet.setValue(true);
}
}
}
post.component.ts
import { Component, OnInit} from '#angular/core';
import {DataService} from './data.service';
import { DomSanitizer } from '#angular/platform-browser';
import {Title} from "#angular/platform-browser";
#Component({
selector: 'app-post-card',
templateUrl: './post-card.component.html',
styleUrls: ['./post-card.component.css']
})
export class PostCardComponent implements OnInit {
constructor(private data: DataService,public sanitizer: DomSanitizer,private titleService:Title)
{
this.titleService.setTitle("Current Feed | Cosmos");
}
received = 'none';
posts: any = [];
ngOnInit()
{
this.data.getPostData().subscribe(data =>
{
this.posts.push(data);
this.received='success';
},
error =>
{
this.received='error';
});
this.data.getValue().subscribe((value) => {
this.data.getPostData().subscribe(data =>
{
this.posts.push(data);
this.received='success';
},
error =>
{
this.received='error';
});
});
}
}
data.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import {BehaviorSubject, Observable} from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class DataService {
private reload: BehaviorSubject<boolean>;
constructor(private http: HttpClient)
{
this.reload = new BehaviorSubject<boolean>(false);
}
fetchGap=5; // use this to set number of results wanted per fetch
fetchEnd:number= 0;
setValue(newValue): void {
this.reload.next(newValue);
}
getValue(): Observable<boolean> {
return this.reload.asObservable();
}
getPostData(){
this.fetchEnd+=this.fetchGap;
return this.http.get('http://localhost:1234/Server/getPosts.php?fetchEnd='+this.fetchEnd+'&fetchGap='+this.fetchGap);
}
}
the problem is that you haven't set the value of reload to false after your treatment.
try to check inside post.component.ts. here is a portion of that code, the block which suscribe to reload.
post.component.ts reload block
this.data.getValue().subscribe((value) => {
if(value){
this.data.getPostData().subscribe(data =>
{
this.posts.push(data);
this.received='success';
},
error =>
{
this.received='error';
});
this.data.setValue(false);
}
});

ANGULAR. Send array data get it of Itunes API; from component-search to component-main, via service

In angular 7. I need to send an Array information get it from Itunes Api, which is included in a component called "search", to another component called "catalog". I've understand that in this case I've to use a service which allows to share the info between them. Here's some code. What's wrong?
I've tried with viewchild, input, output, but there's no result; because both components aren't "relatives".
"search"
"search"
import { Component, OnInit, Output, EventEmitter } from '#angular/core';
import { RequestService } from '../../services/request/request.service';
import {DataShareService} from '../../services/dataShare/data-share.service';
import { Music } from '../../models/music';
#Component({
selector: 'search',
styleUrls: ['./ion-searchbar.component.sass'],
templateUrl: './ion-searchbar.component.html',
providers: [RequestService, DataShareService],
})
export class IonSearchBarComponent implements OnInit {
public searchResults: Music[];
public searchValue: string;
constructor(public _requestService: RequestService, private _dataShareService: DataShareService) {}
ngOnInit() {
this._dataShareService.$sendDataObservable.subscribe(
data => {
this.searchResults = data
})
}
sendData(searchResults: Music[]){
console.log("executat");
this._dataShareService.sendData(searchResults);
}
search(){
this._requestService.getMusic(this.searchValue).subscribe(
result => {
this.searchResults = result.results;
console.log(result.results);
this.sendData(this.searchResults);
},
error =>{
console.log(<any>error);
}
);
}
}
"service"
import { Injectable } from '#angular/core';
import { Music } from '../../models/music';
import { Subject } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class DataShareService {
private _sendDataSubject = new Subject<Music[]>();
$sendDataObservable = this._sendDataSubject.asObservable();
constructor() { }
sendData(data: Music[]){
this._sendDataSubject.next(data);
console.log(data);
}
}
"catalog"
import { Component, OnInit, Input } from '#angular/core';
import {RequestService} from '../../services/request/request.service';
import {DataShareService} from '../../services/dataShare/data-share.service';
import { Music } from '../../models/music';
#Component({
selector: 'catalog',
templateUrl: './catalog.component.html',
styleUrls: ['./catalog.component.sass'],
providers: [RequestService, DataShareService]
})
export class CatalogComponent implements OnInit {
public title: any;
public InfoLlegada: any;
constructor(private _dataShareService: DataShareService) {}
ngOnInit() {
console.log(this.InfoLlegada)
this._dataShareService.$sendDataObservable.subscribe(
data => {
this.InfoLlegada = data
console.log(data);
});
}
}
Not sure if this is the actual cause, but there an issue with your this binding in getMusic subscription in search component. Try this.sendData.call(this, result.results);

Theme switcher on localstorage observable service

I implemented a dynamic theme switcher (with tutorial) in my angular app. It work's but when I reload website, the choice is not remembered.
I read about localStorage and i will use it but still doesn't work because I don't know how "where" I should get data from this localStorage, that the choice of the theme will be remembered when I reload the page.
I have this code:
theme.service.ts new version
import { Injectable } from '#angular/core';
import { Subject } from 'rxjs/Subject';
#Injectable()
export class ThemeService {
private _themeDark: Subject<boolean> = new Subject<boolean>();
isDarkFunction() {
let value = localStorage.getItem('isDark');
this._themeDark.next(value);
return this._themeDark.asObservable();
}
isThemeDark = this.isDarkFunction();
setDarkTheme(isThemeDark: boolean) {
this._themeDark.next(isThemeDark);
localStorage.setItem('isDark', JSON.stringify(isThemeDark));
}
}
navbar.component.html
<div class="container-fluid switcher-container">
<mat-slide-toggle [checked]="isThemeDark | async" (change)="toggleDarkTheme($event.checked)">Dark theme</mat-slide-toggle>
</div>
navbar.component.ts
import { Component, OnInit } from '#angular/core';
import { ThemeService } from '../services/theme.service';
import { Observable } from 'rxjs/Observable';
#Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.scss']
})
export class NavbarComponent implements OnInit {
isThemeDark: Observable<boolean>;
constructor(
private themeService: ThemeService) { }
ngOnInit() {
this.isThemeDark = this.themeService.isThemeDark;
}
toggleDarkTheme(checked: boolean) {
this.themeService.setDarkTheme(checked);
}
}
app.component.ts
import { Component, OnInit } from '#angular/core';
import { Observable } from "rxjs/Observable";
import { ThemeService } from "./services/theme.service";
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
providers: [ThemeService]
})
export class AppComponent implements OnInit {
isThemeDark: Observable<boolean>;
constructor(
public themeService: ThemeService) {
}
ngOnInit() {
this.isThemeDark = this.themeService.isThemeDark;
}
}
Please help,
Regards
You might write something like the following in theme.service.ts.
I don't know if it will run flawlessly as is but the idea is to read from localstorage in isThemeDark().
isThemeDark() {
let value = localStorage.getItem('isDark');
this._themeDark.next(value);
return this._themeDark.asObservable();
}
I think it's because you when you do localStorage.getItem('isDark') the result is a string, not a boolean. Maybe try:
let value = JSON.parse(localStorage.getItem('isDark')) === true;
Also check manually if the localstorage is kept after a refresh. Some browsers have a setting to clear everything on refresh.

(Angular2) JSON data (http.get()) is undefined, and data is not updated in the component

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);
}));
}
}

Categories

Resources