NG0303: Can't bind to 'ngForOf' since it isn't a known property of 'div' - angular12

I have added a condition and the page doesn't load the div anymore. Please let me know if I did something wrong. I am making an API call and fetching parentmodules which should bind if any data is present.
TypeScript:
import { Component } from '#angular/core';
import { Title } from '#angular/platform-browser';
import { ActivatedRoute, Router } from '#angular/router';
import * as _ from 'lodash';
import { Module } from '.../module';
#Component({
selector: '...',
templateUrl: './....html',
styleUrls: ['./....component.scss']
})
export class AdministrationComponent {
modules: Module[] = [];
parentmodules: Module[] = [];
showModules: boolean = false;..........
}
HTML:
<div *ngFor="let eachparentmodule of parentmodules" class="mt-5">
<h6 class="mb-0 text-uppercase">
{{eachparentmodule.name}}
</h6>
</div>

Related

Why the state of my app does not change in my angular app using NGRX?

I'm building a 'hello world' app using NGRX, but the state of my app keeps the initial value even when I'm triggering actions that should change it.
This is my app.module:
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { StoreModule } from '#ngrx/store';
import { StoreDevtoolsModule } from '#ngrx/store-devtools';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { counterReducer } from './contador.reducer';
import { environment } from 'src/environments/environment';
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
StoreModule.forRoot({ counter: counterReducer }),
StoreDevtoolsModule.instrument({
maxAge: 25,
logOnly: environment.production,
})
],
bootstrap: [AppComponent]
})
export class AppModule { }
app.component.ts:
import { Component, OnInit } from '#angular/core';
import { Store } from '#ngrx/store';
import { decrement, increment } from './contador/contador.actions';
interface AppState {
counter: number
}
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
public counter!: number;
constructor(private store: Store<AppState>) {
this.store.subscribe(state => {
console.log('state', state)
this.counter = state.counter;
})
}
ngOnInit() { }
inc() {
this.store.dispatch(increment())
}
dec() {
this.store.dispatch(decrement())
}
}
app.component.html:
<div class="container-fluid text-center">
<div class="row">
<div class="col pt-5">
<h1>Counter</h1>
<h2>{{counter}}</h2>
</div>
</div>
<button (click)="inc()" class="btn btn-primary pr-5">increment</button>
<button (click)="dec()" class="btn btn-primary pr-5">decrement</button>
</div>
counter.reducer.ts:
import { decrement, increment } from './contador/contador.actions';
import { Action, createReducer, on } from "#ngrx/store";
export const initialState = 20;
const _counterReducer = createReducer(initialState,
on(increment => initialState + 1),
on(decrement => initialState - 1)
)
export function counterReducer(initialState: number | undefined, actions: Action) {
return _counterReducer(initialState, actions)
}
contador.actions.ts
import { createAction } from "#ngrx/store"
export const increment = createAction('[counter] increment')
export const decrement = createAction('[counter] decrement')
The only thing I'm seeing is that in the reducer, the increment and decrement imports are not being used in the on() methods as they are unused imports.
I always get the initialValue = 0, no matter if I click the increment or decrement buttons.
The on cases in you reducer are not defined correctly.
The first argument is the action, second argument is a function which takes the existing state, then returns a modified version of it according to the specified action.
const _counterReducer = createReducer(initialState,
on(increment, state => state + 1),
on(decrement, state => state - 1)
);

Routing edit/id in asp.net core application with angular not working

I am learning building application using angular and asp.net core using these videos on this link. Everything works fine except the edit of a component. If I give a URL like below, it goes to the route for error in app-routing.module.ts even though there's no error in the browser console log.
http://localhost:4200/genres/edit/1
The app-routing.model.ts is as below
import { Component, NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { CreateActorComponent } from './actors/create-actor/create-actor.component';
import { EditActorComponent } from './actors/edit-actor/edit-actor.component';
import { IndexActorsComponent } from './actors/index-actors/index-actors.component';
import { CreateGenreComponent } from './genres/create-genre/create-genre.component';
import { EditGenreComponent } from './genres/edit-genre/edit-genre.component';
import { IndexGenresComponent } from './genres/index-genres/index-genres.component';
import { HomeComponent } from './home/home.component';
import { CreateMovieTheaterComponent } from './movie-theaters/create-movie-theater/create-movie-theater.component';
import { EditMovieTheaterComponent } from './movie-theaters/edit-movie-theater/edit-movie-theater.component';
import { IndexMovieTheaterComponent } from './movie-theaters/index-movie-theater/index-movie-theater.component';
import { CreateMovieComponent } from './movies/create-movie/create-movie.component';
import { EditMovieComponent } from './movies/edit-movie/edit-movie.component';
const routes: Routes = [
{path:' ', component:HomeComponent},
{path:'genres', component:IndexGenresComponent},
{path:'genres/create', component:CreateGenreComponent},
{path:'genres/edit:id', component:EditGenreComponent},
{path:'actors', component:IndexActorsComponent},
{path:'actors/create', component:CreateActorComponent},
{path:'actors/edit:id', component:EditActorComponent},
{path:'movietheaters', component:IndexMovieTheaterComponent},
{path:'movietheaters/create', component:CreateMovieTheaterComponent},
{path:'movietheaters/edit:id', component:EditMovieTheaterComponent},
{path:'movies/create', component:CreateMovieComponent},
{path:'movies/edit:id', component:EditMovieComponent},
// {path:'**',component:HomeComponent}
{path:'**',redirectTo:' '}
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
edit-genre.component.ts is
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { genreCreationDTO } from '../genres.model';
#Component({
selector: 'app-edit-genre',
templateUrl: './edit-genre.component.html',
styleUrls: ['./edit-genre.component.css']
})
export class EditGenreComponent implements OnInit {
constructor(private activatedRoute:ActivatedRoute) { }
model: genreCreationDTO={name:"Drama"};
ngOnInit(): void {
this.activatedRoute.params.subscribe(params=>{
});
}
//Event emiited value passed from child form-genre-creation to parent create-genre.component
//to be displayed
saveChanges(genreCreationDTO:genreCreationDTO)
{
}
}
edit-genre.component.html is
<h2>Edit Genre</h2>
<app-form-genre [model]="model" (onSaveChanges)="saveChanges($event)"></app-form-genre>
form-genre.component.html is
<form (submit)="saveChanges()" [formGroup]="form">
<mat-form-field appearance="outline">
<mat-label>Name*</mat-label>
<input matInput formControlName="name">
<mat-error *ngIf="form.invalid">{{getErrorMessageFieldName()}}</mat-error>
</mat-form-field>
<div>
<button mat-flat-button color="primary" [disabled]="form.invalid">Save Changes</button>
<a mat-stroked-button routerLink="/genres">Cancel</a>
</div>
form-genre.component.ts is
import { Component, OnInit, Output,EventEmitter, Input } from '#angular/core';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
import { Router } from '#angular/router';
import { firstLetterUppercase } from 'src/app/validators/firstLetterUppercase';
import { genreCreationDTO } from '../genres.model';
#Component({
selector: 'app-form-genre',
templateUrl: './form-genre.component.html',
styleUrls: ['./form-genre.component.css']
})
export class FormGenreComponent implements OnInit {
constructor(private router: Router, private formBuilder:FormBuilder) { }
#Input()
model!: genreCreationDTO;
//Event Emitter
#Output()
onSaveChanges: EventEmitter<genreCreationDTO>=new EventEmitter<genreCreationDTO>();
form!: FormGroup;
ngOnInit(): void {
this.form= this.formBuilder.group({
name:['',[Validators.required, Validators.minLength(3),firstLetterUppercase()]]
});
if(this.model!==undefined){
this.form.patchValue(this.model);
}
}
getErrorMessageFieldName()
{
const field= this.form.get("name");
if(field?.hasError("required"))
{
return "The name field is required";
}
if(field?.hasError("minLength")){
return "The minimum length is 3"
}
if(field?.hasError('firstLetterUppercase')){
return field.getError('firstLetterUppercase').message;
}
return '';
}
saveChanges()
{
//Emit value from child form-genre.compnent to parent create-genre.component
this.onSaveChanges.emit(this.form.value);
// this.router.navigate(['/genres']);
}
}
I am new to .net core framework & angular and i'm using forms(chapter sharing forms) in the video tutorial by Felipe galivan. Everytime I give an edit/id url for a component, it keeps using this
{path:'**',redirectTo:' '}
in the app-routing.module.ts as if say genres/edit/id has no match. I'm doing exactly as Felipe in the video, mine keeps redirecting me to home page instead of genres/edit. Why is this happening?

Having issues trying to get downloadURL for multiple images from firebase storage using angular fire2

I have created a collection that holds the news title, news img, news desc, etc.. I also created the upload method that works fine , uploads the file to storage and saves the path to the collection.
Issues when trying to retrieve the image using getDownloadUrl();
Here are the files
news.component.html
<div class="container-fluid">
<div *ngFor="let item of thenews | async">
<p>
{{ item.newsTitle }} {{ item.newsDesc }}
</p>
<div class="col-md-4">
<img [src]="getImgUrl(item.newsImg)" class="img-responsive">
</div>
</div>
</div>
<div class="container-fluid">
<button mat-raised-button (click)="onLogout()">Logout</button>
</div>
News.component.ts
import { tap } from 'rxjs/operators';
import { AngularFireStorage } from 'angularfire2/storage';
import { AngularFirestoreCollection, AngularFirestoreDocument, AngularFirestore } from 'angularfire2/firestore';
import { Component, OnInit, Injectable } from '#angular/core';
import { AuthService } from './../auth.service';
import { DataService } from '../services/data.service';
import { News } from './../models/newsModel';
import { Observable } from 'rxjs';
#Component({
selector: 'app-news',
templateUrl: './news.component.html',
styleUrls: ['./news.component.css']
})
#Injectable()
export class NewsComponent implements OnInit {
news = {} as News;
newsCol: AngularFirestoreCollection<News>;
thenews: Observable<News[]>;
imgUrl: Observable<any>;
theData: News[] = [];
constructor(public authservice: AuthService, public dataservice: DataService, public afs: AngularFirestore,
private storage: AngularFireStorage) { }
ngOnInit() {
this.newsCol = this.afs.collection<News>('news');
this.thenews = this.newsCol.valueChanges();
}
getImgUrl(img) {
return this.storage.ref(img).getDownloadURL();
}
addNews(news) {
this.dataservice.addNews(news);
}
onLogout() {
this.authservice.onLogout();
}
}
When this is served it runs into an infinite loop. and the site goes hung.
Any help?
getDownloadURL() is a observable method (async function), so you have to wait for the observable to return the value i.e. the url or null if the image is not available
for example
imageUrl: Observable<string | null>;
const ref = this.storage.ref('users/davideast.jpg');
this.imageUrl= ref.getDownloadURL();
in template
<img [src]="profileUrl | async" />
Please refer this link from github
Hope this helps

Dynamically load CSS from a String to your Component using Angular 2+

i want to load my html-code and css-code code dynamically. Loading the html code is working fine, but i have no idea how inject the CSS dynamically.
Therefore i wrote following Component :
import { Component, Input } from '#angular/core';
import { Injectable, Inject } from '#angular/core';
import { Http, URLSearchParams } from '#angular/http';
import { APP_BASE_HREF } from '#angular/common';
import { ORIGIN_URL } from '../../shared/constants/baseurl.constants';
import { HttpClient } from '#angular/common/http';
import { DynamicComponentData } from './dynamic-component.data';
import { Observable } from 'rxjs/Observable';
import { TransferHttp } from '../../../modules/transfer-http/transfer-http';
import { DomSanitizer } from '#angular/platform-browser';
#Component({
template: `
<div [innerHTML]="html"> </div>
`
})
export class DynamicHTMLComponent implements DynamicComponentData {
html: any;
css: any;
constructor(
#Inject(DOCUMENT) private document,
private http: HttpClient,
private _sanitizer: DomSanitizer,
private transferHttp: TransferHttp,
#Inject(ORIGIN_URL) private baseUrl: string) {
this.getHTML();
this.getCSS();
}
#Input() data: any;
getHTML() {
this.http.get(`${this.baseUrl}/HTML.txt`, { responseType: 'text' })
.subscribe(data => this.html = this._sanitizer.bypassSecurityTrustHtml(data));
}
getCSS() {
this.http.get(`${this.baseUrl}/CSS.txt`, { responseType: 'text' })
.subscribe(data => this.css = this._sanitizer.bypassSecurityTrustHtml(data));
}}
The content of HTML.txt is
<input id="name" name="name">
The content of my CSS.txt is
input {background:red}
You can have the file path and inject into the DOM anytime
document.getElementByTagName('link').href="..............."
The path of the file shall be returned from the server

Angular2 communication between 2 components

i am using Angular2 rc5 and i try to build a component communication through a service.
For arrays it works like expected but if i change a string its not updating.
My main component looks like:
import {Component} from '#angular/core';
import {ShareServiceService} from "../share-service.service";
import {ChildTwoComponent} from "../child-two/child-two.component";
import {ChildOneComponent} from "../child-one/child-one.component";
#Component({
selector: 'parent',
template: `
<h1>Parent</h1>
<div>
<child-one></child-one>
<child-two></child-two>
</div>
`,
providers: [ShareServiceService],
directives: [ChildOneComponent, ChildTwoComponent]
})
export class ParentComponent {
constructor() {}
}
My first children component:
import {Component} from '#angular/core';
import {ShareServiceService} from "../share-service.service";
#Component({
selector: 'child-one',
template: `
<div style="float:right; width: 45%">
<pre>title: {{title}}</pre>
<pre>title: {{_sharedService.testTitle}}</pre>
<div>
<ul *ngFor="let dataElement of data">
<li>{{dataElement}}</li>
</ul>
</div>
</div>
`
})
export class ChildOneComponent{
data:string[] = [];
title:string;
constructor(public _sharedService:ShareServiceService) {
this.data = this._sharedService.dataArray;
this.title = this._sharedService.testTitle;
}
}
The second children component:
import {Component} from '#angular/core';
import {ShareServiceService} from "../share-service.service";
#Component({
selector: 'child-two',
template: `
<div style="float:left; width: 45%">
<pre>title: {{title}}</pre>
<pre>titleObj: {{titleObj.title}}</pre>
<div>
<ul *ngFor="let dataElement of data">
<li>{{dataElement}}</li>
</ul>
</div>
<input type="text" [(ngModel)]="dataInput"/>
<button (click)="addData()">addData</button>
<button (click)="updateTitle()">updateTitle</button>
</div>
`
})
export class ChildTwoComponent {
dataInput:string = 'Testing data';
data:string[] = [];
title:string;
constructor(public _sharedService:ShareServiceService) {
this.data = this._sharedService.dataArray;
this.title = this._sharedService.testTitle;
}
addData() {
this._sharedService.insertData(this.dataInput);
this.dataInput = '';
}
updateTitle() {
this._sharedService.updateTestTitle(this.dataInput);
this.dataInput = '';
}
}
My service:
import {Injectable} from '#angular/core';
#Injectable()
export class ShareServiceService {
dataArray:string[] = [];
testTitle:string = "should be updated";
insertData(data:string) {
this.dataArray.push(data);
}
updateTestTitle(newTitle:string) {
this.testTitle = {title: newTitle};
}
}
What i try to achieve is, that if i enter something in the input field with binding for "" and press the "updateTitle" that the Title in both components are updated.
But thats doesnt work currently.
if i add my input value to an array, by clicking the "adddata" Button, all works like excepted and my list with data elements shows all elements.
Does someone know why i cant update a string?
Thanks in advance!
If you copy an object or array you copy a reference. Both (source and destination) point to the same object. If one side modifies the object the other side sees the modification.
If you copy a primitive value (string, number, boolean), the the destination gets a copy of the value and source and destination aren't related in any way.
// copies a reference
this.data = this._sharedService.dataArray;
// copies the value
this.title = this._sharedService.testTitle;
What you probably want is an observable that emits events when properties in the shared service are modified.
For more details see https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service

Resources