*ngif not working if using subscribe in ngOnInit - html

this is my component code
import { Component, OnInit } from '#angular/core';
import { Subscription } from 'rxjs';
//import { Item } from '../item/item.model';
import { CartItem } from './cart-item.model';
import { CartService } from './my-cart.service';
#Component({
selector: 'app-my-cart',
templateUrl: './my-cart.component.html',
styleUrls: ['./my-cart.component.css']
})
export class MyCartComponent implements OnInit {
items:CartItem[];
subscribe:Subscription;
display=true;
constructor(private cartService:CartService) { }
ngOnInit(): void {
this.subscribe=this.cartService.itemsChanged.subscribe(
(items:CartItem[])=>{
this.items=items;
});
}
ngOnDestroy(): void {
this.subscribe.unsubscribe();
}
}
and this is my html code
<p *ngIf="display">my-cart works!</p>
if i removed the subscription from ngOnInit it works fine.
can any one help? I don't know why it doesn't work

These two are irrelevant. Try this display: boolean =true;

Related

I get undefined property when I share boolean data between Angular components using #ViewChild

I have a component named RedirectUserToMobileAppComponent , I want to share a boolean property from it named enableLoginForm with app.component.
When I execute, I get this error :
enableLoginForm is undefined property on ngAfterViewInit in app.component
this is RedirectUserToMobileAppComponent component:
import {
Component,
ComponentFactoryResolver,
ComponentRef,
Inject,
Input,
OnInit,
Output,
ViewChild,
ViewContainerRef,
} from '#angular/core';
import { Observable, Subscription } from 'rxjs';
import { filter, map, pluck, tap } from 'rxjs/operators';
import { ActivatedRoute, Router } from '#angular/router';
import { MAT_DIALOG_SCROLL_STRATEGY_FACTORY } from '#angular/material/dialog';
#Component({
selector: 'redirect-user-to-mobile-app',
templateUrl: './redirect-user-to-mobile-app.component.html',
styleUrls: ['./redirect-user-to-mobile-app.component.sass'],
})
export class RedirectUserToMobileAppComponent implements OnInit {
constructor(
) {}
enableLoginForm = false;
ngOnInit(): void {}
OnLogin(): void {
this.enableLoginForm = true;
this.router.navigate(['../login']);
}
}
and this is app.component:
import {
Component,
HostListener,
OnDestroy,
OnInit,
ViewChild,
AfterViewInit,
} from '#angular/core';
import { MatIconRegistry } from '#angular/material/icon';
import { DomSanitizer } from '#angular/platform-browser';
import { FirebaseService } from './services/firebase/firebase.service';
import {
SnakeMessage,
SnakeMessageService,
} from './services/snakeMessage/snakeMessage.service';
import { MatSnackBar } from '#angular/material/snack-bar';
import { Subscription } from 'rxjs';
import { StorageService } from './services/storage/storage.service';
import { AuthService } from './services/auth/auth.service';
import { RedirectUserToMobileAppComponent } from './redirect-user-to-mobile-app/redirect-user-to-mobile-app.component';
#Component({
selector: 'app-component',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit, OnDestroy, AfterViewInit {
favIcon: HTMLLinkElement = document.querySelector('#appIcon');
private snakeMessageSub: Subscription;
isLoading = true;
isLogged: boolean;
#ViewChild(RedirectUserToMobileAppComponent)
redirectComponent!: RedirectUserToMobileAppComponent;
constructor(
private matIconRegistry: MatIconRegistry,
private firebaseService: FirebaseService,
private snakeMessageService: SnakeMessageService,
private _snackBar: MatSnackBar,
private storageService: StorageService,
private domSanitizer: DomSanitizer,
private authService: AuthService
) {
this.registerCustomIcons();
this.storageService.initDB();
this.storageService.onLoaded$.subscribe((loaded) => {
if (loaded) {
this.isLoading = false;
}
});
this.isLogged = this.authService.isLoggedIn;
}
ngAfterViewInit() {
if (this.redirectComponent.enableLoginForm) {
this._is = this.redirectComponent.enableLoginForm;
}
}
ngOnInit(): void {
this.snakeMessageSub = this.snakeMessageService.messageSub.subscribe(
(snakeMessage: SnakeMessage) => {
this._snackBar.open(snakeMessage.message, snakeMessage.action, {
duration: 3000,
horizontalPosition: 'center',
verticalPosition: 'top',
});
}
);
}
this is my app.component.html
<ng-container *ngIf="!isLoading">
<ng-container *ngIf="isMobileDevice() && !isLogged">
<redirect-user-to-mobile-app> </redirect-user-to-mobile-app>
<router-outlet
*ngIf="enableLoginForm"
></router-outlet>
</ng-container>
<router-outlet *ngIf="!isMobileDevice()"></router-outlet>
This is how you use ViewChild:
#ViewChild('templateId', { static: false }) redirectComponent: RedirectUserToMobileAppComponent;
You should have the templateId set in the template part :
<redirect-user-to-mobile-app #templateId> ... </redirect-user-to-mobile-app>
EDIT: Though I agree with skyBlue, you should use a service to shared data between components
ViewChild returns a reference to the HTML element.
I will quote from angular.io:
Property decorator that configures a view query. The change detector looks for the first element or the directive matching the selector in the view DOM. If the view DOM changes, and a new child matches the selector, the property is updated.
So you cant access it's controller variables with ViewChild.
My suggestion for you is to use a service for passing data.
I have changed the method, I have used #Output() component and it works fine:
this is RedirectUserToMobileAppComponent component after changing the method :
import {
Component,
ComponentFactoryResolver,
ComponentRef,
Inject,
Input,
OnChanges,
OnInit,
Output,
SimpleChanges,
ViewChild,
ViewContainerRef,
EventEmitter,
} from '#angular/core';
import { Observable, Subscription } from 'rxjs';
import { filter, map, pluck, tap } from 'rxjs/operators';
import { ActivatedRoute, Router } from '#angular/router';
import { MAT_DIALOG_SCROLL_STRATEGY_FACTORY } from '#angular/material/dialog';
#Component({
selector: 'yobi-redirect-user-to-mobile-app',
templateUrl: './redirect-user-to-mobile-app.component.html',
styleUrls: ['./redirect-user-to-mobile-app.component.sass'],
})
export class RedirectUserToMobileAppComponent implements OnInit {
constructor(
private router: Router,
private componentFactoryResolver: ComponentFactoryResolver
) {}
#Output() _enableLoginForm: EventEmitter<boolean> = new EventEmitter();
variable: any;
login: boolean;
enableLoginForm = false;
enableSignupForm = false;
ngOnInit(): void {}
sendDataToParent() {
this.enableLoginForm = true;
this._enableLoginForm.emit(this.enableLoginForm);
console.log(this.enableLoginForm + ' From redirect ');
}
I added this to RedirectUserToMobileAppComponent.html:
<a class="login-text" (click)="sendDataToParent()">
Login
</a>
I added this code to app.component :
receiveChildData($event) {
this.enableLoginForm = $event;
}
I added this code to the app.component.html :
<redirect-user-to-mobile-app
(_enableLoginForm)="receiveChildData($event)"
>
</redirect-user-to-mobile-app>

How to retrieve all id of firebase database content using Angular?

I am trying to retrieve all firebase database content with their IDs. Currently I have two functions, getAll() and get(input) which returns one specific product with the given ID. My current implementation gives me all the objects from firebase database without the IDs. What do I need to change to be able to get all objects with their IDs?
product.service.ts
import { Injectable } from '#angular/core';
import { AngularFireDatabase } from '#angular/fire/database';
import { Product } from './admin/product-form/product-interface';
#Injectable({
providedIn: 'root'
})
export class ProductService {
constructor(private db: AngularFireDatabase) { }
create(product){
return this.db.list('/products').push(product);
}
getAll() {
return this.db.list('/products').valueChanges();
}
get(productId){
return this.db.object('/products/' + productId).valueChanges();
}
}
product-form.component.ts
import { Product } from './product-interface';
import { ProductService } from './../../product.service';
import { CategoryService } from './../../category.service';
import { Component, OnInit } from '#angular/core';
import { Router, ActivatedRoute } from '#angular/router';
import { take } from 'rxjs/operators';
#Component({
selector: 'app-product-form',
templateUrl: './product-form.component.html',
styleUrls: ['./product-form.component.css']
})
export class ProductFormComponent implements OnInit {
categories$;
product = {};
// product:Product;
constructor(
private route: ActivatedRoute,
private router: Router,
private categoryService: CategoryService,
private productService: ProductService)
{
}
save(product){
this.productService.create(product);
this.router.navigate(['/admin/products']);
}
ngOnInit(): void {
this.categories$ = this.categoryService.getCategories();
let id = this.route.snapshot.paramMap.get('id');
this.productService.getAll().subscribe((a) =>
this.product = a);
}
}
admin-products.component.ts
import { ProductService } from './../../product.service';
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-admin-products',
templateUrl: './admin-products.component.html',
styleUrls: ['./admin-products.component.css']
})
export class AdminProductsComponent implements OnInit {
products$;
constructor(private productService: ProductService) {
this.products$ = this.productService.getAll()
}
ngOnInit(): void {
this.products$.subscribe(p => {
console.log(p, 'products');
})
}
}
admin-products.component.html
<p>
<a routerLink = "/admin/products/new" class="btn btn-primary">New Product</a>
</p>
<table class="table">
<thead>
<tr>
<th>Title</th>
<th>Price</th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let p of products$ | async">
<td>{{ p.title }}</td>
<td>{{ p.price}}</td>
<td>
<a [routerLink]="['/admin/products/', p.$key]">Edit</a>
</td>
</tr>
</tbody>
</table>
Btw, if you subscribe to observables in components (not in angular services), you will have to unsubscribe them ngOnDestroy() lifecycle hook to avoid memory and performance issues in your browser.
You'll need to use snapshotChanges() instead of valueChanges(). valueChanges() only gives you the document data while snapshotChanges() will also give you metadata.
View relevant docs

Subscribe a local variable Value to an Observable of variable in another Component in Angular

I want to change an HTML view via *ngIf, based on a local variable, which should change based on a variable delivered through an observable from a shared service.
HTML
<div class="login-container" *ngIf="!isAuthenticated">
TypeScript of same component:
export class LoginComponent implements OnInit {
authenticationsSubscription;
isAuthenticated: boolean;
constructor(
private authService: AuthServiceService,
private router: Router,
private route: ActivatedRoute){}
getAuth(): Observable<boolean>{
return this.authService.validation();
}
ngOnInit() {
this.authenticationsSubscription = this.authService.validation().subscribe(auth => this.isAuthenticated = auth);
}
}
TypeScript of shared service AuthService:
export class AuthServiceService {
isAuthenticated: boolean;
validation(): Observable<boolean>{
return of(this.isAuthenticated);
}
}
While debugging I found out, the variable isAuthenticated in the LoginComponent does not change, on changes of the variable isAuthenticated of the AuthService. I also tried using pipe() and tap(), which did not change anything.
What am I doing wrong?
Convert your AuthServiceService to have the authentication state as a BehaviorSubject and return it as Observable as described below.
import { Observable, BehaviorSubject } from "rxjs";
export class AuthServiceService {
private isAuthenticatedSub: BehaviorSubject<boolean> = new BehaviorSubject(false);
set isAuthenticated(isAuthenticated: boolean) {
this.isAuthenticatedSub.next(isAuthenticated);
}
get isAuthenticated(): boolean {
return this.isAuthenticatedSub.value;
}
validation(): Observable<boolean> {
return this.isAuthenticatedSub.asObservable();
}
}
The actual subscription of your observable will only happens once, when the OnInit lifecycle hook is triggered when the component is initialized.
You can subscribe to a BehaviorSubject in order to catch value changes.
Stackblitz example
AuthService
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs';
#Injectable()
export class AuthService {
isAuthenticated: BehaviorSubject<boolean>;
constructor() {
this.isAuthenticated = new BehaviorSubject<boolean>(false);
}
}
Component
import { Component, OnInit } from '#angular/core';
import { AuthService } from './auth.service';
import { Observable } from 'rxjs';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
isAuthenticated: Observable<boolean>;
constructor(private authService: AuthService) {}
ngOnInit() {
this.isAuthenticated = this.authService.isAuthenticated;
}
login() {
this.authService.isAuthenticated.next(true);
}
logout() {
this.authService.isAuthenticated.next(false);
}
}
Template
<div *ngIf="isAuthenticated | async; else notAuthenticated">
User is authenticated
</div>
<ng-template #notAuthenticated>
<div>User isn't authenticated</div>
</ng-template>
<button (click)="login()">Login</button>
<button (click)="logout()">Logout</button>

null parameters from angular

I am trying to send parameters from my angular app using httpRequest.
I am getting back Null to my backend server.
I have checked with Postman and Fiddler both work with a json Object.
I have tried changing from Post to Get.
I am using Java RestAPI for the backend with apache Tomcat as the server.
This is my Service for login:
#Injectable({
providedIn: 'root'
})
export class LoginService {
private loginURL='http://localhost:8080/CouponSystemWeb/rest/loginpage/login'
constructor(private http:HttpClient) { }
public login(loginDetailes:LoginDetailes):Observable<LoginDetailes>{
return this.http.post<LoginDetailes>(this.loginURL,loginDetailes,{withCredentials:true})
}
}
This is my Login Component:
import { Component, OnInit } from '#angular/core';
import { LoginDetailes } from 'src/app/Entities/LoginDetailes';
import { LoginService } from 'src/app/services/login.service';
import { Router } from '#angular/router';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
public loggedin:boolean;
public loggedClient:string;
public errormessage:string;
public loginDetailes = new LoginDetailes();
constructor(private loginservice:LoginService,private router:Router) { }
ngOnInit() {
this.loggedin=false;
}
public onLogin():void{
const observable=this.loginservice.login(this.loginDetailes);
observable.subscribe((returnedLoginDetailes:LoginDetailes)=>{
alert("Login Aquired");
this.loggedin=true;
if(this.loginDetailes.clientType=="ADMIN"){
this.router.navigate(['/crtComp']);
}
else if(this.loginDetailes.clientType=="COMPANY"){
this.router.navigate(['/login']);
}
else if(this.loginDetailes.clientType=="CUSTOMER"){
this.router.navigate(['/login']);
}else{
alert("Wrong Login Detailes");
}
}, err => {
this.errormessage=err.console.error("Wrong Detailes please Check Again!");
alert(this.errormessage);
}
)}}
This is the login Entity :
export class LoginDetailes{
public name:string
public password:string
public clientType:string
constructor(){
}
}
I have tried ngModel but that didn't fix the problem.
I have tried changing my backend from Post to Get.
The problem happends only in the angular App. I can send parameters with fiddler and Postman without problem.
Ok the answer was not in the component or the service.
the problem was in the HTML i was missing the ngModel two way data binding so my App was sending null's.

Component dosen't work in all ionic views

I'm working on an Ionic 2 project and I'm using a component called "offre".
I have got a problem running this component. It works correctly in the home page but not in the views (check this picture to see the error)
The data from firebase shown correctly in home.html but not in the other views!
Any suggestions?
Offre.ts code:
import { Component } from '#angular/core';
import { AngularFireDatabase, FirebaseListObservable } from "angularfire2/database";
import { IonicPage, NavController, NavParams} from 'ionic-angular';
import { NativeStorage } from '#ionic-native/native-storage';
#Component({
selector: 'offre',
templateUrl: 'offre.html'
})
export class OffreComponent {
text: string;
datas: FirebaseListObservable<any>;
user : any ;
constructor(public navCtrl: NavController, public db: AngularFireDatabase, public nativeStorage: NativeStorage) {
this.datas=db.list('/posts');
console.log('Hello OffreComponent Component');
}