{"id":8261,"date":"2021-03-17T12:24:00","date_gmt":"2021-03-17T17:24:00","guid":{"rendered":"https:\/\/upmostly.com\/?p=8261"},"modified":"2022-11-01T09:49:54","modified_gmt":"2022-11-01T14:49:54","slug":"creating-a-textbox-with-delayed-output-in-angular","status":"publish","type":"post","link":"http:\/\/upmostly.com\/angular\/creating-a-textbox-with-delayed-output-in-angular","title":{"rendered":"Creating A Textbox With Delayed Output In Angular"},"content":{"rendered":"\n<p>I wasn\u2019t quite sure what to call this post, so instead let\u2019s give give some scenarios in which you want to use a \u201cTexbox with delayed output\u201d<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>You want to create your own custom typeahead component that waits until a user stops typing before looking up results<\/li><li>You want a textbox that waits until a user stops typing, so you can call a backend API to check for duplicated names\/emails\/records<\/li><li>You want to add a text filter to a table\/list, that only refreshes\/filters when you stop typing in a textbox for a short period of time<\/li><li>In general, we want to use a textbox that waits until the user has stopped typing for a few milliseconds, and only then return the result to us<\/li><\/ul>\n\n\n\n<p>All of these can be solved using a Textbox with a delayed (or debounced) output. And it\u2019s actually very simple using some helpful code from RxJS.<\/p>\n\n\n\n<p>First I\u2019ll give you the complete code, then point out the important bits :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"jsx\" class=\"language-jsx\">@Component({\n  selector: 'app-delayed-textbox',\n  templateUrl: '.\/delayed-textbox.component.html',\n  styleUrls: ['.\/delayed-textbox.component.scss'], \n  providers : [\n    { \n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() =&gt; DebounceTextboxComponent),\n      multi: true\n    }\n  ]\n})\nexport class DelayedTextboxComponent implements OnInit {\n  delayTime : number = 250\n  \n  currentText : string;\n  \n  private textChanged = new Subject();\n\n  constructor() { }\n\n  ngOnInit(): void {\n    this.textChanged.pipe(debounceTime(this.delayTime)).subscribe(() =&gt; {\n      this.propogateTouch();\n      this.propagateChange(this.currentText);\n    });\n  }\n\n  onTextInput() {\n    this.textChanged.next();\n  }\n\n   \/\/Start implementation of ControlValueAccessor\n   propagateChange = (_: any) =&gt; {};\n   propogateTouch = () =&gt; {};\n \n   writeValue(obj: any): void {\n     this.currentText = obj;\n   }\n \n   registerOnChange(fn: any): void {\n     this.propagateChange = fn;\n   }\n   registerOnTouched(fn : any) {\n     this.propogateTouch = fn;\n   }\n   setDisabledState?(isDisabled: boolean): void {}\n   \/\/End implementation of ControlValueAccessor\n}<\/code><\/pre>\n\n\n\n<p>This little piece here is where the secret sauce is :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"jsx\" class=\"language-jsx\">private textChanged = new Subject();\n\nthis.textChanged.pipe(debounceTime(this.delayTime)).subscribe(() =&gt; {\n  this.propogateTouch();\n  this.propagateChange(this.currentText);\n});<\/code><\/pre>\n\n\n\n<p>What this says is as events are pumped into the textChanged subject, \u201cdebounce\u201d them. That is, wait until there is a gap of 250ms, then return me the&nbsp;<strong>*last*<\/strong>&nbsp;item. If there are multiple events pumped into the subject during this time, still I only want the last one returned to me.<\/p>\n\n\n\n<p>In our view for our custom component, we will have just the following :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"jsx\" class=\"language-jsx\">&lt;input type=\"text\"\n        name=\"delayTextbox\"\n        [(ngModel)]=\"currentText\"\n        (ngModelChange)=\"onTextInput()\" \/&gt;<\/code><\/pre>\n\n\n\n<p>So nothing special, but in particular notice that when the model is changed, onTextInput() is called. This then enqueues a message onto our subject, which then itself debounces for 250ms, and then finally we propogate the change!<\/p>\n\n\n\n<p>We can use this delayed textbox like so :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"jsx\" class=\"language-jsx\">&lt;app-delayed-textbox \n  name=\"myTextbox\" \n  [(ngModel)]=\"myModel.Field\" \n  (ngModelChange)=\"onMyModelFieldChanged()\"&gt;\n&lt;\/app-delayed-textbox &gt;<\/code><\/pre>\n\n\n\n<p>Notice how because we set up the ControlValueAccessor interface on our custom component, we can simply use the standard ngModel and ngModelChange to be alerted when the field changes.<\/p>\n\n\n\n<p>I\u2019ve seen some really crazy implementations of these sorts of delayed textboxes where people try and time keydowns and keyups, and just a crazy combination of setTimeout and booleans etc. But RxJS essentially does the same thing for us, using the simply debounceTime operator!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I wasn\u2019t quite sure what to call this post, so instead let\u2019s give give some scenarios in which you want to use a \u201cTexbox with delayed output\u201d You want to create your own custom typeahead component that waits until a user stops typing before looking up results You want a textbox that waits until a [&hellip;]<\/p>\n","protected":false},"author":131,"featured_media":8270,"comment_status":"open","ping_status":"open","sticky":false,"template":"post-tutorial-new.php","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[150],"tags":[],"class_list":["post-8261","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-angular"],"acf":[],"_links":{"self":[{"href":"https:\/\/upmostly.com\/wp-json\/wp\/v2\/posts\/8261","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/upmostly.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/upmostly.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/upmostly.com\/wp-json\/wp\/v2\/users\/131"}],"replies":[{"embeddable":true,"href":"https:\/\/upmostly.com\/wp-json\/wp\/v2\/comments?post=8261"}],"version-history":[{"count":4,"href":"https:\/\/upmostly.com\/wp-json\/wp\/v2\/posts\/8261\/revisions"}],"predecessor-version":[{"id":13425,"href":"https:\/\/upmostly.com\/wp-json\/wp\/v2\/posts\/8261\/revisions\/13425"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/upmostly.com\/wp-json\/wp\/v2\/media\/8270"}],"wp:attachment":[{"href":"https:\/\/upmostly.com\/wp-json\/wp\/v2\/media?parent=8261"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/upmostly.com\/wp-json\/wp\/v2\/categories?post=8261"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/upmostly.com\/wp-json\/wp\/v2\/tags?post=8261"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}