Angular Http Observable doesn't update - javascript

Hey Guys i wrote a little backend which returns some data. Now i want to fetch this data with Angular Http and show new values when i post them in the backend. So the first thing that came to my mind were Observables but currently i can fetch the data onInit but when Posting new Data to the Backend (currently just via Postman) the Fetched data wont update. So if this is the wrong approach tell me how to do this please. Below is my code i used so far:
App Component:
import { Component, OnInit } from '#angular/core';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
import 'rxjs/add/operator/map';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import {WeaponServiceService} from './weapon-service.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
weaponTypesarr: IweaponsTypes [] = [
{name: 'Nahkampf', value: 'melee'},
{name: 'Fernkampf', value: 'ranged'},
{name: 'Spezial', value: 'special'},
];
meleeTypesarr: IweaponsTypes [] = [
{name: 'Klingenwaffen', value: 'klinge'},
{name: 'Messer', value: 'messer'},
{name: 'Dolche', value: 'dolch'},
{name: 'Äxte/Beile', value: 'axt'},
{name: 'Speere/Stäbe', value: 'speer'},
{name: 'Stumpfe Hiebwaffen', value: 'stumpf'}
];
rangedTypesarr: IweaponsTypes [] = [
{name: 'Bogen', value: 'bogen'},
{name: 'Armbrust', value: 'armbrust'},
{name: 'Wurfwaffe', value: 'wurfwaffe'},
{name: 'kleine Schusswaffe', value: 'gun-litte'},
{name: 'große Schusswaffe', value: 'gun-big'}
];
specialTypesarr: IweaponsTypes [] = [
{name: 'Exotische Waffen', value: 'exotics'},
{name: 'Granaten und Exoplosive', value: 'grenade'}
];
rForm: FormGroup;
post: any;
weaponName = '';
weaponType= '';
impairment= '';
special= '';
results: Observable<any>;
constructor(private fb: FormBuilder , private weaponService: WeaponServiceService) {
this.rForm = fb.group({
'weaponName' : [null, Validators.required],
'weaponType': [null, Validators.required],
'impairment': [null, Validators.required],
'special': [null, Validators.required]
});
}
ngOnInit() {
this.results = this.weaponService.getWeapons();
this.results.subscribe(data => {console.log(data); });
}
generateWeapon(weaponData) {
this.weaponName = weaponData.weaponName;
this.weaponType = weaponData.weaponType;
this.impairment = weaponData.impairment;
this.special = weaponData.special;
console.log(weaponData);
}
}
export interface IweaponsTypes {
name: string;
value: string;
}
WeaponServiceService (didnt knew it calls it service by its own :D):
import { Injectable } from '#angular/core';
import {HttpClient} from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
#Injectable()
export class WeaponServiceService {
constructor( private http: HttpClient) { }
getWeapons() {
return this.http.get('http://192.168.178.48:3000/getWeapons').map(data => {
return(data);
},
err => {
console.log(err);
}
);
}
createWeapon(weaponData2: any) {
return this.http.post('http://192.168.178.48:3000/createWeapon', weaponData2)
.map(
res => {
console.log(res);
},
err => {
console.log(err);
}
);
}
}
Module:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
import {NgbModule} from '#ng-bootstrap/ng-bootstrap';
import { AppComponent } from './app.component';
import { HttpClientModule } from '#angular/common/http';
import {WeaponServiceService} from './weapon-service.service';
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
FormsModule,
HttpClientModule,
ReactiveFormsModule,
NgbModule.forRoot()
],
providers: [WeaponServiceService],
bootstrap: [AppComponent]
})
export class AppModule { }
and last but not least the corresponding HTML but currently i just try to log all the values.
<div *ngIf="!name; else forminfo">
<form [formGroup]="rForm" (ngSubmit)="generateWeapon(rForm.value)">
<h1>Generate Weapon</h1>
<label for="WeaponName">WeaponName</label>
<input class="form-control" type="text" name="weaponName" formControlName="weaponName" id="WeaponName">
<div class="form-group">
<label for="WeaponGroup">Weapon Group</label>
<select class="form-control" #weaponTypeSelektor formControlName="weaponType" id="WeaponGroup">
<option> Select a Type</option>
<option *ngFor="let types of weaponTypesarr" [value]="types.value">{{types.name}}</option>
</select>
</div>
<div class="form-group" *ngIf="weaponTypeSelektor.value == 'melee'">
<label for="WeaponTypeMelee">Weapon Type</label>
<select class="form-control" formControlName="weaponType" id="WeaponTypeMelee">
<option *ngFor="let types of meleeTypesarr" [value]="types.value">{{types.name}}</option>
</select>
</div>
<div class="form-group" *ngIf="weaponTypeSelektor.value == 'ranged'">
<label for="WeaponTypeRanged">Weapon Type</label>
<select class="form-control" formControlName="weaponType" id="WeaponTypeRanged">
<option *ngFor="let types of rangedTypesarr" [value]="types.value">{{types.name}}</option>
</select>
</div>
<div class="form-group" *ngIf="weaponTypeSelektor.value == 'special'">
<label for="WeaponTypeSpecial">Weapon Type</label>
<select class="form-control" formControlName="weaponType" id="WeaponTypeSpecial">
<option *ngFor="let types of specialTypesarr" [value]="types.value">{{types.name}}</option>
</select>
</div>
<label for="impairment">Beeinträchtigung</label>
<input class="form-control" type="text" name="Beeinträchtigung" formControlName="impairment" value="" id="impairment">
<label for="special">Spezial</label>
<input class="form-control" type="text" name="Spezial" formControlName="special" value="" id="special">
<br><br>
<input type="submit" class="btn btn-primary" value="Submit Form" [disabled]="!rForm.valid">
</form>
<div *ngFor="let item of results | async"> {{item.weaponName}} </div>
</div>
<ng-template #forminfo>
<div class="form-container">
<div class="row columns">
<h1>{{ name }}</h1>
<p>{{ weaponType }}</p>
</div>
</div>
</ng-template>
So just to be clear. AppComponent starts and fetched initial data. I post Data into the Db with postman. App Component doesn't recognize new Value.

Change these lines in the Service.
getWeapons() {
return this.http.get('http://192.168.178.48:3000/getWeapons').map(data => {
return data.json();
}
And Change these lines in the AppComponent
ngOnInit() {
this.results = this.weaponService.getWeapons();
//delete this line ---> this.results.subscribe(data => {console.log(data); });
}
since you are using the async pipe you dont need to subscribe.
Hope this helps.

Tested on:
Angular CLI: 13.1.4
Node: 17.3.0
Package Manager: npm 8.3.0
I know I don't have the best answer but one which works (at least).
Maybe it helps someone to continue further ;-)
I fetched the data once in the component's ngOnInit as well as in a function which pulls the database data after a defined interval/time has passed.
data: any;
baseUrl = 'foo_URL';
fetchInterval: 3000; // 3 Seconds
constructor(private http: HttpClient) {
}
// First Fetch
ngOnInit(): void {
this.http.get(this.baseUrl)
.pipe(takeUntil(this.destroy$))
.subscribe((fooData) => {
this.data = fooData;
})
}
// Interval Fetch
setInterval: any = setInterval(() => {
this.http.get(this.baseUrl)
.pipe(takeUntil(this.destroy$))
.subscribe((fooData) => {
// Compare for view update
if (JSON.stringify(fooData) !== JSON.stringify(this.data)) {
console.log('New stuff -> update view')
this.data = fooData;
}
});
}, fetchInterval)
// Shield Memory Leakeage after Component is deleted
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
This is generally a bad approach as ..
.. data is pulled although there is no update the data.
.. data may be pushed towards the view without any need (fixed).
.. the interval is (mostly) barely adjustable to fit the need of both sides, Client & Server.
It is recommended to at least check changes in the data before updating the view with the same data.
Maybe even offer an API which only serves a checksum before pulling the whole dataset.
Last:
The more advanced solution would be a two-way-binding.
Once an API is called which changes the data, angular gets an update for the backend. For this kind of solution you might want to take a look at socket.io ... ;-)

Related

Filtering two concatenated values

I have a list of users that I want to filter by their full_name and address. And I'm having trouble filtering their names using angular filter because their names are stored in first_name and last_name seperately.
Here's what I've done so far:
TS
userSearch = {
full_name: "",
address: "",
};
HTML
<input [(ngModel)]="userSearch.full_name" placeholder="Name" />
<input [(ngModel)]="userSearch.address" placeholder="Address" />
<tr *ngFor="let user of usersJson| filter:userSearch">
<td>{{user.first_name+' '+user.last_name}}</td>
<td>{{user.address}}</td>
</tr>
you must create your custom pipe
filter.pipe.ts
import { Pipe, PipeTransform } from "#angular/core";
#Pipe({
name: "filterUsers"
})
export class FilterPipe implements PipeTransform {
transform(users: any, full_name: string, address: string): any {
if (full_name || address) {
return users.filter(user => {
const user_full_name = `${user.first_name} ${user.last_name}`;
// This will return true if user_full_name is equal full_name
// or if user.address is equal address
// **Note** if you want them both to be true then change || to &&
return (
user_full_name.toLocaleLowerCase() ===
full_name?.toLocaleLowerCase() ||
user.address.toLocaleLowerCase() === address?.toLocaleLowerCase()
);
});
}
return users;
}
}
Import filter Pipe in your module
import { AppComponent } from './app.component';
import { HelloComponent } from './hello.component';
import { FilterPipe } from './filter.pipe';
#NgModule({
imports: [ BrowserModule, FormsModule ],
declarations: [ AppComponent, HelloComponent, FilterPipe ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
Use the pipe in your Components Html
<input [(ngModel)]="full_name" name="full_name" placeholder="Name"/>
<input [(ngModel)]="address" name="address" placeholder="Address"/>
<tr *ngFor="let user of users | filterUsers: full_name : address">
<td>{{user.first_name+' '+user.last_name}}</td>
<td>{{user.address}} </td>
</tr>
In your component ts file, you can add two variable
full_name: string;
address: string;
and also created a stackblitz link

How to set the object key value in an angular reactive form

I have an object like this.
types: {
2: {
zoom: true,
select: true
},
4: {
zoom: true,
select: true
},
}
Is it possible to create this json object from a angular form?
<div formGroupName="types">
<input type="number" matInput placeholder="Type" [(ngModel)]="searchType" i18n-placeholder>
<div [ngModelGroup]="searchType">
<mat-slide-toggle [(ngModel)]="searchType.zoom" color="primary">Zoom</mat-slide-toggle>
<mat-slide-toggle [(ngModel)]="searchType.select" color="primary">Klik</mat-slide-toggle>
</div>
</div>
Sadly it's not possible to change the json but the numbers need to be changable. The form is reactive driven but I could not find a way so I tried template driven but neither way worked out.
Using Angular reactiveForm and Factory to build your desire json object. It is possible to add property dynamically to your object. But your props name could not be some numbers as you mentioned in your example; If you want something its better to have an array of objects.
So, try something like this:
app.component.ts
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormBuilder, Validators } from '#angular/forms';
import { TypeFactory } from './type.factory.ts';
import { TypeModel } from './app-type.model';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
typesForm:FormGroup;
types: TypeModel[] = [];
constructor(
private formBuilder: FormBuilder,
private typeFactory: TypeFactory,
){}
ngOnInit(){
this.typesForm = this.formBuilder.group({
id: ['', [Validators.required]],
zoom: [''],
select: ['']
});
}
regForm = () => {
let newType = this.typeFactory.createTypeDto(this.typesForm.getRawValues());
this.types = [ ...types, ...newType];
}
}
app.component.html
<form [formGroup]="typesForm">
<input formControlName="id" type="number" matInput placeholder="Type" i18n-placeholder>
<div class="container">
<mat-slide-toggle formControlName="zoom" color="primary">Zoom</mat-slide-toggle>
<mat-slide-toggle formControlName="select" color="primary">Klik</mat-slide-toggle>
</div>
<button class="btn btn-success" (click)="regForm()">Register</button>
</form>
app-type.model.ts
export class TypeModel {
id: number;
zoom: boolean;
select: boolean;
}
app.factory.ts
import { TypeModel } from './app-type.model';
export class TypeFactory {
createTypeDto(
form: any,
): TypeModel {
const model = new TypeModel();
model.id = form.id;
model.zoom = form.zoom;
model.select = form.select;
return model;
}
}

Angular 6 Form not passing variable to URL

I am trying to create a form in angular that takes a name, passes it to a URL, and returns a portion of a .json file. I can't figure out why the url is not getting updated though.
The HTML:
<form (ngSubmit)="processForm($engineer)">
<div class="form-group">
<label for="engineerselectform">Engineer Name</label>
<select class="form-control" id="engineerselectform" name="engineer" [(ngModel)]="engineer">
<option></option>
<option>Smith</option>
<option>Jones</option>
<option>Clark</option>
</select>
</div>
<input class="btn btn-primary" type="submit" value="submit" aria-pressed="true">
</form>
The Component:
import { Component, OnInit } from '#angular/core';
import { ScheduleService } from '../schedule.service';
import { ActivatedRoute } from '#angular/router';
#Component({
selector: 'app-schedule',
templateUrl: './schedule.component.html',
styleUrls: ['./schedule.component.scss']
})
export class ScheduleComponent implements OnInit {
engineer;
constructor(
private scheduleService: ScheduleService,
private route: ActivatedRoute
) { }
ngOnInit() {}
processForm(engineer: string) {
this.route.params.subscribe(params=> { const engineer = params["engineer"];
this.scheduleService.getschedule(engineer).subscribe(engineer => this.engineer = engineer);
});
}
}
The Service:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class ScheduleService {
apiUrl ='http://127.0.0.1:5000/schedule'
engineer;
constructor(private http: HttpClient) { }
getschedule(engineer: string){
return this.http.get(`${this.apiUrl}?engineer=${this.engineer}`);
}
}
The Flask API backend:
#app.route('/schedule', methods = ['GET'])
def engineer_location_api():
if "engineer" in request.args:
print ('did this')
engineer_name = request.args["engineer"]
print ("engineer name:", engineer_name)
else:
return "not found, sorry"
answer = {}
with open(LOC1, "r") as file:
check_loc1 = json.load(file)
for item in check_loc1["LOC1"]:
if engineer_name in item["Engineer"]:
answer.update(item)
else:
continue
with open(LOC2, "r") as file:
check_loc2 = json.load(file)
for item in check_loc2:
if engineer_name in item:
answer.update(item)
else:
continue
if answer:
return answer
else:
return 'engineer not found'
app.run()
the error:
ERROR
Object { headers: {…}, status: 200, statusText: "OK", url: "http://127.0.0.1:5000/schedule?engineer=undefined", ok: false, name: "HttpErrorResponse", message: "Http failure during parsing for http://127.0.0.1:5000/schedule?engineer=undefined", error: {…} }
core.js:6014:19
As I understand it, when I hit submit the process form function should send the engineer variable to the component where it sets it as a parameter that it provides to the service which should fill out the URL. But regardless of how I play around with it, the engineer always comes back as undefined. Clearly I'm missing something core to passing the variable.
Also, I'm super new and therefore there are probably other things in this code that are ugly or not best practice, feel free to rip into it, I figure my understanding can only go up.
You don't have to subscribe to activated url if your data is coming from form. You have to remove the $event from processForm because we will add the global variable in your service function. Please have a look on below example
<form (ngSubmit)="processForm()">
<div class="form-group">
<label for="engineerselectform">Engineer Name</label>
<select class="form-control" id="engineerselectform" name="engineer" [(ngModel)]="engineer">
<option></option>
<option value="smith">Smith</option>
<option value="jones">Jones</option>
<option value="clark">Clark</option>
</select>
</div>
<input class="btn btn-primary" type="submit" value="submit" aria-pressed="true">
</form>
import { Component, OnInit } from '#angular/core';
import { ScheduleService } from '../schedule.service';
import { ActivatedRoute } from '#angular/router';
#Component({
selector: 'app-schedule',
templateUrl: './schedule.component.html',
styleUrls: ['./schedule.component.scss']
})
export class ScheduleComponent implements OnInit {
engineer;
receivedEngineers;
constructor(
private scheduleService: ScheduleService,
private route: ActivatedRoute
) { }
ngOnInit() {}
processForm() {
this.scheduleService.getschedule(this.engineer).subscribe(engineer => this.receivedEngineers = engineer);
});
}
}
getschedule(engineer: string){
return this.http.get(`${this.apiUrl}?engineer=${engineer}`);
}
The engineer is now accessed from parameter of getSchedule() function.

Price does not multiply by the input number given,

It's meant to multiply the 1 by 5, as you can see but I don't know how, I've tried stuff with ngModel but that didn't work.
This is the code in the HTML of the input and what has to be the total price:
<input type="number" style="width:40px; float:right;" />
<br>
<hr>
<p style="float: left;">Total price:</p>
<p style="float: right;"> <b>€{{activeProduct.price * inputNum}}</b>,-</p>
This is the model I made for the product:
This is the code in my TypeScript file:
import { Component, OnInit } from '#angular/core';
import { Product } from 'src/app/models/product';
#Component({
selector: 'app-tool-card',
templateUrl: './tool-card.component.html',
styleUrls: ['./tool-card.component.css']
})
export class ToolCardComponent implements OnInit {
public activeProduct: any;
public inputNum: number;
products: Product[] = [
new Product('Hammer', 'Hammer', 'Item used to hammer things', 'https://upload.wikimedia.org/wikipedia/commons/8/84/Claw-hammer.jpg', 1),
new Product('Saw', 'Hammer', 'I just saw a guy saying the n-word', 'https://media.screwfix.com/is/image//ae235?src=ae235/32045_P&$prodImageMedium$', 2),
new Product('Hit or miss', 'Hit or miss', 'I guess they never miss huh, mwah', 'https://pbs.twimg.com/media/Ds5mk0RU0AA1z_l.jpg', 5)
];
constructor() {
}
ngOnInit() {
}
public calculateTotal() {
this.activeProduct.price * this.inputNum;
}
public openModal(product): void {
// Copying object reference so we don't modify the original
this.activeProduct = Object.assign({}, product);
this.inputNum = 0;
}
}
You have not bound the input box to anything, use ngModel
<input type="number" [(ngModel)]="inputNum" style="width:40px; float:right;" />
or if you don't want to use the forms module
<input type="number" (change)="inputNum = $event.target.value" style="width:40px; float:right;" />
Make sure you add FormsModule to your imports array in your app.module.ts file
app.module.ts:
import { FormsModule } from '#angular/forms';
#NgModule({
declarations: [...],
imports: [
...
FormsModule
],
...etc
})
HTML File
<div>
<p>{{ activeProduct.price }} </p>
<label for="amount">Amount</label>
<input type="number" (change)="calculateTotal() [(ngModel)]="activeProduct.numOfItems"/>
<br>
<hr>
<p style="float: left;">Total price:</p>
<p [(ngModel)]="totalCost">{{ totalCost }}</p>
</div>
ts file
export class AppComponent {
activeProduct: any = {
price: 12,
name: 'pizza',
numOfItems: 0
};
totalCost: number = 0;
constructor() {}
calculateTotal(): number {
return this.totalCost = this.activeProduct.numOfItems * this.activeProduct.price;
}
}
not the most elegant way but it will get you there. I think the biggest gotcha is FormsModule

Angular 4 Filter Search Custom Pipe

So I am trying to build a custom pipe to do a search filter of multiple values in a ngFor loop. I have looked for a number of hours for a good working example, and most of them are based on previous builds and don't seem to work. So I was building the Pipe and using the console to give me the values. However, I cannot seem to get the input text to show up.
Here are the previous places I have looked to find working examples:
Angular 4 Pipe Filter
http://jilles.me/ng-filter-in-angular2-pipes/
https://mytechnetknowhows.wordpress.com/2017/02/18/angular-2-pipes-passing-multiple-filters-to-pipes/
https://plnkr.co/edit/vRvnNUULmBpkbLUYk4uw?p=preview
https://www.youtube.com/results?search_query=filter+search+angular+2
https://www.youtube.com/watch?v=UgMhQpkjCFg
Here is the code that I currently have:
component.html
<input type="text" class="form-control" placeholder="Search" ngModel="query" id="listSearch" #LockFilter>
<div class="panel panel-default col-xs-12 col-sm-11" *ngFor="let lock of locked | LockFilter: query">
<input type="checkbox" ngModel="lock.checked" (change)="openModal($event, lock)" class="check" id="{{lock.ID}}">
<label for="{{lock.ID}}" class="check-label"></label>
<h3 class="card-text name" ngModel="lock.name">{{lock.User}}</h3>
<h3 class="card-text auth" ngModel="lock.auth">{{lock.AuthID}}</h3>
<h3 class="card-text form" ngModel="lock.form">{{lock.FormName}}</h3>
<h3 class="card-text win" ngModel="lock.win">{{lock.WinHandle}}</h3>
</div>
pipe.ts
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'LockFilter'
})
export class LockFilterPipe implements PipeTransform {
transform(locked: any, query: string): any {
console.log(locked); //this shows in the console
console.log(query); //this does not show anything in the console when typing
if(!query) {
return locked;
}
return locked.filter((lock) => {
return lock.User.toLowerCase().match(query.toLowerCase());
});
}
}
I have imported the pipe into the module.
I am still a little newer to Angular 4 and am trying to figure out how to make this work. Anyways thanks for your help!
I guess I will need to be more specific. I already built out a filter search in JS that does not filter all of the options, which is what I am trying to do. Not just filter the User Name. I am filtering all 4 pieces of data. I chose a Pipe as this was what Angular suggests you do as they originally used them in AngularJS. I am just trying to essentially recreate the filter pipe we had in AngularJS that they removed for performance. All options I have found don't work, or are from previous builds of Angular.
If you need anything else from my code let me know.
I have to implement search functionality in my local and Here is Updated your code. please do this way.
Here is the code that I have to update.
directory Structure
app/
_pipe/
search/
search.pipe.ts
search.pipe.spec.ts
app/
app.component.css
app.component.html
app.component.ts
app.module.ts
app.component.spec.ts
command run for creating pipe
ng g pipe search
component.html
<input type="text" class="form-control" placeholder="Search" [(ngModel)]="query" id="listSearch">
<div class="panel panel-default col-xs-12 col-sm-11" *ngFor="let lock of locked | LockFilter: query">
<input type="checkbox" (change)="openModal($event, lock)" class="check" id="{{lock.ID}}">
<label [for]="lock.ID" class="check-label"></label>
<h3 class="card-text name">{{lock.User}}</h3>
<h3 class="card-text auth">{{lock.AuthID}}</h3>
<h3 class="card-text form">{{lock.FormName}}</h3>
<h3 class="card-text win">{{lock.WinHandle}}</h3>
</div>
component.js
Note: In this file, i have to use dummy records for implementation and testing purpose.
import { Component, OnInit } from '#angular/core';
import { FormsModule } from '#angular/forms';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
public search:any = '';
locked: any[] = [];
constructor(){}
ngOnInit(){
this.locked = [
{ID: 1, User: 'Agustin', AuthID: '68114', FormName: 'Fellman', WinHandle: 'Oak Way'},
{ID: 2, User: 'Alden', AuthID: '98101', FormName: 'Raccoon Run', WinHandle: 'Newsome'},
{ID: 3, User: 'Ramon', AuthID: '28586', FormName: 'Yorkshire Circle', WinHandle: 'Dennis'},
{ID: 4, User: 'Elbert', AuthID: '91775', FormName: 'Lee', WinHandle: 'Middleville Road'},
]
}
}
module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { AppComponent } from './app.component';
import { SearchPipe } from './_pipe/search/search.pipe';
#NgModule({
declarations: [
AppComponent,
SearchPipe
],
imports: [
BrowserModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
pipe.ts
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'LockFilter'
})
export class SearchPipe implements PipeTransform {
transform(value: any, args?: any): any {
if(!value)return null;
if(!args)return value;
args = args.toLowerCase();
return value.filter(function(item){
return JSON.stringify(item).toLowerCase().includes(args);
});
}
}
I hope you are getting the pipe functionality and this will help you.
Simple filterPipe for Angular 2+
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'filter'
})
export class filterPipe implements PipeTransform {
transform(items: any[], field:string, value: string): any[] {
if(!items) return [];
if(!value) return items;
return items.filter( str => {
return str[field].toLowerCase().includes(value.toLowerCase());
});
}
}
Here is the HTML
<input type="text" class="form-control" placeholder="Search" id="listSearch" #search>
<div class="panel panel-default col-xs-12 col-sm-11" *ngFor="let lock of locked | filter:'propName': search.value>
<input type="checkbox" (change)="openModal($event, lock)" class="check" id="{{lock.ID}}">
<label [for]="lock.ID" class="check-label"></label>
<h3 class="card-text name">{{lock.User}}</h3>
<h3 class="card-text auth">{{lock.AuthID}}</h3>
<h3 class="card-text form">{{lock.FormName}}</h3>
<h3 class="card-text win">{{lock.WinHandle}}</h3>
</div>
in HTML PropName is dummy text. In place of PropName use your any object property key.
Follow this code to filter specific column instead of all columns in table using custom filters
filename.component.html
<table class="table table-striped">
<thead>
<tr>
<th scope="col">product name </th>
<th scope="col">product price</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let respObj of data | filter:searchText">
<td>{{respObj.product_name}}</td>
<td>{{respObj.product_price}}</td>
</tr>
</tbody>
</table>
filename.component.ts
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'app-productlist',
templateUrl: './productlist.component.html',
styleUrls: ['./productlist.component.css']
})
export class ProductlistComponent implements OnInit {
searchText: string;
constructor(private http: HttpClient) { }
data: any;
ngOnInit() {
this.http.get(url)
.subscribe(
resp => {
this.data = resp;
}
)
}
}
filename.pipe.ts
Create a class and implement it with PipeTransform, in that way we can write custom filter with transform method.
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'filter'
})
export class PipeList implements PipeTransform {
transform(value: any, args?: any): any {
if(!args)
return value;
return value.filter(
item => item.product_name.toLowerCase().indexOf(args.toLowerCase()) > -1
);
}
}
Here is simple explanation to create custom pipe..as available pipes does not support it.
I found this solution here..Nicely explained it
Create pipe file advanced-filter.pipe
import {Pipe, PipeTransform} from '#angular/core';
#Pipe({
name: 'advancedFilters'
})
export class AdvancedFilterPipe implements PipeTransform {
transform(array: any[], ...args): any {
if (array == null) {
return null;
}
return array.filter(function(obj) {
if (args[1]) {
return obj.status === args[0];
}
return array;
});
}
}
Here, array – will be data array passed to your custom pipe
obj – will be the object of data by using that object you can add condition to filter data
We have added condition obj.status === args[0] so that data will get filter on status which is passed in .html file
Now, import and declare custom pipe in module.ts file of component:
import {AdvancedFilterPipe} from './basic-filter.pipe';
//Declare pipe
#NgModule({
imports: [DataTableModule, HttpModule, CommonModule, FormsModule, ChartModule, RouterModule],
declarations: [ DashboardComponent, AdvancedFilterPipe],
exports: [ DashboardComponent ],
providers: [{provide: HighchartsStatic}]
})
Use of created custom angular pipe in .html file
<table class="table table-bordered" [mfData]="data | advancedFilters: status" #mf="mfDataTable" [mfRowsOnPage]="rowsOnPage" [(mfSortBy)]="sortBy" [(mfSortOrder)]="sortOrder">
<thead>
<tr>
<th class="sortable-column" width="12%">
<mfDefaultSorter by="inquiry_originator">Origin</mfDefaultSorter>
</th>
</tr>
</thead>
<tbody class="dashboard-grid">
<ng-container *ngFor="let item of mf.data; let counter = index;">
<tr class="data-row {{ item.status }} grid-panel-class-{{ counter }}">
<td class="align-center">{{ item.trn_date }}</td>
<td>{{ item.trn_ref }}</td>
</tr>
</tbody>
</table>
//If you are using *ngFor and want to use custom angular pipe then below is code
<li *ngFor="let num of (numbers | advancedFilters: status">
{{ num | ordinal }}
</li>
A simple Java-like logic that I could think of which might not look very compact in terms of typescript, is as below:
transform(value:IBook[], keyword:string) {
if(!keyword)
return value;
let filteredValues:any=[];
for(let i=0;i<value.length;i++){
if(value[i].name.toLowerCase().includes(keyword.toLowerCase())){
filteredValues.push(value[i]);
}
}
return filteredValues;
}
<h2>Available Books</h2>
<input type="text" [(ngModel)]="bookName"/>
<ul class="books">
<li *ngFor="let book of books | search:bookName"
[class.selected]="book === selectedBook"
(click)="onSelect(book)">
<span class="badge">{{book.name}}</span>
</li>
</ul>
You can use the given function instead on the (input) event of your input box
filterNames(event)
{
this.names_list = this.names_list.filter(function(tag) {
return tag.name.toLowerCase().indexOf(event.target.value.toLowerCase()) >= 0;
});
}
Hope it helps..

Categories