[{"id":"f61760ca-2010-4c99-9af5-655b0291457f","thread_id":"ee26398e-ceb8-4a7e-8b62-f3f50aa9ac2f","created_at":"2025-08-06T14:37:00Z","state":"done","prompt":"Can you write me an Autocomplete component for Angular? It should be able to call a callback to receive new data based on the user input.","reply":"<p></p><details><summary>Thinking</summary>\n<p>Okay, the user is asking for an Autocomplete component in Angular that can call a callback to fetch data based on user input. Let me think about how to approach this.</p>\n<p>First, I need to recall how Angular components work. Autocomplete usually involves an input field where as the user types, suggestions pop up. The key parts here are handling input events, debouncing to avoid too many requests, and displaying the results.</p>\n<p>The user mentioned a callback to receive new data. So the component should take a function as an input that gets called with the current input value. That function would probably return an Observable of the data.</p>\n<p>I should use Angular's reactive forms or at least the async pipe. Maybe use FormControl to track the input value. Then, using RxJS operators like debounceTime and switchMap to manage the HTTP requests or the callback.</p>\n<p>Wait, the callback is provided by the parent component. So the autocomplete component needs an @Input() for the callback function. Let me structure the component.</p>\n<p>Steps:</p>\n<ol>\n<li>Create a component with an input field.</li>\n<li>Use FormControl to monitor the input changes.</li>\n<li>Apply debounceTime to wait for user to stop typing.</li>\n<li>Use switchMap to call the callback function with the current value.</li>\n<li>Handle the results and display them.</li>\n</ol>\n<p>Also, need to handle cases where the callback might return an empty list or errors. Maybe show a loading indicator.</p>\n<p>Let me outline the component code.</p>\n<p>First, the template. It should have an input, and a dropdown list for suggestions.</p>\n<p>In the component class:</p>\n<ul>\n<li>@Input() searchCallback: (term: string) => Observable<any[]>; // or maybe a generic type</li>\n<li>control = new FormControl();</li>\n<li>filteredOptions$: Observable<any[]>;</li>\n<li>isLoading = false;</li>\n</ul>\n<p>In ngOnInit:</p>\n<p>this.filteredOptions$ = this.control.valueChanges.pipe(<br>\n debounceTime(300),<br>\n distinctUntilChanged(),<br>\n tap(() => this.isLoading = true),<br>\n switchMap(term => this.searchCallback(term).pipe(<br>\n catchError(() => of([])), // handle errors<br>\n tap(() => this.isLoading = false)<br>\n ))<br>\n);</p>\n<p>Wait, but the user said \"call a callback to receive new data\". So the callback is a function that returns an Observable. So the parent provides that function.</p>\n<p>Also, need to handle selecting an option. When a user clicks a suggestion, the input should be set to that value, and maybe emit an event.</p>\n<p>So the component should have an @Output() for when an option is selected.</p>\n<p>Let me think about the template structure.</p>\n<p><input [formControl]=\"control\" (keydown)=\"handleKeyDown($event)\" /></p>\n<p><ul <em>ngIf=\"filteredOptions$ | async as options; else loading\"><br>\n <li </em>ngFor=\"let option of options\" (click)=\"selectOption(option)\"><br>\n {{ option }}<br>\n </li><br>\n</ul><br>\n<ng-template #loading><br>\n <li *ngIf=\"isLoading\">Loading...</li><br>\n</ng-template></p>\n<p>Wait, but the async pipe in the template might not handle the isLoading properly. Maybe better to have a separate isLoading$ observable or a variable.</p>\n<p>Alternatively, use the async pipe with a loading state. But using a separate isLoading variable might be simpler for the template.</p>\n<p>Wait, in the pipe above, when the request starts, set isLoading to true, and on completion (success or error), set it to false.</p>\n<p>So in the component:</p>\n<p>ngOnInit() {<br>\n this.control.valueChanges.pipe(<br>\n debounceTime(300),<br>\n distinctUntilChanged(),<br>\n tap(() => this.isLoading = true),<br>\n switchMap(term => this.searchCallback(term).pipe(<br>\n catchError(() => of([])),<br>\n finalize(() => this.isLoading = false)<br>\n ))<br>\n ).subscribe(results => {<br>\n this.filteredOptions = results;<br>\n });<br>\n}</p>\n<p>But using async pipe is better to avoid manual subscriptions. So maybe:</p>\n<p>filteredOptions$: Observable<any[]>;<br>\nisLoading = false;</p>\n<p>ngOnInit() {<br>\n this.filteredOptions$ = this.control.valueChanges.pipe(<br>\n startWith(''),<br>\n debounceTime(300),<br>\n distinctUntilChanged(),<br>\n tap(() => this.isLoading = true),<br>\n switchMap(term => this.searchCallback(term).pipe(<br>\n catchError(() => of([])),<br>\n finalize(() => this.isLoading = false)<br>\n ))<br>\n );<br>\n}</p>\n<p>Then in the template:</p>\n<p><input [formControl]=\"control\" /></p>\n<p><div <em>ngIf=\"isLoading\">Loading...</div><br>\n<ul </em>ngIf=\"(filteredOptions$ | async)?.length > 0\"><br>\n <li *ngFor=\"let option of filteredOptions$ | async\" (click)=\"selectOption(option)\"><br>\n {{ option }}<br>\n </li><br>\n</ul></p>\n<p>Wait, but using async pipe multiple times might cause multiple subscriptions. So better to use *ngIf with async and store the result.</p>\n<p>Like:</p>\n<p><ng-container <em>ngIf=\"filteredOptions$ | async as options\"><br>\n <ul </em>ngIf=\"options.length > 0\"><br>\n <li *ngFor=\"let option of options\" (click)=\"selectOption(option)\"><br>\n {{ option }}<br>\n </li><br>\n </ul><br>\n</ng-container></p>\n<p>But then the loading indicator needs to be handled. Maybe have a separate isLoading$ observable.</p>\n<p>Alternatively, use a behavior subject for the loading state.</p>\n<p>But for simplicity, maybe the component can have a isLoading variable that's set in tap and finalize.</p>\n<p>Wait, in the pipe:</p>\n<p>this.filteredOptions$ = this.control.valueChanges.pipe(<br>\n debounceTime(300),<br>\n distinctUntilChanged(),<br>\n tap(() => this.isLoading = true),<br>\n switchMap(term => this.searchCallback(term).pipe(<br>\n catchError(() => of([])),<br>\n finalize(() => this.isLoading = false)<br>\n ))<br>\n);</p>\n<p>But this might not work because finalize is called after the observable completes, but the switchMap would switch to a new observable each time, so the finalize would reset isLoading.</p>\n<p>Wait, yes. So when a new search starts, isLoading is set to true. When the search completes (either with results or error), isLoading is set to false.</p>\n<p>So in the template, show loading when isLoading is true and there are no options yet.</p>\n<p>But when the user types, isLoading becomes true, then when data comes back, it becomes false.</p>\n<p>So the template can have:</p>\n<p><div *ngIf=\"isLoading && (filteredOptions$ | async)?.length === 0\">Loading...</div></p>\n<p>But maybe better to have a separate loading state.</p>\n<p>Alternatively, use a combineLatest for the options and loading state.</p>\n<p>But for simplicity, let's proceed with the isLoading variable.</p>\n<p>Now, the callback function. The parent component will provide a function that takes a string and returns an Observable of the results.</p>\n<p>For example:</p>\n<p>searchUsers(term: string): Observable<User[]> {<br>\n return this.http.get<User[]>(<code>/api/users?search=${term}</code>);<br>\n}</p>\n<p>Then, in the parent template:</p>\n<p><app-autocomplete [searchCallback]=\"searchUsers.bind(this)\"></app-autocomplete></p>\n<p>Wait, but in Angular, when passing a method as an input, you need to bind the context. So using .bind(this) is necessary.</p>\n<p>Alternatively, in the parent component, define the callback as an arrow function to preserve context.</p>\n<p>searchCallback = (term: string) => this.http.get(...);</p>\n<p>But the user might not know that, so in the example, it's better to show using .bind(this).</p>\n<p>Now, the component should also handle keyboard navigation, like up/down arrows and enter key. But the user didn't specify that, so maybe keep it simple for now. Just basic click selection.</p>\n<p>But the user said \"Autocomplete component\", which typically includes keyboard navigation. Hmm. The user might expect that, but the main requirement is the callback. Maybe include a basic version without keyboard nav, but mention it as a possible enhancement.</p>\n<p>Wait, the user's main request is to have it call a callback based on input. So focus on that.</p>\n<p>Let me outline the component code.</p>\n<p>First, the component class:</p>\n<p>import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';<br>\nimport { FormControl } from '@angular/forms';<br>\nimport { Observable, of } from 'rxjs';<br>\nimport { debounceTime, distinctUntilChanged, switchMap, catchError, finalize } from 'rxjs/operators';</p>\n<p>@Component({<br>\n selector: 'app-autocomplete',<br>\n template: ```<br>\n </p><div class=\"autocomplete\"><br>\n <input [formcontrol]=\"control\" type=\"text\" placeholder=\"Search...\"><p></p>\n<div class=\"highlight\"><span class=\"filename\">Text Only</span><pre><span></span><code> <div *ngIf=\"isLoading\" class=\"loading\">Loading...</div>\n\n <ul *ngIf=\"(filteredOptions$ | async)?.length > 0\" class=\"options\">\n <li \n *ngFor=\"let option of filteredOptions$ | async\" \n (click)=\"selectOption(option)\"\n >\n {{ option }}\n </li>\n </ul>\n</div>\n</code></pre></div>\n<p><code>,\n styles: [</code><br>\n .autocomplete { position: relative; }<br>\n .options { <br>\n position: absolute; <br>\n width: 100%; <br>\n max-height: 200px; <br>\n overflow-y: auto; <br>\n border: 1px solid #ccc; <br>\n list-style: none; <br>\n padding: 0; <br>\n margin: 0;<br>\n z-index: 1000;<br>\n }<br>\n .options li { <br>\n padding: 8px; <br>\n cursor: pointer; <br>\n }<br>\n .options li:hover { background-color: #f0f0f0; }<br>\n .loading { padding: 8px; color: #666; }<br>\n ```]<br>\n})<br>\nexport class AutocompleteComponent implements OnInit {<br>\n @Input() searchCallback!: (term: string) => Observable<any[]>;<br>\n @Output() optionSelected = new EventEmitter<any>();</p>\n<p>control = new FormControl();<br>\n filteredOptions$!: Observable<any[]>;<br>\n isLoading = false;</p>\n<p>ngOnInit() {<br>\n this.filteredOptions$ = this.control.valueChanges.pipe(<br>\n debounceTime(300),<br>\n distinctUntilChanged(),<br>\n tap(() => {<br>\n this.isLoading = true;<br>\n }),<br>\n switchMap(term => <br>\n this.searchCallback(term).pipe(<br>\n catchError(() => of([])),<br>\n finalize(() => this.isLoading = false)<br>\n )<br>\n )<br>\n );<br>\n }</p>\n<p>selectOption(option: any) {<br>\n this.control.setValue(option);<br>\n this.optionSelected.emit(option);<br>\n }<br>\n}</p>\n<p>Wait, but the searchCallback is required, so using !: to assert it's initialized. But maybe better to have a default or check if it's provided.</p>\n<p>Also, the initial value of filteredOptions$ needs to be set. In ngOnInit, it's assigned.</p>\n<p>But when the component initializes, the input field is empty, and no search is triggered until the user types. So maybe add startWith('') to trigger an initial search with empty string. But the user might not want that. Depending on the use case. If the API can handle empty terms, then startWith('') would make sense. Otherwise, maybe not.</p>\n<p>The user didn't specify, so perhaps include startWith('') so that when the component loads, it might show some default suggestions. But the callback should handle empty terms appropriately.</p>\n<p>Alternatively, only trigger when term length is sufficient, like >= 2 characters. But that's up to the callback implementation.</p>\n<p>So maybe in the component, don't filter by term length, leave it to the callback.</p>\n<p>So the code as written uses valueChanges, which starts emitting when the control value changes. So initially, when the component loads, control.value is null or empty string, but valueChanges doesn't emit until there's a change. So to trigger an initial search, need startWith('').</p>\n<p>Wait, valueChanges emits when the value changes, so if the control starts with an empty string, the first emission is when the user types something. So to have the initial empty string trigger a search, use startWith('').</p>\n<p>But maybe the user doesn't want to search on empty string. So perhaps the component should only search when term length >= 2, but that's a business logic decision. Since the user didn't specify, better to leave it to the callback.</p>\n<p>So the component should pass whatever the user types to the callback, and the callback can decide to return empty if term is too short.</p>\n<p>So in the code, using valueChanges without startWith would mean that the first search happens after the first keystroke. But if the user wants to show suggestions when the input is focused, maybe startWith('') is better.</p>\n<p>Hmm. Let's adjust the code to include startWith('') so that when the component initializes, it triggers a search with empty string, which the callback can handle.</p>\n<p>So:</p>\n<p>this.filteredOptions$ = this.control.valueChanges.pipe(<br>\n startWith(''),<br>\n debounceTime(300),<br>\n distinctUntilChanged(),<br>\n ...<br>\n);</p>\n<p>But then, when the component loads, it immediately calls searchCallback(''), which might be what the user wants (e.g., show top results). If not, the callback can return empty.</p>\n<p>So including startWith('') makes sense.</p>\n<p>Also, need to handle the case where searchCallback is not provided. But since it's marked as required with !:, Angular will throw an error if not provided. So in the example, the user must provide it.</p>\n<p>Now, testing the component.</p>\n<p>In the parent component:</p>\n<p>searchUsers = (term: string) => {<br>\n return this.http.get<User[]>(<code>/api/users?search=${term}</code>);<br>\n};</p>\n<p>Then in template:</p>\n<p><app-autocomplete [searchCallback]=\"searchUsers\"></app-autocomplete></p>\n<p>Wait, but if searchUsers is a method, then when passing it as [searchCallback]=\"searchUsers\", the context (this) will be lost. So need to bind it.</p>\n<p>So in parent component:</p>\n<p>searchUsers = (term: string) => {<br>\n return this.http.get(...);<br>\n};</p>\n<p>Then in template, [searchCallback]=\"searchUsers\" would work because it's an arrow function, which preserves 'this'.</p>\n<p>Alternatively, if it's a regular method:</p>\n<p>searchUsers(term: string) {<br>\n return this.http.get(...);<br>\n}</p>\n<p>Then need to pass [searchCallback]=\"searchUsers.bind(this)\".</p>\n<p>So in the example, better to show using an arrow function to avoid context issues.</p>\n<p>Now, the component also emits when an option is selected via optionSelected event.</p>\n<p>The user might want to know when an option is chosen.</p>\n<p>Now, possible improvements: keyboard navigation, clearing the input, handling errors, etc. But the user's main request is the callback, so the example should focus on that.</p>\n<p>Let me check if the code is correct.</p>\n<p>In the ngOnInit, filteredOptions$ is assigned. The valueChanges starts with '', then debounces, etc.</p>\n<p>Yes.</p>\n<p>Also, using catchError to return empty array on error, so the UI doesn't break.</p>\n<p>finalize sets isLoading to false after the observable completes.</p>\n<p>Yes.</p>\n<p>Now, the template uses *ngIf=\"(filteredOptions$ | async)?.length > 0\" to show the options list only when there are results.</p>\n<p>The loading indicator shows when isLoading is true.</p>\n<p>Styling is basic but functional.</p>\n<p>Now, the user might need to customize how the options are displayed. So instead of just {{ option }}, maybe allow a template. But the user didn't ask for that, so keep it simple.</p>\n<p>Alternatively, add an @Input() for a display function, but again, the user's main request is the callback.</p>\n<p>So the example provided should meet the user's needs.</p>\n<p>Wait, the user said \"call a callback to receive new data based on the user input\". The component does that via the searchCallback input.</p>\n<p>Yes.</p>\n<p>So the final code should be as outlined.</p>\n<p>Now, formatting the response according to the guidelines.</p>\n<p>Use markdown, proper lists, code blocks with language.</p>\n<p>Make sure to use hyphens for lists, indent nested lists.</p>\n<p>The response should have a code block for the component, and maybe some usage instructions.</p>\n<p>Also, mention that the parent component needs to provide the searchCallback function.</p>\n<p>Check for metric units, time format, but this is code, so not relevant.</p>\n<p>Language is English as the query is in English.</p>\n<p>Okay, time to write the response.</p>\n</div></details>\n<p>Here's an Angular Autocomplete component that fetches data via a callback function:</p>\n<div class=\"codehilite\"><span class=\"filename\">TypeScript</span><pre><span></span><code><span class=\"k\">import</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> </span><span class=\"nx\">Component</span><span class=\"p\">,</span><span class=\"w\"> </span><span class=\"nx\">Input</span><span class=\"p\">,</span><span class=\"w\"> </span><span class=\"nx\">Output</span><span class=\"p\">,</span><span class=\"w\"> </span><span class=\"nx\">EventEmitter</span><span class=\"p\">,</span><span class=\"w\"> </span><span class=\"nx\">OnInit</span><span class=\"w\"> </span><span class=\"p\">}</span><span class=\"w\"> </span><span class=\"kr\">from</span><span class=\"w\"> </span><span class=\"s1\">'@angular/core'</span><span class=\"p\">;</span>\n<span class=\"k\">import</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> </span><span class=\"nx\">FormControl</span><span class=\"w\"> </span><span class=\"p\">}</span><span class=\"w\"> </span><span class=\"kr\">from</span><span class=\"w\"> </span><span class=\"s1\">'@angular/forms'</span><span class=\"p\">;</span>\n<span class=\"k\">import</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> </span><span class=\"nx\">Observable</span><span class=\"p\">,</span><span class=\"w\"> </span><span class=\"k\">of</span><span class=\"w\"> </span><span class=\"p\">}</span><span class=\"w\"> </span><span class=\"kr\">from</span><span class=\"w\"> </span><span class=\"s1\">'rxjs'</span><span class=\"p\">;</span>\n<span class=\"k\">import</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> </span>\n<span class=\"w\"> </span><span class=\"nx\">debounceTime</span><span class=\"p\">,</span><span class=\"w\"> </span>\n<span class=\"w\"> </span><span class=\"nx\">distinctUntilChanged</span><span class=\"p\">,</span><span class=\"w\"> </span>\n<span class=\"w\"> </span><span class=\"nx\">switchMap</span><span class=\"p\">,</span><span class=\"w\"> </span>\n<span class=\"w\"> </span><span class=\"nx\">catchError</span><span class=\"p\">,</span><span class=\"w\"> </span>\n<span class=\"w\"> </span><span class=\"nx\">finalize</span><span class=\"w\"> </span>\n<span class=\"p\">}</span><span class=\"w\"> </span><span class=\"kr\">from</span><span class=\"w\"> </span><span class=\"s1\">'rxjs/operators'</span><span class=\"p\">;</span>\n\n<span class=\"kd\">@Component</span><span class=\"p\">({</span>\n<span class=\"w\"> </span><span class=\"nx\">selector</span><span class=\"o\">:</span><span class=\"w\"> </span><span class=\"s1\">'app-autocomplete'</span><span class=\"p\">,</span>\n<span class=\"w\"> </span><span class=\"nx\">template</span><span class=\"o\">:</span><span class=\"w\"> </span><span class=\"sb\">`</span>\n<span class=\"sb\"> <div class=\"autocomplete-container\"></span>\n<span class=\"sb\"> <input </span>\n<span class=\"sb\"> [formControl]=\"control\"</span>\n<span class=\"sb\"> type=\"text\"</span>\n<span class=\"sb\"> placeholder=\"Start typing...\"</span>\n<span class=\"sb\"> class=\"autocomplete-input\"</span>\n<span class=\"sb\"> /></span>\n\n<span class=\"sb\"> <div *ngIf=\"isLoading\" class=\"loading-indicator\">Loading...</div></span>\n\n<span class=\"sb\"> <ul *ngIf=\"(filteredOptions$ | async)?.length > 0\" class=\"suggestions-list\"></span>\n<span class=\"sb\"> <li </span>\n<span class=\"sb\"> *ngFor=\"let option of filteredOptions$ | async\" </span>\n<span class=\"sb\"> (click)=\"selectOption(option)\"</span>\n<span class=\"sb\"> class=\"suggestion-item\"</span>\n<span class=\"sb\"> ></span>\n<span class=\"sb\"> {{ displayWith ? displayWith(option) : option }}</span>\n<span class=\"sb\"> </li></span>\n<span class=\"sb\"> </ul></span>\n<span class=\"sb\"> </div></span>\n<span class=\"sb\"> `</span><span class=\"p\">,</span>\n<span class=\"w\"> </span><span class=\"nx\">styles</span><span class=\"o\">:</span><span class=\"w\"> </span><span class=\"p\">[</span><span class=\"sb\">`</span>\n<span class=\"sb\"> .autocomplete-container { position: relative; }</span>\n<span class=\"sb\"> .autocomplete-input {</span>\n<span class=\"sb\"> width: 100%;</span>\n<span class=\"sb\"> padding: 8px;</span>\n<span class=\"sb\"> font-size: 14px;</span>\n<span class=\"sb\"> }</span>\n<span class=\"sb\"> .suggestions-list {</span>\n<span class=\"sb\"> position: absolute;</span>\n<span class=\"sb\"> width: 100%;</span>\n<span class=\"sb\"> max-height: 200px;</span>\n<span class=\"sb\"> overflow-y: auto;</span>\n<span class=\"sb\"> border: 1px solid #ddd;</span>\n<span class=\"sb\"> list-style: none;</span>\n<span class=\"sb\"> padding: 0;</span>\n<span class=\"sb\"> margin: 0;</span>\n<span class=\"sb\"> background: white;</span>\n<span class=\"sb\"> z-index: 1000;</span>\n<span class=\"sb\"> box-shadow: 0 2px 6px rgba(0,0,0,0.1);</span>\n<span class=\"sb\"> }</span>\n<span class=\"sb\"> .suggestion-item {</span>\n<span class=\"sb\"> padding: 8px 12px;</span>\n<span class=\"sb\"> cursor: pointer;</span>\n<span class=\"sb\"> }</span>\n<span class=\"sb\"> .suggestion-item:hover {</span>\n<span class=\"sb\"> background-color: #f5f5f5;</span>\n<span class=\"sb\"> }</span>\n<span class=\"sb\"> .loading-indicator {</span>\n<span class=\"sb\"> padding: 8px;</span>\n<span class=\"sb\"> color: #666;</span>\n<span class=\"sb\"> font-style: italic;</span>\n<span class=\"sb\"> }</span>\n<span class=\"sb\"> `</span><span class=\"p\">]</span>\n<span class=\"p\">})</span>\n<span class=\"k\">export</span><span class=\"w\"> </span><span class=\"kd\">class</span><span class=\"w\"> </span><span class=\"nx\">AutocompleteComponent</span><span class=\"w\"> </span><span class=\"k\">implements</span><span class=\"w\"> </span><span class=\"nx\">OnInit</span><span class=\"w\"> </span><span class=\"p\">{</span>\n<span class=\"w\"> </span><span class=\"kd\">@Input</span><span class=\"p\">()</span><span class=\"w\"> </span><span class=\"nx\">searchCallback</span><span class=\"o\">!:</span><span class=\"w\"> </span><span class=\"p\">(</span><span class=\"nx\">term</span><span class=\"o\">:</span><span class=\"w\"> </span><span class=\"kt\">string</span><span class=\"p\">)</span><span class=\"w\"> </span><span class=\"p\">=></span><span class=\"w\"> </span><span class=\"nx\">Observable</span><span class=\"o\"><</span><span class=\"nx\">any</span><span class=\"p\">[]</span><span class=\"o\">></span><span class=\"p\">;</span>\n<span class=\"w\"> </span><span class=\"kd\">@Input</span><span class=\"p\">()</span><span class=\"w\"> </span><span class=\"nx\">displayWith</span><span class=\"o\">?:</span><span class=\"w\"> </span><span class=\"p\">(</span><span class=\"nx\">option</span><span class=\"o\">:</span><span class=\"w\"> </span><span class=\"kt\">any</span><span class=\"p\">)</span><span class=\"w\"> </span><span class=\"p\">=></span><span class=\"w\"> </span><span class=\"kt\">string</span><span class=\"p\">;</span>\n<span class=\"w\"> </span><span class=\"kd\">@Output</span><span class=\"p\">()</span><span class=\"w\"> </span><span class=\"nx\">optionSelected</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"ow\">new</span><span class=\"w\"> </span><span class=\"nx\">EventEmitter</span><span class=\"o\"><</span><span class=\"nx\">any</span><span class=\"o\">></span><span class=\"p\">();</span>\n\n<span class=\"w\"> </span><span class=\"nx\">control</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"ow\">new</span><span class=\"w\"> </span><span class=\"nx\">FormControl</span><span class=\"p\">();</span>\n<span class=\"w\"> </span><span class=\"nx\">filteredOptions$</span><span class=\"o\">!:</span><span class=\"w\"> </span><span class=\"nx\">Observable</span><span class=\"o\"><</span><span class=\"nx\">any</span><span class=\"p\">[]</span><span class=\"o\">></span><span class=\"p\">;</span>\n<span class=\"w\"> </span><span class=\"nx\">isLoading</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"kc\">false</span><span class=\"p\">;</span>\n\n<span class=\"w\"> </span><span class=\"nx\">ngOnInit</span><span class=\"p\">()</span><span class=\"w\"> </span><span class=\"p\">{</span>\n<span class=\"w\"> </span><span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">filteredOptions$</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">control</span><span class=\"p\">.</span><span class=\"nx\">valueChanges</span><span class=\"p\">.</span><span class=\"nx\">pipe</span><span class=\"p\">(</span>\n<span class=\"w\"> </span><span class=\"nx\">debounceTime</span><span class=\"p\">(</span><span class=\"mf\">300</span><span class=\"p\">),</span>\n<span class=\"w\"> </span><span class=\"nx\">distinctUntilChanged</span><span class=\"p\">(),</span>\n<span class=\"w\"> </span><span class=\"nx\">tap</span><span class=\"p\">(()</span><span class=\"w\"> </span><span class=\"p\">=></span><span class=\"w\"> </span><span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">isLoading</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"kc\">true</span><span class=\"p\">),</span>\n<span class=\"w\"> </span><span class=\"nx\">switchMap</span><span class=\"p\">(</span><span class=\"nx\">term</span><span class=\"w\"> </span><span class=\"p\">=></span><span class=\"w\"> </span>\n<span class=\"w\"> </span><span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">searchCallback</span><span class=\"p\">(</span><span class=\"nx\">term</span><span class=\"w\"> </span><span class=\"o\">||</span><span class=\"w\"> </span><span class=\"s1\">''</span><span class=\"p\">).</span><span class=\"nx\">pipe</span><span class=\"p\">(</span>\n<span class=\"w\"> </span><span class=\"nx\">catchError</span><span class=\"p\">(()</span><span class=\"w\"> </span><span class=\"p\">=></span><span class=\"w\"> </span><span class=\"k\">of</span><span class=\"p\">([])),</span>\n<span class=\"w\"> </span><span class=\"nx\">finalize</span><span class=\"p\">(()</span><span class=\"w\"> </span><span class=\"p\">=></span><span class=\"w\"> </span><span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">isLoading</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"kc\">false</span><span class=\"p\">)</span>\n<span class=\"w\"> </span><span class=\"p\">)</span>\n<span class=\"w\"> </span><span class=\"p\">)</span>\n<span class=\"w\"> </span><span class=\"p\">);</span>\n<span class=\"w\"> </span><span class=\"p\">}</span>\n\n<span class=\"w\"> </span><span class=\"nx\">selectOption</span><span class=\"p\">(</span><span class=\"nx\">option</span><span class=\"o\">:</span><span class=\"w\"> </span><span class=\"kt\">any</span><span class=\"p\">)</span><span class=\"w\"> </span><span class=\"p\">{</span>\n<span class=\"w\"> </span><span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">control</span><span class=\"p\">.</span><span class=\"nx\">setValue</span><span class=\"p\">(</span><span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">displayWith</span><span class=\"w\"> </span><span class=\"o\">?</span><span class=\"w\"> </span><span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">displayWith</span><span class=\"p\">(</span><span class=\"nx\">option</span><span class=\"p\">)</span><span class=\"w\"> </span><span class=\"o\">:</span><span class=\"w\"> </span><span class=\"nx\">option</span><span class=\"p\">);</span>\n<span class=\"w\"> </span><span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">optionSelected</span><span class=\"p\">.</span><span class=\"nx\">emit</span><span class=\"p\">(</span><span class=\"nx\">option</span><span class=\"p\">);</span>\n<span class=\"w\"> </span><span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<h2>Key Features</h2>\n<ul>\n<li>Uses reactive forms with <code>FormControl</code></li>\n<li>Debounces input (300ms) to reduce unnecessary requests</li>\n<li>Handles loading states and errors gracefully</li>\n<li>Supports custom display formatting via <code>displayWith</code> function</li>\n<li>Emits selected option through <code>optionSelected</code> event</li>\n</ul>\n<h2>Usage Example</h2>\n<ol>\n<li>\n<p><strong>Parent Component</strong>:<br>\n</p><div class=\"codehilite\"><span class=\"filename\">TypeScript</span><pre><span></span><code><span class=\"nx\">searchUsers</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"p\">(</span><span class=\"nx\">term</span><span class=\"o\">:</span><span class=\"w\"> </span><span class=\"kt\">string</span><span class=\"p\">)</span><span class=\"o\">:</span><span class=\"w\"> </span><span class=\"nx\">Observable</span><span class=\"o\"><</span><span class=\"nx\">User</span><span class=\"p\">[]</span><span class=\"o\">></span><span class=\"w\"> </span><span class=\"p\">=></span><span class=\"w\"> </span><span class=\"p\">{</span>\n<span class=\"w\"> </span><span class=\"k\">return</span><span class=\"w\"> </span><span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">http</span><span class=\"p\">.</span><span class=\"nx\">get</span><span class=\"o\"><</span><span class=\"nx\">User</span><span class=\"p\">[]</span><span class=\"o\">></span><span class=\"p\">(</span><span class=\"sb\">`/api/users?search=</span><span class=\"si\">${</span><span class=\"nx\">term</span><span class=\"si\">}</span><span class=\"sb\">`</span><span class=\"p\">);</span>\n<span class=\"p\">};</span>\n\n<span class=\"nx\">handleSelection</span><span class=\"p\">(</span><span class=\"nx\">user</span><span class=\"o\">:</span><span class=\"w\"> </span><span class=\"kt\">User</span><span class=\"p\">)</span><span class=\"w\"> </span><span class=\"p\">{</span>\n<span class=\"w\"> </span><span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"s1\">'Selected user:'</span><span class=\"p\">,</span><span class=\"w\"> </span><span class=\"nx\">user</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n</code></pre></div><p></p>\n</li>\n<li>\n<p><strong>Template</strong>:<br>\n</p><div class=\"codehilite\"><span class=\"filename\">HTML</span><pre><span></span><code><span class=\"p\"><</span><span class=\"nt\">app-autocomplete</span>\n <span class=\"err\">[</span><span class=\"na\">searchCallback</span><span class=\"err\">]=\"</span><span class=\"na\">searchUsers</span><span class=\"err\">\"</span>\n <span class=\"err\">[</span><span class=\"na\">displayWith</span><span class=\"err\">]=\"(</span><span class=\"na\">user</span><span class=\"err\">)</span> <span class=\"err\">=</span><span class=\"p\">></span> user.name\"\n (optionSelected)=\"handleSelection($event)\"\n><span class=\"p\"></</span><span class=\"nt\">app-autocomplete</span><span class=\"p\">></span>\n</code></pre></div><p></p>\n</li>\n</ol>\n<h2>Requirements</h2>\n<ul>\n<li>Parent must provide:<ul>\n<li><code>searchCallback</code>: Function that takes search term and returns <code>Observable</code> of results</li>\n<li>Optional <code>displayWith</code> formatter for custom option rendering</li>\n</ul>\n</li>\n<li>Handles empty results and HTTP errors automatically</li>\n<li>Includes basic styling (customize as needed)</li>\n</ul>\n<p>> Note: Remember to import <code>ReactiveFormsModule</code> in your Angular module and handle CORS/server-side requirements for your API calls. The component automatically converts empty inputs to empty strings to prevent <code>undefined</code> values in requests.</p>","md":"<details><summary>Thinking</summary>\n\nOkay, the user is asking for an Autocomplete component in Angular that can call a callback to fetch data based on user input. Let me think about how to approach this.\n\nFirst, I need to recall how Angular components work. Autocomplete usually involves an input field where as the user types, suggestions pop up. The key parts here are handling input events, debouncing to avoid too many requests, and displaying the results.\n\nThe user mentioned a callback to receive new data. So the component should take a function as an input that gets called with the current input value. That function would probably return an Observable of the data.\n\nI should use Angular's reactive forms or at least the async pipe. Maybe use FormControl to track the input value. Then, using RxJS operators like debounceTime and switchMap to manage the HTTP requests or the callback.\n\nWait, the callback is provided by the parent component. So the autocomplete component needs an @Input() for the callback function. Let me structure the component.\n\nSteps:\n\n1. Create a component with an input field.\n2. Use FormControl to monitor the input changes.\n3. Apply debounceTime to wait for user to stop typing.\n4. Use switchMap to call the callback function with the current value.\n5. Handle the results and display them.\n\nAlso, need to handle cases where the callback might return an empty list or errors. Maybe show a loading indicator.\n\nLet me outline the component code.\n\nFirst, the template. It should have an input, and a dropdown list for suggestions.\n\nIn the component class:\n\n- @Input() searchCallback: (term: string) => Observable<any[]>; // or maybe a generic type\n- control = new FormControl();\n- filteredOptions$: Observable<any[]>;\n- isLoading = false;\n\nIn ngOnInit:\n\nthis.filteredOptions$ = this.control.valueChanges.pipe(\n debounceTime(300),\n distinctUntilChanged(),\n tap(() => this.isLoading = true),\n switchMap(term => this.searchCallback(term).pipe(\n catchError(() => of([])), // handle errors\n tap(() => this.isLoading = false)\n ))\n);\n\nWait, but the user said \"call a callback to receive new data\". So the callback is a function that returns an Observable. So the parent provides that function.\n\nAlso, need to handle selecting an option. When a user clicks a suggestion, the input should be set to that value, and maybe emit an event.\n\nSo the component should have an @Output() for when an option is selected.\n\nLet me think about the template structure.\n\n<input [formControl]=\"control\" (keydown)=\"handleKeyDown($event)\" />\n\n<ul *ngIf=\"filteredOptions$ | async as options; else loading\">\n <li *ngFor=\"let option of options\" (click)=\"selectOption(option)\">\n {{ option }}\n </li>\n</ul>\n<ng-template #loading>\n <li *ngIf=\"isLoading\">Loading...</li>\n</ng-template>\n\nWait, but the async pipe in the template might not handle the isLoading properly. Maybe better to have a separate isLoading$ observable or a variable.\n\nAlternatively, use the async pipe with a loading state. But using a separate isLoading variable might be simpler for the template.\n\nWait, in the pipe above, when the request starts, set isLoading to true, and on completion (success or error), set it to false.\n\nSo in the component:\n\nngOnInit() {\n this.control.valueChanges.pipe(\n debounceTime(300),\n distinctUntilChanged(),\n tap(() => this.isLoading = true),\n switchMap(term => this.searchCallback(term).pipe(\n catchError(() => of([])),\n finalize(() => this.isLoading = false)\n ))\n ).subscribe(results => {\n this.filteredOptions = results;\n });\n}\n\nBut using async pipe is better to avoid manual subscriptions. So maybe:\n\nfilteredOptions$: Observable<any[]>;\nisLoading = false;\n\nngOnInit() {\n this.filteredOptions$ = this.control.valueChanges.pipe(\n startWith(''),\n debounceTime(300),\n distinctUntilChanged(),\n tap(() => this.isLoading = true),\n switchMap(term => this.searchCallback(term).pipe(\n catchError(() => of([])),\n finalize(() => this.isLoading = false)\n ))\n );\n}\n\nThen in the template:\n\n<input [formControl]=\"control\" />\n\n<div *ngIf=\"isLoading\">Loading...</div>\n<ul *ngIf=\"(filteredOptions$ | async)?.length > 0\">\n <li *ngFor=\"let option of filteredOptions$ | async\" (click)=\"selectOption(option)\">\n {{ option }}\n </li>\n</ul>\n\nWait, but using async pipe multiple times might cause multiple subscriptions. So better to use *ngIf with async and store the result.\n\nLike:\n\n<ng-container *ngIf=\"filteredOptions$ | async as options\">\n <ul *ngIf=\"options.length > 0\">\n <li *ngFor=\"let option of options\" (click)=\"selectOption(option)\">\n {{ option }}\n </li>\n </ul>\n</ng-container>\n\nBut then the loading indicator needs to be handled. Maybe have a separate isLoading$ observable.\n\nAlternatively, use a behavior subject for the loading state.\n\nBut for simplicity, maybe the component can have a isLoading variable that's set in tap and finalize.\n\nWait, in the pipe:\n\nthis.filteredOptions$ = this.control.valueChanges.pipe(\n debounceTime(300),\n distinctUntilChanged(),\n tap(() => this.isLoading = true),\n switchMap(term => this.searchCallback(term).pipe(\n catchError(() => of([])),\n finalize(() => this.isLoading = false)\n ))\n);\n\nBut this might not work because finalize is called after the observable completes, but the switchMap would switch to a new observable each time, so the finalize would reset isLoading.\n\nWait, yes. So when a new search starts, isLoading is set to true. When the search completes (either with results or error), isLoading is set to false.\n\nSo in the template, show loading when isLoading is true and there are no options yet.\n\nBut when the user types, isLoading becomes true, then when data comes back, it becomes false.\n\nSo the template can have:\n\n<div *ngIf=\"isLoading && (filteredOptions$ | async)?.length === 0\">Loading...</div>\n\nBut maybe better to have a separate loading state.\n\nAlternatively, use a combineLatest for the options and loading state.\n\nBut for simplicity, let's proceed with the isLoading variable.\n\nNow, the callback function. The parent component will provide a function that takes a string and returns an Observable of the results.\n\nFor example:\n\nsearchUsers(term: string): Observable<User[]> {\n return this.http.get<User[]>(```/api/users?search=${term}```);\n}\n\nThen, in the parent template:\n\n<app-autocomplete [searchCallback]=\"searchUsers.bind(this)\"></app-autocomplete>\n\nWait, but in Angular, when passing a method as an input, you need to bind the context. So using .bind(this) is necessary.\n\nAlternatively, in the parent component, define the callback as an arrow function to preserve context.\n\nsearchCallback = (term: string) => this.http.get(...);\n\nBut the user might not know that, so in the example, it's better to show using .bind(this).\n\nNow, the component should also handle keyboard navigation, like up/down arrows and enter key. But the user didn't specify that, so maybe keep it simple for now. Just basic click selection.\n\nBut the user said \"Autocomplete component\", which typically includes keyboard navigation. Hmm. The user might expect that, but the main requirement is the callback. Maybe include a basic version without keyboard nav, but mention it as a possible enhancement.\n\nWait, the user's main request is to have it call a callback based on input. So focus on that.\n\nLet me outline the component code.\n\nFirst, the component class:\n\nimport { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';\nimport { FormControl } from '@angular/forms';\nimport { Observable, of } from 'rxjs';\nimport { debounceTime, distinctUntilChanged, switchMap, catchError, finalize } from 'rxjs/operators';\n\n@Component({\n selector: 'app-autocomplete',\n template: ```\n <div class=\"autocomplete\">\n <input \n [formControl]=\"control\" \n type=\"text\" \n placeholder=\"Search...\"\n />\n \n <div *ngIf=\"isLoading\" class=\"loading\">Loading...</div>\n \n <ul *ngIf=\"(filteredOptions$ | async)?.length > 0\" class=\"options\">\n <li \n *ngFor=\"let option of filteredOptions$ | async\" \n (click)=\"selectOption(option)\"\n >\n {{ option }}\n </li>\n </ul>\n </div>\n ```,\n styles: [```\n .autocomplete { position: relative; }\n .options { \n position: absolute; \n width: 100%; \n max-height: 200px; \n overflow-y: auto; \n border: 1px solid #ccc; \n list-style: none; \n padding: 0; \n margin: 0;\n z-index: 1000;\n }\n .options li { \n padding: 8px; \n cursor: pointer; \n }\n .options li:hover { background-color: #f0f0f0; }\n .loading { padding: 8px; color: #666; }\n ```]\n})\nexport class AutocompleteComponent implements OnInit {\n @Input() searchCallback!: (term: string) => Observable<any[]>;\n @Output() optionSelected = new EventEmitter<any>();\n\n control = new FormControl();\n filteredOptions$!: Observable<any[]>;\n isLoading = false;\n\n ngOnInit() {\n this.filteredOptions$ = this.control.valueChanges.pipe(\n debounceTime(300),\n distinctUntilChanged(),\n tap(() => {\n this.isLoading = true;\n }),\n switchMap(term => \n this.searchCallback(term).pipe(\n catchError(() => of([])),\n finalize(() => this.isLoading = false)\n )\n )\n );\n }\n\n selectOption(option: any) {\n this.control.setValue(option);\n this.optionSelected.emit(option);\n }\n}\n\nWait, but the searchCallback is required, so using !: to assert it's initialized. But maybe better to have a default or check if it's provided.\n\nAlso, the initial value of filteredOptions$ needs to be set. In ngOnInit, it's assigned.\n\nBut when the component initializes, the input field is empty, and no search is triggered until the user types. So maybe add startWith('') to trigger an initial search with empty string. But the user might not want that. Depending on the use case. If the API can handle empty terms, then startWith('') would make sense. Otherwise, maybe not.\n\nThe user didn't specify, so perhaps include startWith('') so that when the component loads, it might show some default suggestions. But the callback should handle empty terms appropriately.\n\nAlternatively, only trigger when term length is sufficient, like >= 2 characters. But that's up to the callback implementation.\n\nSo maybe in the component, don't filter by term length, leave it to the callback.\n\nSo the code as written uses valueChanges, which starts emitting when the control value changes. So initially, when the component loads, control.value is null or empty string, but valueChanges doesn't emit until there's a change. So to trigger an initial search, need startWith('').\n\nWait, valueChanges emits when the value changes, so if the control starts with an empty string, the first emission is when the user types something. So to have the initial empty string trigger a search, use startWith('').\n\nBut maybe the user doesn't want to search on empty string. So perhaps the component should only search when term length >= 2, but that's a business logic decision. Since the user didn't specify, better to leave it to the callback.\n\nSo the component should pass whatever the user types to the callback, and the callback can decide to return empty if term is too short.\n\nSo in the code, using valueChanges without startWith would mean that the first search happens after the first keystroke. But if the user wants to show suggestions when the input is focused, maybe startWith('') is better.\n\nHmm. Let's adjust the code to include startWith('') so that when the component initializes, it triggers a search with empty string, which the callback can handle.\n\nSo:\n\nthis.filteredOptions$ = this.control.valueChanges.pipe(\n startWith(''),\n debounceTime(300),\n distinctUntilChanged(),\n ...\n);\n\nBut then, when the component loads, it immediately calls searchCallback(''), which might be what the user wants (e.g., show top results). If not, the callback can return empty.\n\nSo including startWith('') makes sense.\n\nAlso, need to handle the case where searchCallback is not provided. But since it's marked as required with !:, Angular will throw an error if not provided. So in the example, the user must provide it.\n\nNow, testing the component.\n\nIn the parent component:\n\nsearchUsers = (term: string) => {\n return this.http.get<User[]>(```/api/users?search=${term}```);\n};\n\nThen in template:\n\n<app-autocomplete [searchCallback]=\"searchUsers\"></app-autocomplete>\n\nWait, but if searchUsers is a method, then when passing it as [searchCallback]=\"searchUsers\", the context (this) will be lost. So need to bind it.\n\nSo in parent component:\n\nsearchUsers = (term: string) => {\n return this.http.get(...);\n};\n\nThen in template, [searchCallback]=\"searchUsers\" would work because it's an arrow function, which preserves 'this'.\n\nAlternatively, if it's a regular method:\n\nsearchUsers(term: string) {\n return this.http.get(...);\n}\n\nThen need to pass [searchCallback]=\"searchUsers.bind(this)\".\n\nSo in the example, better to show using an arrow function to avoid context issues.\n\nNow, the component also emits when an option is selected via optionSelected event.\n\nThe user might want to know when an option is chosen.\n\nNow, possible improvements: keyboard navigation, clearing the input, handling errors, etc. But the user's main request is the callback, so the example should focus on that.\n\nLet me check if the code is correct.\n\nIn the ngOnInit, filteredOptions$ is assigned. The valueChanges starts with '', then debounces, etc.\n\nYes.\n\nAlso, using catchError to return empty array on error, so the UI doesn't break.\n\nfinalize sets isLoading to false after the observable completes.\n\nYes.\n\nNow, the template uses *ngIf=\"(filteredOptions$ | async)?.length > 0\" to show the options list only when there are results.\n\nThe loading indicator shows when isLoading is true.\n\nStyling is basic but functional.\n\nNow, the user might need to customize how the options are displayed. So instead of just {{ option }}, maybe allow a template. But the user didn't ask for that, so keep it simple.\n\nAlternatively, add an @Input() for a display function, but again, the user's main request is the callback.\n\nSo the example provided should meet the user's needs.\n\nWait, the user said \"call a callback to receive new data based on the user input\". The component does that via the searchCallback input.\n\nYes.\n\nSo the final code should be as outlined.\n\nNow, formatting the response according to the guidelines.\n\nUse markdown, proper lists, code blocks with language.\n\nMake sure to use hyphens for lists, indent nested lists.\n\nThe response should have a code block for the component, and maybe some usage instructions.\n\nAlso, mention that the parent component needs to provide the searchCallback function.\n\nCheck for metric units, time format, but this is code, so not relevant.\n\nLanguage is English as the query is in English.\n\nOkay, time to write the response.\n\n</details>\n\nHere's an Angular Autocomplete component that fetches data via a callback function:\n\n```typescript\nimport { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';\nimport { FormControl } from '@angular/forms';\nimport { Observable, of } from 'rxjs';\nimport { \n debounceTime, \n distinctUntilChanged, \n switchMap, \n catchError, \n finalize \n} from 'rxjs/operators';\n\n@Component({\n selector: 'app-autocomplete',\n template: `\n <div class=\"autocomplete-container\">\n <input \n [formControl]=\"control\"\n type=\"text\"\n placeholder=\"Start typing...\"\n class=\"autocomplete-input\"\n />\n \n <div *ngIf=\"isLoading\" class=\"loading-indicator\">Loading...</div>\n \n <ul *ngIf=\"(filteredOptions$ | async)?.length > 0\" class=\"suggestions-list\">\n <li \n *ngFor=\"let option of filteredOptions$ | async\" \n (click)=\"selectOption(option)\"\n class=\"suggestion-item\"\n >\n {{ displayWith ? displayWith(option) : option }}\n </li>\n </ul>\n </div>\n `,\n styles: [`\n .autocomplete-container { position: relative; }\n .autocomplete-input {\n width: 100%;\n padding: 8px;\n font-size: 14px;\n }\n .suggestions-list {\n position: absolute;\n width: 100%;\n max-height: 200px;\n overflow-y: auto;\n border: 1px solid #ddd;\n list-style: none;\n padding: 0;\n margin: 0;\n background: white;\n z-index: 1000;\n box-shadow: 0 2px 6px rgba(0,0,0,0.1);\n }\n .suggestion-item {\n padding: 8px 12px;\n cursor: pointer;\n }\n .suggestion-item:hover {\n background-color: #f5f5f5;\n }\n .loading-indicator {\n padding: 8px;\n color: #666;\n font-style: italic;\n }\n `]\n})\nexport class AutocompleteComponent implements OnInit {\n @Input() searchCallback!: (term: string) => Observable<any[]>;\n @Input() displayWith?: (option: any) => string;\n @Output() optionSelected = new EventEmitter<any>();\n\n control = new FormControl();\n filteredOptions$!: Observable<any[]>;\n isLoading = false;\n\n ngOnInit() {\n this.filteredOptions$ = this.control.valueChanges.pipe(\n debounceTime(300),\n distinctUntilChanged(),\n tap(() => this.isLoading = true),\n switchMap(term => \n this.searchCallback(term || '').pipe(\n catchError(() => of([])),\n finalize(() => this.isLoading = false)\n )\n )\n );\n }\n\n selectOption(option: any) {\n this.control.setValue(this.displayWith ? this.displayWith(option) : option);\n this.optionSelected.emit(option);\n }\n}\n```\n\n## Key Features\n\n- Uses reactive forms with ```FormControl```\n- Debounces input (300ms) to reduce unnecessary requests\n- Handles loading states and errors gracefully\n- Supports custom display formatting via ```displayWith``` function\n- Emits selected option through ```optionSelected``` event\n\n## Usage Example\n\n1. **Parent Component**:\n```typescript\nsearchUsers = (term: string): Observable<User[]> => {\n return this.http.get<User[]>(`/api/users?search=${term}`);\n};\n\nhandleSelection(user: User) {\n console.log('Selected user:', user);\n}\n```\n\n2. **Template**:\n```html\n<app-autocomplete\n [searchCallback]=\"searchUsers\"\n [displayWith]=\"(user) => user.name\"\n (optionSelected)=\"handleSelection($event)\"\n></app-autocomplete>\n```\n\n## Requirements\n\n- Parent must provide:\n - ```searchCallback```: Function that takes search term and returns ```Observable``` of results\n - Optional ```displayWith``` formatter for custom option rendering\n- Handles empty results and HTTP errors automatically\n- Includes basic styling (customize as needed)\n\n> Note: Remember to import ```ReactiveFormsModule``` in your Angular module and handle CORS/server-side requirements for your API calls. The component automatically converts empty inputs to empty strings to prevent ```undefined``` values in requests.","profile":{"id":null,"name":null,"model":"qwen-3-235b-a22b-thinking","model_name":"Qwen3-235B (reasoning)","model_provider":"qwen","model_input_limit":1000000,"recommended":false,"model_info":"\n\n<div class=\"heading\">\n <div class=\"left\">\n \n \n \n <svg class=\"model-icon icon-xs\" data-model=\"qwen-3-235b-a22b-thinking\">\n <use href=\"#icon-qwen\"/>\n </svg>\n <h3>\n \n <span class=\"model-provider\">Alibaba</span>\n \n <span class=\"model-name\">none</span>\n </h3>\n </div>\n\n \n <a href=\"/settings?p=custom_assistant&id=none\">\n <svg class=\"icon-sm edit-icon\" aria-hidden=\"true\">\n <use href=\"#icon-pencil\" />\n </svg>\n </a>\n \n</div>\n\n\n<hr />\n<ul>\n \n <li>\n <h4>\n Cost\n </h4>\n <span>\n \n \n \n\n \n \n \n\n <div class=\"score\" aria-label=\"Relatively cheap\">\n \n \n \n \n <div aria-hidden=\"true\" class=\"filled-cost --low\"></div>\n \n \n \n \n \n <div aria-hidden=\"true\" class=\"filled-cost --low\"></div>\n \n \n \n \n \n <div aria-hidden=\"true\" class=\"unfilled-cost --low\"></div>\n \n \n \n \n \n <div aria-hidden=\"true\" class=\"unfilled-cost --low\"></div>\n \n \n \n \n \n <div aria-hidden=\"true\" class=\"unfilled-cost --low\"></div>\n \n \n </div>\n</span>\n </li>\n <li>\n <h4>\n Quality\n </h4>\n <span>\n \n \n \n\n \n \n \n\n <div class=\"score\" aria-label=\"Rated 4 out of 5\">\n \n \n \n <div aria-hidden=\"true\" class=\"filled-bubble\"></div>\n \n \n \n \n <div aria-hidden=\"true\" class=\"filled-bubble\"></div>\n \n \n \n \n <div aria-hidden=\"true\" class=\"filled-bubble\"></div>\n \n \n \n \n <div aria-hidden=\"true\" class=\"filled-bubble\"></div>\n \n \n \n \n <div aria-hidden=\"true\" class=\"unfilled-bubble\"></div>\n \n \n </div>\n</span>\n </li>\n <li>\n <h4>\n Speed\n </h4>\n <span>\n \n \n \n\n \n \n \n\n <div class=\"score\" aria-label=\"Rated 2 out of 5\">\n \n \n \n <div aria-hidden=\"true\" class=\"filled-bubble\"></div>\n \n \n \n \n <div aria-hidden=\"true\" class=\"filled-bubble\"></div>\n \n \n \n \n <div aria-hidden=\"true\" class=\"unfilled-bubble\"></div>\n \n \n \n \n <div aria-hidden=\"true\" class=\"unfilled-bubble\"></div>\n \n \n \n \n <div aria-hidden=\"true\" class=\"unfilled-bubble\"></div>\n \n \n </div>\n</span>\n </li>\n <li>\n <h4>\n Privacy\n </h4>\n <span>\n \n \n \n\n \n \n \n\n <div class=\"score\" aria-label=\"Rated 5 out of 5\">\n \n \n \n <div aria-hidden=\"true\" class=\"filled-bubble\"></div>\n \n \n \n \n <div aria-hidden=\"true\" class=\"filled-bubble\"></div>\n \n \n \n \n <div aria-hidden=\"true\" class=\"filled-bubble\"></div>\n \n \n \n \n <div aria-hidden=\"true\" class=\"filled-bubble\"></div>\n \n \n \n \n <div aria-hidden=\"true\" class=\"filled-bubble\"></div>\n \n \n </div>\n</span>\n </li>\n <li class=\"divider\" aria-hidden=\"true\"></li>\n <li>\n <h4>Last updated</h4>\n <span class=\"date\">\n \n \n 2025-07-25\n \n \n </span>\n </li>\n \n</ul>\n","model_provider_name":"Alibaba","internet_access":true,"personalizations":true,"shortcut":null,"is_default_profile":false},"metadata":"<li>\n <span class=\"attribute\">Model</span>\n <span class=\"value\"><i class=\"icon-xs mr-2\"><svg><use href=\"#icon-qwen\"></use></svg></i>Qwen3-235B (reasoning)</span>\n</li>\n<li>\n <span class=\"attribute\">Version</span>\n <span class=\"value\">qwen3-235b-a22b-thinking-2507</span>\n</li>\n<li>\n <span class=\"attribute\">Speed (tok/s)</span>\n <span class=\"value\">96</span>\n</li>\n<li>\n <span class=\"attribute\">Tokens</span>\n <span class=\"value\">4,836</span>\n</li>\n<li>\n <span class=\"attribute\">Cost / Total ($)</span>\n <span class=\"value\">0.006 / 0.006</span>\n</li>\n<li>\n <span class=\"attribute\">End to end time (s)</span>\n <span class=\"value\">46.64</span>\n</li>\n\n","documents":[]}]