Add fuzzy-matcher poc for Angular 7.2.15. · iCodeIN/JavaScript-Demos@00ad01c · GitHub
Skip to content

Commit 00ad01c

Browse files
committed
Add fuzzy-matcher poc for Angular 7.2.15.
1 parent b1b30b0 commit 00ad01c

25 files changed

Lines changed: 8221 additions & 0 deletions

README.md

Lines changed: 1 addition & 0 deletions
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
# Now that we're using Webpack, we can install modules locally and just ignore
3+
# them since the assets are baked into the compiled modules.
4+
node_modules/
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
2+
:host {
3+
display: block ;
4+
font-size: 18px ;
5+
}
6+
7+
.filter {
8+
font-size: 22px ;
9+
}
10+
11+
.match {
12+
font-size: 18px ;
13+
14+
&__segment {
15+
color: #454545 ;
16+
display: inline-block ;
17+
white-space: pre ;
18+
19+
&--on {
20+
color: #000000 ;
21+
font-weight: 800 ;
22+
}
23+
}
24+
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
2+
// Import the core angular services.
3+
import { Component } from "@angular/core";
4+
5+
// Import the application components and services.
6+
import { FuzzyMatcher } from "./fuzzy-matcher";
7+
import { FuzzySegment } from "./fuzzy-matcher";
8+
import { primates } from "./primates";
9+
import { Species } from "./primates";
10+
11+
// ----------------------------------------------------------------------------------- //
12+
// ----------------------------------------------------------------------------------- //
13+
14+
interface FilterMatch {
15+
score: number;
16+
value: Species;
17+
segments: FuzzySegment[];
18+
}
19+
20+
@Component({
21+
selector: "my-app",
22+
styleUrls: [ "./app.component.less" ],
23+
template:
24+
`
25+
<input
26+
type="text"
27+
name="filter"
28+
[(ngModel)]="form.filter"
29+
(ngModelChange)="applyFilter()"
30+
placeholder="Search primates...."
31+
autofocus
32+
class="filter"
33+
/>
34+
35+
<ul *ngIf="matches.length">
36+
<li *ngFor="let match of matches" class="match">
37+
38+
<span
39+
*ngFor="let segment of match.segments"
40+
class="match__segment"
41+
[class.match__segment--on]="segment.isMatch"
42+
>{{ segment.value }}</span>
43+
44+
</li>
45+
</ul>
46+
`
47+
})
48+
export class AppComponent {
49+
50+
public form: {
51+
filter: string;
52+
};
53+
public matches: FilterMatch[];
54+
55+
private fuzzyMatcher: FuzzyMatcher;
56+
57+
// I initialize the app component.
58+
constructor( fuzzyMatcher: FuzzyMatcher ) {
59+
60+
this.fuzzyMatcher = fuzzyMatcher;
61+
62+
this.form = {
63+
filter: ""
64+
};
65+
this.matches = [];
66+
67+
}
68+
69+
// ---
70+
// PUBLIC METHODS.
71+
// ---
72+
73+
// I apply the current filter to the collection of primates, generate a set of fuzzy
74+
// matches.
75+
public applyFilter() : void {
76+
77+
// If there is no filter, then hide the list entirely. We only want to show
78+
// matches when we have something to match on.
79+
if ( ! this.form.filter ) {
80+
81+
this.matches = [];
82+
return;
83+
84+
}
85+
86+
this.matches = primates
87+
// First, we want to take the updated form input and use it to SCORE the
88+
// collection of values. This phase will have to evaluate the entire set of
89+
// values; but, will only do the minimal amount of work needed to calculate a
90+
// scope. Then, we'll be able to use that score to narrow down and format the
91+
// set of values that we end-up showing to the user.
92+
.map(
93+
( primate ) => {
94+
95+
return({
96+
value: primate,
97+
score: this.fuzzyMatcher.scoreValue( primate.name, this.form.filter )
98+
});
99+
100+
}
101+
)
102+
// Now that the entire set of values has been scored, let's sort them from
103+
// highest to lowest.
104+
.sort(
105+
( a, b ) => {
106+
107+
return(
108+
( ( a.score > b.score ) && -1 ) || // Move item up.
109+
( ( a.score < b.score ) && 1 ) || // Move item down.
110+
0
111+
);
112+
113+
}
114+
)
115+
// For the sake of the demo, we only want to show the top-scoring matches.
116+
// Slice off the top of the scored values.
117+
.slice( 0, 20 )
118+
// At this point, we've narrowed down the set of values to the ones we want
119+
// to show to the user. Now, we can go back and create a data-structure that
120+
// can be more easily rendered (but takes more processing).
121+
.map(
122+
( scoredValue ) => {
123+
124+
return({
125+
score: scoredValue.score,
126+
value: scoredValue.value,
127+
segments: this.fuzzyMatcher.parseValue( scoredValue.value.name, this.form.filter )
128+
});
129+
130+
}
131+
)
132+
;
133+
134+
}
135+
136+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
// Import the core angular services.
3+
import { BrowserModule } from "@angular/platform-browser";
4+
import { FormsModule } from "@angular/forms";
5+
import { NgModule } from "@angular/core";
6+
7+
// Import the application components and services.
8+
import { AppComponent } from "./app.component";
9+
10+
// ----------------------------------------------------------------------------------- //
11+
// ----------------------------------------------------------------------------------- //
12+
13+
@NgModule({
14+
imports: [
15+
BrowserModule,
16+
FormsModule
17+
],
18+
declarations: [
19+
AppComponent
20+
],
21+
bootstrap: [
22+
AppComponent
23+
]
24+
})
25+
export class AppModule {
26+
// ...
27+
}
Lines changed: 160 additions & 0 deletions

0 commit comments

Comments
 (0)