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..
Related
I am developing a Angular website with help of Firebase Firestore. It is my first project on Angular. I have learned Angular 2months ago. Please See the below codes: -
Component.html
<section class="rank">
<p class="records" *ngIf="members.length === 0">No Records Found.</p>
<div class="text-img" *ngIf="members.length > 0">
<p class="sb">Best Sulphuric</p>
<p class="role">Member</p>
<p class="name">
{{ members[0].payload.doc.data().name }}
</p>
</div>
<table *ngIf="members.length > 0">
<tr>
<th>ID</th>
<th>Name</th>
<th>Posts</th>
<th>Score</th>
</tr>
<tr *ngFor="let member of members; let indexOfelement = index">
<td>{{ indexOfelement + 1 }}</td>
<td>{{ member.payload.doc.data().name }}</td>
<td>{{ member.payload.doc.data().posts }}</td>
<td>{{ member.payload.doc.data().score }}</td>
</tr>
</table>
</section>
Component.ts
import { Component, OnInit } from '#angular/core';
import { AngularFirestore } from '#angular/fire/firestore';
#Component({
selector: 'app-rank',
templateUrl: './rank.component.html',
styleUrls: ['./rank.component.scss'],
})
export class RankComponent implements OnInit {
members: any;
constructor(public db: AngularFirestore) {
db.collection('members')
.snapshotChanges()
.subscribe((res) => (this.members = res));
}
ngOnInit(): void {}
}
When I open this on browser this shows all the data in members in Firestore. But when i change component.ts to this -->
Component.ts
import { Component, OnInit } from '#angular/core';
import { AngularFirestore } from '#angular/fire/firestore';
#Component({
selector: 'app-rank',
templateUrl: './rank.component.html',
styleUrls: ['./rank.component.scss'],
})
export class RankComponent implements OnInit {
members: any;
constructor(public db: AngularFirestore) {
this.members = db.collection('members').ref.orderBy('score');
}
ngOnInit(): void {}
}
It shows no data on window. Can you help me please?
Thanks in Advance for Helping.
In the second version,
You are missing the
.snapshotChanges()
.subscribe((res) => (this.members = res));
}
inside the constructor. Without the subscribe, Angular will not make any HTTP Requests and your component will not receive any data.
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
I'm beginner to Angular 2.
I was trying to create the custom pipe for search operation in angular 2.
While trying to filter the objects of data by using the filter function I was getting as like my data is not supporting the filter function.
My Pipe code :
import {Pipe,PipeTransform} from '#angular/core'
#Pipe({
name : 'GenderSetter'
})
export class SettingGenderPipe implements PipeTransform
{
transform(Employees:any,EmpFind:any):any{
if(EmpFind === undefined) return Employees;
else {
return Employees.filter(function(x){
console.log(x.toLowerCase().includes(EmpFind.toLowerCase()));
return x.toLowerCase().includes(EmpFind.toLowerCase())
})
}
}
}
My template html file :
<div style="text-align:center">
<input type="text" id='txtsearch' [(ngModel)]="EmpFind"/>
<table>
<thead>
<td>Name</td>
<td>Gender</td>
<td>Salary</td>
</thead>
<tbody>
<tr *ngFor='let x of Employees'>
<td>{{x.Empname | GenderSetter : EmpFind}}</td>
<td>{{x.gender}}</td>
<td>{{x.salary}}</td>
</tr>
</tbody>
</table>
</div>
My Component Code :
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
Employees=[
{Empname : 'Roshan',gender:1,salary:'70k' },
{Empname : 'Ishita',gender:0,salary:'60k' },
{Empname : 'Ritika',gender:0,salary:'50k' },
{Empname : 'Girish',gender:1,salary:'40k' },
]
}
In the console I'm getting the error as :
ERROR TypeError: Employees.filter is not a function.
The problem is that you are applying the pipe to the x.Empname, however the pipe itself should accept an array. Move your pipe to the ngFor:
<tr *ngFor='let x of Employees | GenderSetter : EmpFind'>
<td>{{x.Empname}}</td>
<td>{{x.gender}}</td>
<td>{{x.salary}}</td>
</tr>
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 ... ;-)
I am actually trying to inject the array and the data inside the array to another component but is constantly getting errors.
My list.component.ts
Here i injected the itemList array from app.component and this component is working just fine. No errors here.
import { Component, OnInit, Input, Output, EventEmitter } from '#angular/core';
import {List} from './list.model'
#Component({
selector: 'app-list',
templateUrl: './list.component.html',
styleUrls: ['./list.component.css']
})
export class ListComponent implements OnInit {
#Input() itemList: List[] = [];
#Output() onItemSelected: EventEmitter<List>;
private currentItem: List;
constructor(){
this.onItemSelected = new EventEmitter();
}
onClick(list: List): void {
this.currentItem = list;
this.onItemSelected.emit(list);
console.log(`clicking list title: ${list.title}`);
}
isSelected(list: List): boolean {
if (!list || !this.currentItem) {
return false;
}
return list.title === this.currentItem.title;
}
ngOnInit() {
}
}
list.component.html
Here i try to inject both the array and then using ngFor i try to inject the single list also.
<div class="ui grid posts">
<app-list-row
[lists]="itemList"
*ngFor="let list of itemList"
[list]="list"
(click)='onClick(list)'
[class.selected]="isSelected(list)">
</app-list-row>
</div>
list-row.component.ts
I am mainly trying to input the array in this component so that i can use the splice method to delete my list. I tried the delete list;method but this says i cannot use delete in strict mode. Therefore i am trying to input the array and use the splice method.
import { Component, OnInit, Input} from '#angular/core';
import {List} from '.././list/list.model';
#Component({
selector: 'app-list-row',
inputs: ['list: List'],
templateUrl: './list-row.component.html',
styleUrls: ['./list-row.component.css'],
host: {'class': 'row'},
})
export class ListRowComponent implements OnInit {
list: List;
#Input() lists: List[];
deletelist(list: List): void {
let index: number = this.lists.indexOf(list);
if (index !== -1) {
this.lists.splice(index, 1);
}
}
ngOnInit() {
}
}
list-row.component.html
In this write a div and use a lable of delete icon and give an event of click with the "deleteList(list)".
<div class="Eight wide column left aligned title">
<div class="value">
<div class = "hello">
<b>
{{ list.title | uppercase }}
</b>
<div style="float: right;" class="ui label">
<i class="delete icon"
(click)="deleteList(list)"
></i>
</div>
</div>
</div>
</div>
These are my codes and i dont know whether i can do the dependency injection of both the array and its single data in the array. If i can, what ways are there to do it. while running in server the console error is
Unhandled Promise rejection: Template parse errors:
Can't bind to 'list' since it isn't a known property of 'app-list-row'.
1. If 'app-list-row' is an Angular component and it has 'list' input, then verify that it is part of this module.
2. If 'app-list-row' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '#NgModule.schemas' of this component to suppress this message.
("
[lists]="itemList"
*ngFor="let list of itemList"
[ERROR ->][list]="list"
(click)='onClick(list)'
[class.selected]="isSelected(list)">
"): ListComponent#4:2 ; Zone: <root> ; Task: Promise.then ; Value: SyntaxError {__zone_symbol__error: Error: Template parse errors:
Can't bind to 'list' since it isn't a known property of 'app-list-row'…, _nativeError: ZoneAwareError, __zone_symbol__currentTask: ZoneTask, __zone_symbol__stack: "Error: Template parse errors:↵Can't bind to 'list'…ttp://localhost:4200/polyfills.bundle.js:6060:47)", __zone_symbol__message: "Template parse errors:↵Can't bind to 'list' since …lected]="isSelected(list)">↵"): ListComponent#4:2"} Error: Template parse errors:
Can't bind to 'list' since it isn't a known property of 'app-list-row'.
1. If 'app-list-row' is an Angular component and it has 'list' input, then verify that it is part of this module.
2. If 'app-list-row' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '#NgModule.schemas' of this component to suppress this message.
("
[lists]="itemList"
*ngFor="let list of itemList"
[ERROR ->][list]="list"
(click)='onClick(list)'
[class.selected]="isSelected(list)">
Thank you.
Add #Input() to list variable in ListRowComponent class and check if it is working or not and remove inputs from metadata.
import { Component, OnInit, Input} from '#angular/core';
import {List} from '.././list/list.model';
#Component({
selector: 'app-list-row',
templateUrl: './list-row.component.html',
styleUrls: ['./list-row.component.css'],
host: {'class': 'row'},
})
export class ListRowComponent implements OnInit {
#Input() list: List;
#Input() lists: List[];
deletelist(list: List): void {
let index: number = this.lists.indexOf(list);
if (index !== -1) {
this.lists.splice(index, 1);
}
}
ngOnInit() {
}
}
or
Remove :List from inputs as
import { Component, OnInit, Input} from '#angular/core';
import {List} from '.././list/list.model';
#Component({
selector: 'app-list-row',
templateUrl: './list-row.component.html',
inputs :['list']
styleUrls: ['./list-row.component.css'],
host: {'class': 'row'},
})
export class ListRowComponent implements OnInit {
list: List;
#Input() lists: List[];
deletelist(list: List): void {
let index: number = this.lists.indexOf(list);
if (index !== -1) {
this.lists.splice(index, 1);
}
}
ngOnInit() {
}
}
I got the answer. I did not do two input bindings but i created a custom event in the list-row.component and emmited the list to list.Component.
import { Component, Input, Output, EventEmitter} from '#angular/core';
import {List} from '.././list/list.model';
#Component({
selector: 'app-list-row',
templateUrl: './list-row.component.html',
styleUrls: ['./list-row.component.css'],
host: {
'class': 'row'
}
})
export class ListRowComponent {
#Input() list: List;
#Output() deleted = new EventEmitter<List>();
deletedl() {
const listing: List = this.list;
this.deleted.emit(listing);
}
In the template I used the click event to call the deletel() method.
<div class="Eight wide column left aligned title">
<div class="value">
<div class = "hello">
<b>
{{ list.title | uppercase }}
</b>
<div style="float: right;" class="ui label">
<i class="delete icon"
(click)="deletedl()">
</i>
</div>
</div>
</div>
</div>
Then I just called the event in the list.component
list.component.html
<div class="ui grid posts">
<app-list-row
*ngFor="let list of itemList"
[list]="list"
(click)='onClick(list)'
[class.selected]="isSelected(list)"
(deleted)="deletedl($event)">
</app-list-row>
</div>
Then i called a method in list.component to delete the list from the array using Splice method.
list.component
import { Component, Input} from '#angular/core';
import {List} from './list.model';
#Component({
selector: 'app-list',
templateUrl: './list.component.html',
styleUrls: ['./list.component.css']
})
export class ListComponent {
#Input() itemList: List[] = [];
private currentItem: List;
onClick(list: List): void {
this.currentItem = list;
console.log(`clicking list title: ${list.title}`);
}
isSelected(list: List): boolean {
if (!list || !this.currentItem) {
return false;
}
return list.title === this.currentItem.title;
}
deletedl(list: List) {
console.log(`deleting list title: ${list.title}`);
let index: number = this.itemList.indexOf(list);
if (index !== -1) {
this.itemList.splice(index, 1);
}
}
}
I have learned that if we want to get some input from the parent component than using property binding helps and when we want to run some output from our parent component then event binding is helpful.