*ngIf works OK in some parts, but not in others. Angular 2.0.x - angular2-directives

I am trying to use *ngIf in a simple component and angular is throwing an error on *ngIf.
Removing the "*ngIf="loggedIn" and it runs. {{loggedIn}} shows true after logging in and false before.
The main app uses the same div to enable menus, which works fine.
I must be doing some simple wrong but it escapes me.
thanks
First the error:
Can't bind to 'ngIf' since it isn't a known property of 'div'. ("<div [ERROR ->]*ngIf="loggedIn">
<div class='panel panel-primary'>
<div class='panel-heading' >
"): ShowConfigComponent#0:5
Property binding ngIf not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "directives" section. ("[ERROR ->]<div *ngIf="loggedIn">
<div class='panel panel-primary'>
<div class='panel-heading' >
"): ShowConfigComponent#0:0 ; Zone: <root> ; Task: Promise.then ; Value: Error: Template parse errors:(…) Error: Template parse errors:
Can't bind to 'ngIf' since it isn't a known property of 'div'. ("<div [ERROR ->]*ngIf="loggedIn">
<div class='panel panel-primary'>
<div class='panel-heading' >
"): ShowConfigComponent#0:5
Property binding ngIf not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "directives" section. ("[ERROR ->]<div *ngIf="loggedIn">
<div class='panel panel-primary'>
<div class='panel-heading' >
"): ShowConfigComponent#0:0
at TemplateParser.parse (http://127.0.0.1:8080/node_modules/#angular/compiler/bundles/compiler.umd.js:8446:21)
at RuntimeCompiler._compileTemplate (http://127.0.0.1:8080/node_modules/#angular/compiler/bundles/compiler.umd.js:16824:53)
at eval (http://127.0.0.1:8080/node_modules/#angular/compiler/bundles/compiler.umd.js:16746:85)
at Set.forEach (native)
at compile (http://127.0.0.1:8080/node_modules/#angular/compiler/bundles/compiler.umd.js:16746:49)
at ZoneDelegate.invoke (http://127.0.0.1:8080/node_modules/zone.js/dist/zone.js:203:28)
at Zone.run (http://127.0.0.1:8080/node_modules/zone.js/dist/zone.js:96:43)
at http://127.0.0.1:8080/node_modules/zone.js/dist/zone.js:462:57
at ZoneDelegate.invokeTask (http://127.0.0.1:8080/node_modules/zone.js/dist/zone.js:236:37)
at Zone.runTask (http://127.0.0.1:8080/node_modules/zone.js/dist/zone.js:136:47)
Template:
<div *ngIf="loggedIn">
<div class='panel panel-primary'>
<div class='panel-heading' >
Shows Configuration {{loggedIn}}
</div>
</div>
Component:
import { Component, OnInit } from '#angular/core';
import { IShowConfig } from './iShowConfig';
import { AuthService } from '../../shared/AuthService';
import { BrowserModule } from '#angular/platform-browser';
#Component({
// selector: 'showconfig',
templateUrl: 'app/showMenu/showConfig/ShowConfig.component.html'
})
export class ShowConfigComponent implements OnInit {
pageTitle: string = 'Product List';
imageWidth: number = 50;
imageMargin: number = 2;
showImage: boolean = false;
listFilter: string = '';
errorMessage: string;
shows: IShowConfig[];
public isLoggedIn: boolean = true;
// constructor(private _productService: ProductService) {
constructor(public authSvc: AuthService) {
this.isLoggedIn = true;
console.log(`config loggedIn: `);
console.log(`${AuthService.isLoggedIn}`);
if (authSvc.user === undefined) {
console.log('islogin undefine');
} else {
console.log('config user: ' + authSvc.user);
}
console.log('show config count: ' + AuthService.count);
}
public get loggedIn(): boolean {
if (AuthService.isLoggedIn) {
return true;
} else {
return false;
}
}
toggleImage(): void {
this.showImage = !this.showImage;
}
ngOnInit(): void { }
onRatingClicked(message: string): void {
this.pageTitle = 'Show List: ' + message;
}
}

I found the solution! I think Nicu also guessed what it was.
I didn't import BrowserModule into my ShowConfig.module.ts ie: my #ngmodule.
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { ShowConfigComponent } from './ShowConfig.component';
import { AuthService } from '../../shared/AuthService';
import { BrowserModule } from '#angular/platform-browser';**
#NgModule({
imports: [
// The following line was missing
BrowserModule,
FormsModule
],
declarations: [
ShowConfigComponent
],
providers: [
]
})
export class ShowConfigModule { }

Related

AngularFire: How To Access Firestore Only When Authenticated

I would like to limit Firestore access to authenticated users using AngularFire but am getting the following error:
core.js:6456 ERROR FirebaseError: Missing or insufficient permissions.
at new e (prebuilt-109c6673-0f51e182.js:188)
at prebuilt-109c6673-0f51e182.js:10416
at prebuilt-109c6673-0f51e182.js:10414
at e.onMessage (prebuilt-109c6673-0f51e182.js:10403)
at prebuilt-109c6673-0f51e182.js:10356
at prebuilt-109c6673-0f51e182.js:10387
at prebuilt-109c6673-0f51e182.js:15194
at ZoneDelegate.invoke (zone.js:372)
at Zone.run (zone.js:134)
at zone.js:1276
I created a very basic test application to test this.
app.component.html
<ng-container *ngIf="auth.user | async as user; else showLogin">
<ul>
<li *ngFor="let profile of profiles | async">{{profile.DisplayName}}</li>
</ul>
</ng-container>
<ng-template #showLogin>
<p>You must sign in to continue.</p>
<button (click)="signIn()"> SIGN IN </button>
</ng-template>
app.component.ts
import { Component } from '#angular/core';
import { AngularFirestore } from '#angular/fire/firestore';
import { AngularFireAuth } from '#angular/fire/auth';
import { Observable } from 'rxjs';
import firebase from 'firebase/app';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'test-auth';
profiles: Observable<any[]>;
constructor (
public auth: AngularFireAuth,
private firestore: AngularFirestore) {
this.profiles = firestore.collection('UserProfiles').valueChanges();
}
signIn(): void {
this.auth.signInWithPopup(new firebase.auth.GoogleAuthProvider());
}
signOut(): void {
this.auth.signOut();
}
}
My Firestore Rules
If the read rule is changed to only "allow read;" the application above works as expected.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents/{document=**} {
allow read: if request.auth != null;
allow write: if request.auth != null;
}
}
My Versions
Angular CLI: 12.0.3
Node: 14.17.0
Package Manager: npm 7.13.0
OS: linux x64
Angular: 12.0.3
... animations, cli, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router
Package Version
---------------------------------------------------------
#angular-devkit/architect 0.1200.3
#angular-devkit/build-angular 12.0.3
#angular-devkit/core 12.0.3
#angular-devkit/schematics 12.0.3
#angular/fire 6.1.5
#schematics/angular 12.0.3
rxjs 6.6.7
typescript 4.2.4
$ firebase --version
9.12.1
However - raw Firebase works as expected.
With the following code, I have isolated this issue to (1) a bug (?) in AngularFire or (2) my inability to properly implement AngularFire in the code provided in my prior comment.
app.component.ts
import { Component, OnDestroy, OnInit } from '#angular/core';
import firebase from 'firebase/app';
import 'firebase/firestore';
import 'firebase/auth';
export interface ProfileModel {
Id: string,
DisplayName: string
}
export interface CurrentUser {
uid: string;
name?: string;
email?: string;
}
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnDestroy, OnInit {
title = 'test-auth';
currentUser: CurrentUser | null = null;
profilesArray: ProfileModel[] = [];
fb: firebase.app.App;
fs: firebase.firestore.Firestore;
profilesCollection: firebase.firestore.CollectionReference<firebase.firestore.DocumentData>;
unsubscribe?: firebase.Unsubscribe;
constructor () {
this.fb = firebase.initializeApp({
apiKey: "OMITTED",
authDomain: "angularfiretestapp.firebaseapp.com",
databaseURL: "https://angularfiretestapp.firebaseio.com",
projectId: "angularfiretestapp",
storageBucket: "angularfiretestapp.appspot.com",
messagingSenderId: "OMITTED",
appId: "OMITTED",
measurementId: "OMITTED"
});
this.fs = firebase.firestore();
this.profilesCollection = this.fs.collection('UserProfiles');
}
ngOnDestroy():void {
if (this.unsubscribe) {
this.unsubscribe();
}
}
ngOnInit():void {
this.unsubscribe = this.fb.auth().onAuthStateChanged(authUser => {
if (authUser) {
this.currentUser = {
uid: authUser.uid,
name: authUser.displayName ? authUser.displayName : '',
email: authUser.email ? authUser.email : ''
};
this.profilesArray = [];
this.profilesCollection.get().then(qSnap => {
qSnap.forEach(doc => {
this.profilesArray.push({
Id: doc.id,
DisplayName: doc.get('DisplayName')
});
});
});
} else {
this.currentUser = null;
}
});
}
signIn(): void {
this.fb.auth().signInWithPopup(new firebase.auth.GoogleAuthProvider());
}
signOut(): void {
this.fb.auth().signOut();
}
}
app.component.html
<ng-container *ngIf="currentUser; else showLogin">
<p>Here are some profiles:</p>
<ul>
<li *ngFor="let profile of profilesArray">{{profile.DisplayName}}</li>
</ul>
<button (click)="signOut()"> SIGN OUT </button>
</ng-container>
<ng-template #showLogin>
<p>You must sign in to continue.</p>
<button (click)="signIn()"> SIGN IN </button>
</ng-template>
Posted Elsewhere
Issue 2838 filed on GitHub.
Also posted on Reddit.
My code is available in this GitHub repository.
In your constructor it should look more like this
auth.onAuthStateChanged((user) => {
if (user && user.emailVerified) {
this.profiles = firestore.collection('UserProfiles').valueChanges();
} else {
signIn();
}
});
If it still throws exceptions you could try downgrading firebase to 8.3.0.

Angular undefined value of #input variable

I'm new to Angular and I have some issues , hope you'll help me.
so I'm trying to share a value of a variable from a ProjectComponent to an AcceuilComponent , the value of this variable is displaying correctly into my acceuil.component.html but when I try to use it into my acceuil.component.ts it's undefined !
project.component.html (the parent component)
<app-header-in></app-header-in>
<ng-sidebar-container>
<ng-sidebar [opened]="opened">
<p> Sidebar </p>
<button (click)="Sidebar()">
Close Sidebar
</button>
<ul class="menu">
<li class="hh"
*ngFor="let project of projects"
[class.selected]="project === selectedProject"
(click)="onSelect(project)">
{{project.nomprojet}}</li>
</ul>
</ng-sidebar>
<div ng-sidebar-content >
<br><br><br><br>
<button (click)="Sidebar()">
Open Sidebar
</button>
<app-acceuil [message]="idProject"></app-acceuil>
</div>
</ng-sidebar-container>
project.component.ts
import { Component, OnInit } from '#angular/core';
import { ApiService } from '../api.service';
import {ProjectService} from '../project.service';
import {PartService} from '../part.service';
#Component({
selector: 'app-project',
templateUrl: './project.component.html',
styleUrls: ['./project.component.css']
})
export class ProjectComponent implements OnInit {
opened=true;
projects:any;
idProject;
selectedProject;
constructor(private projectService:ProjectService) { }
ngOnInit(): void {
this.projectService.getProjects().subscribe((result)=>{console.log("result",result)
this.projects=result})
}
Sidebar(){
this.opened=!this.opened;
}
onSelect(pro): void {
this.idProject = pro.id;
}
}
acceuil.component.html (my child component)
<p>{{message}}</p>
<ul >
<li class="hh"
*ngFor="let part of parts">
{{part.nomparti}}
</li>
</ul>
acceuil.component.ts
import { Component, OnInit,Input } from '#angular/core';
import { ApiService } from '../api.service';
import {PartService} from '../part.service';
#Component({
selector: 'app-acceuil',
templateUrl: './acceuil.component.html',
styleUrls: ['./acceuil.component.css']
})
export class AcceuilComponent implements OnInit {
#Input() message;
parts:any;
constructor(private partService:PartService) {
}
ngOnInit(): void{
console.log("id",this.message);
this.partService.getPartsFromIdProject(this.message).subscribe((result)=>{console.log("result",result)
this.parts=result})
}
ngOnChanges() {
if(this.message) {
console.log(this.message)
}
}
}
I'm using the message to call a service and displaying data .
in the acceuil.component.html <p>{{message}}</p> is displaying correctly but console.log("id",this.message); in acceuil.component.ts displays undefined
As message is an input property, you need to get its value in ngOnchanges life cycle.
First time, when it is in ngOnChanges, input value will be undefined. So for the safe side, better to add a check for not undefiled condition like below
ngOnChanges(changes: SimpleChanges) {
if (changes.message) {
// Should be defined now
console.log(this.message);
}
}

TypeError: this.navigator.element.pushPage is not a function

Im using onsen-ui with angular 8 I'm getting error in the below function, I am not sure why this happens, because it is the code from the onsenUI-page.
push(event, value){
console.log(value);
this.navigator.element.pushPage(value, {animation: 'slide'});
}
My code
Sidemenu.html
<ons-page id="menu">
<ons-toolbar>
<div class="center">Menu</div>
</ons-toolbar>
<div class="background"></div>
<div class="content">
<ons-list>
<ons-list-item (click)="push($event, 'HomeComponent')" tappable>
Home
</ons-list-item>
<ons-list-item (click)="push($event, 'FormComponent')" tappable>
Form
</ons-list-item>
</ons-list>
</div>
</ons-page>
sidemenucomponent.html
import { Component, OnInit } from '#angular/core';
import { ViewChild, OnsNavigator} from 'ngx-onsenui';
import { HomeComponent } from './../home/home.component';
#Component({
selector: 'ons-page[third]',
templateUrl: './sidemenu.component.html',
styleUrls: ['./sidemenu.component.scss'],
providers:[OnsNavigator]
})
export class SidemenuComponent implements OnInit {
constructor(private navigator: OnsNavigator) { }
ngOnInit() {
}
push(event, value){
console.log(value);
this.navigator.element.pushPage(value, {animation: 'slide'});
}
}
Im getting error
ERROR TypeError: this.navigator.element.pushPage is not a function
at SidemenuComponent.push (sidemenu.component.ts:20)
at Object.eval [as handleEvent] (VM5587 SidemenuComponent.ngfactory.js:21)
at handleEvent (core.js:43993)
at callWithDebugContext (core.js:45632)
at Object.debugHandleEvent [as handleEvent] (core.js:45247)
at dispatchEvent (core.js:29804)
at core.js:42925
at HTMLElement.<anonymous> (platform-browser.js:2668)
at ZoneDelegate.invokeTask (zone-evergreen.js:391)
at Object.onInvokeTask (core.js:39680)
Below is the app component i added but still getting same error
app.component.html
<ons-navigator swipeable [page]="sidePage"></ons-navigator>
<ons-page id="apppage">
<ons-splitter #splitter>
<ons-splitter-side [page]="sidePage" side="left" width="300px" collapse swipeable>
</ons-splitter-side>
<ons-splitter-content [page]="contentPage">
</ons-splitter-content>
</ons-splitter>
</ons-page>
<router-outlet></router-outlet>
app.component.ts
import { Component } from '#angular/core';
import { HomeComponent } from './components/home/home.component';
import { SidemenuComponent } from './components/sidemenu/sidemenu.component';
import { MenuService } from './menu-service.service';
import {
Injectable,
ViewChild,
} from 'ngx-onsenui';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'my-app';
sidePage = SidemenuComponent;
contentPage = HomeComponent;
#ViewChild('splitter',{static: false}) splitter;
constructor(private menuService: MenuService) {
this.menuService.menu$.subscribe(() => this.splitter.nativeElement.side.open());
}
}
Please can anyone help.

How to pass value from template HTML to component to then be used in service

I want to fetch id from component.html into component.ts to pass it to a service.
.ts file is;
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http'
import { HttpErrorResponse } from '#angular/common/http/src/response';
import { SendUsingApiService } from '../send-using-api.service';
import { Router, ActivatedRoute } from '#angular/router';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
import { setDefaultService } from 'selenium-webdriver/chrome';
#Component({
selector: 'app-org-info',
templateUrl: './org-info.component.html',
styleUrls: ['./org-info.component.css'],
providers: [SendUsingApiService]
})
export class OrgInfoComponent implements OnInit {
orgData: string[] = [];
Id = 1;
editRecord:FormGroup;
constructor(private httpService: HttpClient, private _serv: SendUsingApiService,
private fb: FormBuilder, private _ar:ActivatedRoute, private _r:Router) {
this.editRecord = this.fb.group({
Id:['1', []],
OrganisationName:['', []],
ContactPerson:['', []],
ContactPersonHPNo:['', []],
ContactPersonEmailId:['', []]
});
}
ngOnInit() {
console.log(this._ar.snapshot.params.Id, "+ve");
this._ar.params.subscribe(() => {
this._serv.getUsers(this._ar.snapshot.params.Id).subscribe((res)=>{
console.log(res);
this.setUser(res);
});
});
}
I am getting the value for console.log(this._ar.snapshot.params.Id); as undefined "+ve".
I want to get the Id value in console.
As per requests I am adding html part, though little adjusted;
<td style="text-align: center;">
<a class="btn btn-basic" [routerLink]="['/org-info',data['Id']]" role="button" (click)="getOrgData(data.Id)">View</a>
</td>
I defined a property instead of Id = 1; (above)
paramId = '';
then, within ngOnInit;
ngOnInit() {
this.paramId = this._ar.snapshot.params.Id;
console.log(paramId, "+ve");
}
Doing this, I got the Id value instead of undefined.

Aurelia - Watch Dependency Value for Change

Suppose you have a class you are injecting into a another class or component. Is there a way to watch for changes on an attributed of the dependency you are injecting and act upon it?
For example, say you have the following app:
app.html
<template>
<input type="text" value.bind="item">
<button click.trigger="addToList()">Add</button>
<h3>Modded</h3>
<ul>
<li repeat.for="it of modded">${it}</li>
</ul>
<h3>Original</h3>
<ul>
<li repeat.for="it of dep.items">${it}</li>
</ul>
</template>
app.js
import {bindable, inject} from 'aurelia-framework';
import {Dep} from './dep';
#inject(Dep)
export class App {
constructor(dep) {
this.dep = dep;
}
attached() {
this.modifyItems();
}
addToList() {
this.dep.addItem(this.item);
}
modifyItems() {
this.modded = [];
for (let item of this.dep.items) {
this.modded.push(item.toUpperCase());
}
}
}
dep.js
export class Dep {
constructor() {
this.items = ['one', 'two', 'three'];
}
addItem(item) {
this.items.push(item);
}
}
Now, let's say that some other component modifies Dep.items. Is there a way to watch for changes in app.js on this.dep.items and then call modifyItems()?
Assume modifyItems() is more complex than this example so maybe a value converter is not the best option. (unless it is the only option I guess)
Here is working plunker with the above example: http://plnkr.co/edit/rEs9UM?p=preview
Someone pointed me to the BindingEngine.collectionObserver and it appears that is what I needed.
app.js:
import {inject} from 'aurelia-framework';
import {BindingEngine} from 'aurelia-binding';
import {Dep} from './dep';
#inject(Dep, BindingEngine)
export class App {
constructor(dep, bindingEngine) {
this.dep = dep;
let subscription = bindingEngine.collectionObserver(this.dep.items)
.subscribe((newVal, oldVal) => {
console.debug(newVal, oldVal);
this.modifyItems();
});
}
attached() {
this.modifyItems();
}
addToList() {
this.dep.addItem(this.item);
this.item = '';
}
modifyItems() {
this.modded = [];
for (let item of this.dep.items) {
this.modded.push(item.toUpperCase());
}
}
}
Here is the working pluker: http://plnkr.co/edit/Pcyxrh?p=preview