Angular filter posts using pipes - html

I'm trying to filter posts of a table in Angular using pipes, but I keep getting on the console this error: core.js:12689 Can't bind to 'ngForFilter' since it isn't a known property of 'a'.
I think the error is on filter: filterPost, but dont know how to fix it. Any clue?
My html code is the following.
<div class="form-group">
<label for="exampleFormControlInput1">Busca un reporte</label>
<input type="text" class="form-control" id="exampleFormControlInput1" name="filterPost" placeholder="Busca.." [(ngModel)]="filterPost">
</div>
<a *ngFor="let report of All_reports | paginate: { itemsPerPage: 10, currentPage: actualPage }; let i = index;
filter: filterPost" class="list-group-item list-group-item-action flex-column align-items-start" [routerLink]="['/reporte-admin']"
routerLinkActive="router-link-active" (click)="onSubmit(report._id)">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">Reporte #: {{report._id}}</h5>
<small>{{i+1}}</small>
</div>
<p class="mb-1">Comentario: {{report.comentario}}</p>
<small class="text-muted">Nombre: {{report.nombre}} {{report.apellido}}</small>
</a>
<br>
This is my filter.pipe.ts code:
#Pipe({
name: 'filter'
})
export class FilterPipe implements PipeTransform {
transform(value: any, arg: any): any {
const resultPosts = [];
for(const report of value){
if(report._id.indexOf(arg) > -1){
resultPosts.push(report);
};
};
return resultPosts;
}
}

Pipe operator "|" expects some value to the left of it.
In your case, you added the pipe operator at the end after let i=index;
I believe you should do something like this
*ngFor="let report of All_reports | paginate: { itemsPerPage: 10, currentPage: actualPage } | filter: filterPost; let i = index;"
and also dont forget to add in declarations in app module

Related

How to pass value from one component to another? (Angular)

I just recently started learning Angular and I have a question. I want to implement a search method to search for a product on my site, I made search.pipe.ts, which works, but the input for input is in the header.component.ts component, and the products array is in the car-list.component.ts component.
car-list.component.html
<div *ngFor="let car of cars | paginate: { itemsPerPage: pageNumber, currentPage: currentPg} | **search:searchStr**" class="col-md-3">
<div class="product box">
<img src="{{'data:image/jpg;base64,' + car.image }}" alt="">
<h3>{{ car.name }}</h3>
<div class="price">{{ car.price | currency:'USD' }}</div>
<button class="btn btn-primary btn-sm">Add to cart</button> <!--(click)="addToCart(tempProduct)"-->
</div>
<br>
</div>
header.component.html
<form class="d-flex me-5">
<input type="text" class="form-control me-2" placeholder="Search cars...">
</form>
header.component.ts
export class HeaderComponent implements OnInit {
searchStr: string = '';
constructor() {
}
ngOnInit(): void {
}
}
search.pipe.ts
#Pipe({
name: 'search'
})
export class SearchPipe implements PipeTransform {
transform(cars: any[], value: any) {
return cars.filter(car => {
return car.name.includes(value);
})
}
}
I want the input values ​​from the header component to be passed to the car-list component so that I can find the product I need.
In this case you can use a shared service where you can pass data from your header component and load that data in your products component.
For further reference - Angular 4 pass data between 2 not related components
use #Input and #Output decorators to communicate between components

Encountering 'TypeError: Cannot read properties of undefined (reading 'memes')' upon attempting to upload a file using ng-upload in Angular

I am struggling with this for a while now. I am trying to upload an image using ng-upload in angular, the file is saved in the database, however I am receiving 'Cannot read properties of undefined' when the upload queue is over. Code used for receiving the file:
Upload.html
<div class="container text-center" *ngIf="memeUploadMode">
<div class="row mt-3">
<div class="col-md-3">
<h3>Dodaj mema</h3>
<div ng2FileDrop
[ngClass]="{'nv-file-over': hasBaseDropzoneOver}"
(fileOver)="fileOverBase($event)"
[uploader]="uploader"
class="card bg-faded p-3 text-center mb-3 my-drop-zone">
<i class="fa fa-upload fa-3x"></i>
Przeciągnij mema tutaj
</div>
<input type="file" ng2FileSelect [uploader]="uploader" />
</div>
<div class="col-md-9" style="margin-bottom: 40px" *ngIf="uploader?.queue?.length">
<h3>Kolejka</h3>
<p>Długość kolejki: {{ uploader?.queue?.length }}</p>
<table class="table">
<thead>
<tr>
<th width="50%">Nazwa</th>
<th>Rozmiar</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of uploader.queue">
<td><strong>{{ item?.file?.name }}</strong></td>
<td *ngIf="uploader.options.isHTML5" nowrap>{{ item?.file?.size/1024/1024 | number:'.2' }} MB</td>
</tr>
</tbody>
</table>
<div>
<div>
Queue progress:
<div class="progress">
<div class="progress-bar" role="progressbar" [ngStyle]="{ 'width': uploader.progress + '%' }"></div>
</div>
</div>
<button type="button" class="btn btn-success btn-s"
(click)="uploader.uploadAll()" [disabled]="!uploader.getNotUploadedItems().length">
<span class="fa fa-upload"></span> Upload all
</button>
</div>
</div>
</div>
And here's the code where I'm trying to add the image to the member object:
Upload.ts
constructor(public accountService: AccountService, private memberService: MembersService,
private router: Router, private toastr: ToastrService) {
this.accountService.currentUser$.pipe(take(1)).subscribe(user => this.user = user);
}
ngOnInit(): void {
this.initializeUploader();
}
fileOverBase(e: any) {
this.hasBaseDropzoneOver = e;
}
deletePhoto(photoId: number) {
this.memberService.deletePhoto(photoId).subscribe(() => {
this.member.photos = this.member.photos.filter(x => x.id !== photoId);
})
}
initializeUploader() {
this.uploader = new FileUploader({
url: this.baseUrl + 'users/add-meme',
authToken: 'Bearer ' + this.user.token,
isHTML5: true,
allowedFileType: ['image'],
removeAfterUpload: true,
autoUpload: false,
maxFileSize: 10 * 1024 * 1024
});
this.uploader.onAfterAddingFile = (file) => {
file.withCredentials = false;
}
this.uploader.onSuccessItem = (item, response, status, headers) => {
if (response) {
const meme: Meme = JSON.parse(response);
this.member.memes.push(meme);
this.user.memeUrl = meme.url;
this.member.memeUrl = meme.url;
this.accountService.setCurrentUser(this.user);
}
}
}
memeToggle() {
this.memeUploadMode = !this.memeUploadMode;
}
The error occurs at this line:
this.member.memes.push(meme);
I've already looked at similar questions, however none of the answers helped me. I must add that I already have a similar feature for adding user's photos, which is set up identically and it works. Any help would be much appreaciated.
Cheers,
Filip
You should define member in your component
member = {
memes: [],
memeUrl: ''
};
Ah, right. I see. I had those in my Upload.ts file when the error occured:
#Input() member: Member;
members: Member[];
memes: Meme[] = [];
model: any = {}
uploader: FileUploader;
After defining the member as you suggested, the compiler asked me to define every other attribute as well. Now it works, you are my savior, my good Sir :)

How to categories items according to some specification in angular using ngFor

I am trying to list doctors with some specialization. But the code below is creating several title with item of same specialization.
Below is my html code:
<div class="row">
<div class="col-md-9" *ngFor="let doctor of doctors; let i = index">
<h3 class="header-subtitle">{{doctor.doctorSpeciality}}</h3>
<div class="doctor">
<div class="doctor-description">
<h4 class="name-title">Dr. {{ doctor.doctorName}}</h4>
</div>
</div>
<hr>
</div>
</div>
The output I am getting is like:
General Physician
doctor name1
Cardiologist
doctor name2
General Physician
doctor name3
Here, the doctor name3 of category general physician should be under heading of first header title.
This is not something that you can achieve only in html (without some directives/pipes at least).
I don't know exactly how you .ts code looks like, but the grouping you're seeking for needs to be made on the actual collection that you're using inside *ngFor. Most likely doctors is a flat array of objects, something like below, on which you can use reduce and map for computing the groups.
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
readonly doctors = [
{
doctorSpeciality: 'General Physician',
doctorName: 'doctor name 1'
},
{
doctorSpeciality: 'Cardiologist',
doctorName: 'doctor name 2'
},
{
doctorSpeciality: 'General Physician',
doctorName: 'doctor name 3'
}
];
specialityGroupedDoctors = {};
constructor() {
this.computeGroups();
}
private computeGroups(): any {
this.specialityGroupedDoctors = this.doctors.reduce(
(acc: any, doc: any) => {
if (!acc[doc.doctorSpeciality]) {
acc[doc.doctorSpeciality] = [];
}
acc[doc.doctorSpeciality].push(doc);
return acc;
}, {});
}
}
And then the html template needs to change to this:
<div class="row">
<div class="col-md-9" *ngFor="let group of specialityGroupedDoctors | keyvalue">
<h3 class="header-subtitle">{{group.key}}</h3>
<div class="doctor" *ngFor="let doctor of group.value">
<div class="doctor-description">
<h4 class="name-title">Dr. {{ doctor.doctorName}}</h4>
</div>
</div>
<hr>
</div>
</div>
Here you have a StackBlitz sandbox where you can see it working: https://stackblitz.com/edit/angular-ivy-t86wnc?file=src/app/app.component.html

Select control doesn't show when published in Azure

I have got a weird situcation here. I have a select control on a web page with angular. It shows correctly in local environment.
However, when I published it to Azure, The select control does not show correctly.
This is local showing.
This is on Azure site showing.
This is inspect of select control on local site. Which looks good.
This is inspect of select control on Azure site. As it can be seen that, the select control is empty.
Here is the html for select control, I create a component for customize showing.
<div class="dynamic-field row" [formGroup]="group">
<label class="col-form-label" [ngClass]="'col-'+config.labelSize" *ngIf="config.labelSize!==0">{{ config.label }}</label>
<div [ngClass]="'col-'+ (12 - (config.labelSize||0))">
<div class="input-group input-group-sm">
<div class="input-group-prepend" *ngIf="config.prepend">
<span class="input-group-text" *ngIf="!config.prependConfig" [innerHTML]="config.prepend"></span>
<span class="input-group-text cursor-pointer" *ngIf="config.prependConfig" cspsDynamicFormModalLink [innerHTML]="config.prepend"
[config]="config.prependConfig"></span>
</div>
<select [formControlName]="config.name" class="form-control">
<option [ngValue]="undefined" *ngIf="config.placeholder">{{ config.placeholder }}</option>
<option [ngValue]="option.key" *ngFor="let option of options">
{{ option.value }}
</option>
</select>
<div class="input-group-append" *ngIf="config.append">
<span class="input-group-text" *ngIf="!config.appendConfig" [innerHTML]="config.append"></span>
<span class="input-group-text cursor-pointer" *ngIf="config.appendConfig" cspsDynamicFormModalLink [innerHTML]="config.append"
[config]="config.appendConfig"></span>
</div>
</div>
</div>
</div>
Here is the ts file:
#Component({
selector: 'form-select',
templateUrl: 'form-select.component.html',
styleUrls: ['form-select.component.css']
})
export class FormSelectComponent implements Field, OnInit {
config: FieldConfig;
group: FormGroup;
options: { key: any, value: string }[];
ngOnInit() {
const sorter = {
asc: (a: { value: string }, b: { value: string }) => { return a.value === b.value ? 0 : (a.value > b.value ? 1 : -1) },
desc: (a: { value: string }, b: { value: string }) => { return a.value === b.value ? 0 : (a.value < b.value ? 1 : -1) },
none: undefined
}
this.config.sortOptions = this.config.sortOptions || 'none';
if (this.config.options)
this.options = this.config.options.sort(sorter[this.config.sortOptions]);
else
this.options = [];
}
}
Could anyone give me some suggestions? Or tell me what's going on?
Thanks

Access nested json object angular 6

I'm trying to access the nested data from the HTML template, but I get undefined or I get nothing as result (empty page with no class list or student list).
The HTML template:
<div class="container">
<label *ngFor="let class of listClass | keyvalue">
<span> {{class.value.name}} </span>
</label>
<div>
<label *ngFor="let student of class.students | keyvalue">
<span>{{student.value.fullName}} </span>
</label>
</div>
</div>
This is the fonction that gets the list of class and the students in it:
getListClasseStudent(){
this.classService.getStudents().subscribe((data) => {
this.listClass = data;
});
}
The nested data:
class:
0:{
code: "Math01"
teacher:
0: {id: 17551, name "Jack"}
students:
0: {studentId: 1, fullName: "Patrick bob"}
1: {studentId: 2, fullName: "Alice Alice"}
}
1:{
code: "English01"
teacher:
0: {id: 2, name "Nicolas"}
students:
0: {studentId: 1, fullName: "Patrick bob"}
1: {studentId: 2, fullName: "Alice Alice"}
}
I want to access to the list of student of each class, is there any efficient way to do it? thanks in advance.
<div class="container">
<div *ngFor="let c of listClass ">
<label >
<span> {{c.code}} </span>
</label>
<div>
<label *ngFor="let student of c.students ">
<span>{{student.fullName}} </span>
</label>
</div>
</div>
Try this (example without your pipe)
A 'Class' object don't have a attribute 'value.name' (probably gonna be injected by your pipe '| keyvalue' ).
Second *ngFor need t be inside of first, because he need's to iterate a students array, inside each class.
I hope this helps.
create a pipe like below
import { Pipe, PipeTransform } from "#angular/core";
#Pipe({ name: 'ObjNgFor', pure: false })
export class ObjNgFor implements PipeTransform {
transform(value: Object): Array<string> { return Object.keys(value); }
}
import the above pipe in app.module.ts and use pipe in the html page like below
<div *ngFor="let key of questions | ObjNgFor" class="row">
{{ questions[key].name}}
<div *ngFor="let r of questions[key].sub_sections | ObjNgFor ; let indx=index"
class="card-body">
{{ questions[key].sub_sections[r].name }}"
</div>
This example should work