{"id":2951,"date":"2021-01-25T10:00:00","date_gmt":"2021-01-25T15:00:00","guid":{"rendered":"https:\/\/www.mymiller.name\/wordpress\/?p=2951"},"modified":"2021-01-17T16:02:14","modified_gmt":"2021-01-17T21:02:14","slug":"angular-material-search-field","status":"publish","type":"post","link":"https:\/\/www.mymiller.name\/wordpress\/angular\/angular-material-search-field\/","title":{"rendered":"Angular Material Search Field"},"content":{"rendered":"\n<p>Angular Material offers a powerful set of features for building your Angular application. It&#8217;s time to take them to the next level. A project I&#8217;m working on needed a search field that would have different purposes throughout the application.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">SearchFieldComponent<\/h2>\n\n\n\n<p>I came up with a list of requirements for this field that would be common across the application:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Wanted to use the mat-form-field with a string input.<\/li><li>A hint would sometimes be necessary.<\/li><li>Needed a label and placeholder.<\/li><li>Had to respond to click the search icon, or hitting Enter in the field.<\/li><li>Needed to show an error message if it did not pass validation.<\/li><\/ul>\n\n\n\n<p>For this solution I did not want to use the base class I had used for my Form-Field components.  So started from scratch, kinda.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import {Component, EventEmitter, Input, OnDestroy, Output} from '@angular\/core';\nimport {Subscription} from \"rxjs\";\nimport {LanguageService} from \"..\/..\/..\/service\/language.service\";\n\n@Component({\n  selector: 'mymiller-search-field',\n  templateUrl: '.\/search-field.component.html',\n  styleUrls: &#91;'.\/search-field.component.scss']\n})\nexport class SearchFieldComponent implements OnDestroy {\n  @Input(\"label\") label: string = \"Search\";\n  @Input(\"placeholder\") placeHolder: string = \"Search\";\n  @Input(\"hint\") hint: string = \"Enter text to search\";\n\n  searchText: string = '';\n  errorMessage: string = '';\n\n  searchEmitted: string = ''\n  searchLabel: string = \"search\";\n  searchSub: Subscription;\n\n  @Output(\"onSearch\") onSearch: EventEmitter&lt;string&gt; = new EventEmitter&lt;string&gt;();\n  constructor(private languageService:LanguageService) {\n    this.searchLabel = this.languageService.searchLabel;\n    this.searchSub = this.languageService.searchSub.subscribe( value =&gt; this.searchLabel = value);\n  }\n\n  ngOnDestroy() {\n    this.searchSub.unsubscribe();\n  }\n\n  public search() {\n    if(this.searchEmitted !== this.searchText) {\n      this.errorMessage = '';\n      this.searchEmitted = this.searchText\n      this.onSearch.emit(this.searchText);\n    }\n  }\n\n  public invalid(message:string) {\n    this.errorMessage = message;\n  }\n\n  keyDownFunction(event:any) {\n    if (event.code === \"Enter\") {\n      this.search();\n    }\n  }\n}<\/code><\/pre>\n\n\n\n<p>Began with three inputs to set the [label], [placeholder], and [hint] for the field.  Then needed an (onSearch) emitter to send value when the search icon or Enter key was hit. I added a public method invalid(message:string) to report an error if needed.<\/p>\n\n\n\n<p>Since this is not based on the AbstractFieldComponent, I directly access the LanguageService to get the text for the search label.<\/p>\n\n\n\n<p>The html for this component is relatively simple:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;mat-form-field appearance=\"legacy\" class=\"full-width\"&gt;\n  &lt;mat-label&gt;{{label}}&lt;\/mat-label&gt;\n  &lt;input matInput &#91;placeholder]=\"placeHolder\" &#91;(ngModel)]=\"searchText\" (keydown)=\"keyDownFunction($event)\"&gt;\n  &lt;mat-icon matSuffix (click)=\"search()\"&gt;search&lt;\/mat-icon&gt;\n  &lt;mat-hint *ngIf=\"hint !== ''\"&gt;{{hint}}&lt;\/mat-hint&gt;\n  &lt;mat-error *ngIf=\"errorMessage !== ''\"&gt;{{errorMessage}}&lt;\/mat-error&gt;\n&lt;\/mat-form-field&gt;&lt;mat-form-field appearance=\"legacy\" class=\"full-width\"&gt;\n  &lt;mat-label&gt;{{label}}&lt;\/mat-label&gt;\n  &lt;input matInput &#91;placeholder]=\"placeHolder\" &#91;(ngModel)]=\"searchText\" (keydown)=\"keyDownFunction($event)\" (blur)=\"search()\" &gt;\n  &lt;mymiller-icon-button matSuffix icon=\"search\" (click)=\"search()\" &#91;tooltip]=\"searchLabel\"&gt;&lt;\/mymiller-icon-button&gt;\n  &lt;mat-hint *ngIf=\"hint !== ''\"&gt;{{hint}}&lt;\/mat-hint&gt;\n  &lt;mat-error *ngIf=\"errorMessage !== ''\"&gt;{{errorMessage}}&lt;\/mat-error&gt;\n&lt;\/mat-form-field&gt;&lt;mat-form-field appearance=\"legacy\" class=\"full-width\"&gt;\n  &lt;mat-label&gt;{{label}}&lt;\/mat-label&gt;\n  &lt;input matInput &#91;placeholder]=\"placeHolder\" &#91;(ngModel)]=\"searchText\" (keydown)=\"keyDownFunction($event)\"&gt;\n  &lt;mat-icon matSuffix (click)=\"search()\"&gt;search&lt;\/mat-icon&gt;\n  &lt;mat-hint *ngIf=\"hint !== ''\"&gt;{{hint}}&lt;\/mat-hint&gt;\n  &lt;mat-error *ngIf=\"errorMessage !== ''\"&gt;{{errorMessage}}&lt;\/mat-error&gt;\n&lt;\/mat-form-field&gt;<\/code><\/pre>\n\n\n\n<p>Added a listener for the (keydown) event to check for the Enter key.  If the hint was not empty then display it, and the same for the errorMessage.  Very simple HTML.<\/p>\n\n\n\n<p>Take note once again I added the full-width class to this.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>.full-width {\n  width: 100%;\n}<\/code><\/pre>\n\n\n\n<p>This is what the field will look like:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2020\/12\/SearchFieldComponent.png?ssl=1\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"359\" height=\"64\" src=\"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2020\/12\/SearchFieldComponent.png?resize=359%2C64&#038;ssl=1\" alt=\"\" class=\"wp-image-2957\" srcset=\"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2020\/12\/SearchFieldComponent.png?w=359&amp;ssl=1 359w, https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2020\/12\/SearchFieldComponent.png?resize=300%2C53&amp;ssl=1 300w\" sizes=\"auto, (max-width: 359px) 100vw, 359px\" \/><\/a><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>Angular Material Search Field component using mat-form-field to create a reusable component for searching.<\/p>\n","protected":false},"author":1,"featured_media":2952,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[281],"tags":[269],"series":[],"class_list":["post-2951","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-angular","tag-angular"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2020\/12\/search-bar-4999181_640.jpg?fit=640%2C225&ssl=1","jetpack-related-posts":[{"id":2946,"url":"https:\/\/www.mymiller.name\/wordpress\/angular\/angular-material-checkbox\/","url_meta":{"origin":2951,"position":0},"title":"Angular Material Checkbox","author":"Jeffery Miller","date":"January 11, 2021","format":false,"excerpt":"Create a compnent for Display\/Edit of a checkbox using Angular Material mat-form-field.","rel":"","context":"In &quot;Angular&quot;","block_context":{"text":"Angular","link":"https:\/\/www.mymiller.name\/wordpress\/category\/angular\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2020\/12\/checklist-2549229_640.jpg?fit=640%2C426&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2020\/12\/checklist-2549229_640.jpg?fit=640%2C426&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2020\/12\/checklist-2549229_640.jpg?fit=640%2C426&ssl=1&resize=525%2C300 1.5x"},"classes":[]},{"id":2943,"url":"https:\/\/www.mymiller.name\/wordpress\/angular\/angular-material-string-component\/","url_meta":{"origin":2951,"position":1},"title":"Angular Material String Component","author":"Jeffery Miller","date":"January 4, 2021","format":false,"excerpt":"Create a compnent for Display\/Edit\/Delete of a string using Angular Material mat-form-field.","rel":"","context":"In &quot;Angular&quot;","block_context":{"text":"Angular","link":"https:\/\/www.mymiller.name\/wordpress\/category\/angular\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2020\/12\/application-1883453_640.jpg?fit=640%2C426&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2020\/12\/application-1883453_640.jpg?fit=640%2C426&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2020\/12\/application-1883453_640.jpg?fit=640%2C426&ssl=1&resize=525%2C300 1.5x"},"classes":[]},{"id":2511,"url":"https:\/\/www.mymiller.name\/wordpress\/angular\/angular-environment\/","url_meta":{"origin":2951,"position":2},"title":"Angular Environment","author":"Jeffery Miller","date":"March 11, 2019","format":false,"excerpt":"Building a website for today and tomorrow begins with Angular. Yes I am a proponent of Angular over many other client frameworks. Let's look over the goals of this post to help you get started. Node.jsAngular-CliAngular Workspace Angular Material Installing Node.js First step you need to do is to install\u2026","rel":"","context":"In &quot;Angular&quot;","block_context":{"text":"Angular","link":"https:\/\/www.mymiller.name\/wordpress\/category\/angular\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2019\/03\/geometry-1023846_640.jpg?fit=640%2C359&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2019\/03\/geometry-1023846_640.jpg?fit=640%2C359&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2019\/03\/geometry-1023846_640.jpg?fit=640%2C359&ssl=1&resize=525%2C300 1.5x"},"classes":[]},{"id":3004,"url":"https:\/\/www.mymiller.name\/wordpress\/angular\/angular-material-calendar\/","url_meta":{"origin":2951,"position":3},"title":"Angular Material Calendar","author":"Jeffery Miller","date":"March 29, 2021","format":false,"excerpt":"Sometimes you need to have a calendar for showing information in your web application. After looking around at different implementations and finding none that work. I decided to create my own. This Calendar is not mobile optimized, For that, I created an Agenda that shows a single day at a\u2026","rel":"","context":"In &quot;Angular&quot;","block_context":{"text":"Angular","link":"https:\/\/www.mymiller.name\/wordpress\/category\/angular\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2021\/03\/january-2290045_640.jpg?fit=640%2C396&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2021\/03\/january-2290045_640.jpg?fit=640%2C396&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2021\/03\/january-2290045_640.jpg?fit=640%2C396&ssl=1&resize=525%2C300 1.5x"},"classes":[]},{"id":3029,"url":"https:\/\/www.mymiller.name\/wordpress\/angular\/angular-material-loading-spinner\/","url_meta":{"origin":2951,"position":4},"title":"Angular Material Loading Spinner","author":"Jeffery Miller","date":"May 3, 2021","format":false,"excerpt":"Just about every project I need to have at least one loading spinner to indicate to the user that data is being loaded and to wait. My recent project I found that to be no exception. I wanted to come up with something that I thought was a little nicer\u2026","rel":"","context":"In &quot;Angular&quot;","block_context":{"text":"Angular","link":"https:\/\/www.mymiller.name\/wordpress\/category\/angular\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2657,"url":"https:\/\/www.mymiller.name\/wordpress\/angular\/angular-material-grid-layout-responsive\/","url_meta":{"origin":2951,"position":5},"title":"Angular Material Grid Layout Responsive","author":"Jeffery Miller","date":"December 16, 2019","format":false,"excerpt":"Angular Material is a powerful extension onto Angular for UI design. I personally fell in love with it before I ever used it. When I started using it I knew I would find things I would want to improve. Material Grid List is so handy to use and makes layouts\u2026","rel":"","context":"In &quot;Angular&quot;","block_context":{"text":"Angular","link":"https:\/\/www.mymiller.name\/wordpress\/category\/angular\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2019\/12\/grid-684983_640.jpg?fit=640%2C480&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2019\/12\/grid-684983_640.jpg?fit=640%2C480&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2019\/12\/grid-684983_640.jpg?fit=640%2C480&ssl=1&resize=525%2C300 1.5x"},"classes":[]}],"jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/posts\/2951","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/comments?post=2951"}],"version-history":[{"count":4,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/posts\/2951\/revisions"}],"predecessor-version":[{"id":2983,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/posts\/2951\/revisions\/2983"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/media\/2952"}],"wp:attachment":[{"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/media?parent=2951"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/categories?post=2951"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/tags?post=2951"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/series?post=2951"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}