material-select.umd.js 85 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175
  1. /**
  2. * @license
  3. * Copyright Google LLC All Rights Reserved.
  4. *
  5. * Use of this source code is governed by an MIT-style license that can be
  6. * found in the LICENSE file at https://angular.io/license
  7. */
  8. (function (global, factory) {
  9. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/animations'), require('@angular/cdk/a11y'), require('@angular/cdk/bidi'), require('@angular/cdk/coercion'), require('@angular/cdk/collections'), require('@angular/cdk/keycodes'), require('@angular/cdk/overlay'), require('@angular/cdk/scrolling'), require('@angular/core'), require('@angular/forms'), require('@angular/material/core'), require('@angular/material/form-field'), require('rxjs'), require('rxjs/operators'), require('@angular/common')) :
  10. typeof define === 'function' && define.amd ? define('@angular/material/select', ['exports', '@angular/animations', '@angular/cdk/a11y', '@angular/cdk/bidi', '@angular/cdk/coercion', '@angular/cdk/collections', '@angular/cdk/keycodes', '@angular/cdk/overlay', '@angular/cdk/scrolling', '@angular/core', '@angular/forms', '@angular/material/core', '@angular/material/form-field', 'rxjs', 'rxjs/operators', '@angular/common'], factory) :
  11. (factory((global.ng = global.ng || {}, global.ng.material = global.ng.material || {}, global.ng.material.select = {}),global.ng.animations,global.ng.cdk.a11y,global.ng.cdk.bidi,global.ng.cdk.coercion,global.ng.cdk.collections,global.ng.cdk.keycodes,global.ng.cdk.overlay,global.ng.cdk.scrolling,global.ng.core,global.ng.forms,global.ng.material.core,global.ng.material.formField,global.rxjs,global.rxjs.operators,global.ng.common));
  12. }(this, (function (exports,animations,a11y,bidi,coercion,collections,keycodes,overlay,scrolling,core,forms,core$1,formField,rxjs,operators,common) { 'use strict';
  13. /*! *****************************************************************************
  14. Copyright (c) Microsoft Corporation. All rights reserved.
  15. Licensed under the Apache License, Version 2.0 (the "License"); you may not use
  16. this file except in compliance with the License. You may obtain a copy of the
  17. License at http://www.apache.org/licenses/LICENSE-2.0
  18. THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  19. KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
  20. WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
  21. MERCHANTABLITY OR NON-INFRINGEMENT.
  22. See the Apache Version 2.0 License for specific language governing permissions
  23. and limitations under the License.
  24. ***************************************************************************** */
  25. /* global Reflect, Promise */
  26. var extendStatics = function(d, b) {
  27. extendStatics = Object.setPrototypeOf ||
  28. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  29. function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  30. return extendStatics(d, b);
  31. };
  32. function __extends(d, b) {
  33. extendStatics(d, b);
  34. function __() { this.constructor = d; }
  35. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  36. }
  37. /**
  38. * @fileoverview added by tsickle
  39. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  40. */
  41. /**
  42. * The following are all the animations for the mat-select component, with each
  43. * const containing the metadata for one animation.
  44. *
  45. * The values below match the implementation of the AngularJS Material mat-select animation.
  46. * \@docs-private
  47. * @type {?}
  48. */
  49. var matSelectAnimations = {
  50. /**
  51. * This animation ensures the select's overlay panel animation (transformPanel) is called when
  52. * closing the select.
  53. * This is needed due to https://github.com/angular/angular/issues/23302
  54. */
  55. transformPanelWrap: animations.trigger('transformPanelWrap', [
  56. animations.transition('* => void', animations.query('@transformPanel', [animations.animateChild()], { optional: true }))
  57. ]),
  58. /**
  59. * This animation transforms the select's overlay panel on and off the page.
  60. *
  61. * When the panel is attached to the DOM, it expands its width by the amount of padding, scales it
  62. * up to 100% on the Y axis, fades in its border, and translates slightly up and to the
  63. * side to ensure the option text correctly overlaps the trigger text.
  64. *
  65. * When the panel is removed from the DOM, it simply fades out linearly.
  66. */
  67. transformPanel: animations.trigger('transformPanel', [
  68. animations.state('void', animations.style({
  69. transform: 'scaleY(0.8)',
  70. minWidth: '100%',
  71. opacity: 0
  72. })),
  73. animations.state('showing', animations.style({
  74. opacity: 1,
  75. minWidth: 'calc(100% + 32px)',
  76. // 32px = 2 * 16px padding
  77. transform: 'scaleY(1)'
  78. })),
  79. animations.state('showing-multiple', animations.style({
  80. opacity: 1,
  81. minWidth: 'calc(100% + 64px)',
  82. // 64px = 48px padding on the left + 16px padding on the right
  83. transform: 'scaleY(1)'
  84. })),
  85. animations.transition('void => *', animations.animate('120ms cubic-bezier(0, 0, 0.2, 1)')),
  86. animations.transition('* => void', animations.animate('100ms 25ms linear', animations.style({ opacity: 0 })))
  87. ]),
  88. /**
  89. * This animation fades in the background color and text content of the
  90. * select's options. It is time delayed to occur 100ms after the overlay
  91. * panel has transformed in.
  92. * @deprecated Not used anymore. To be removed.
  93. * \@breaking-change 8.0.0
  94. */
  95. fadeInContent: animations.trigger('fadeInContent', [
  96. animations.state('showing', animations.style({ opacity: 1 })),
  97. animations.transition('void => showing', [
  98. animations.style({ opacity: 0 }),
  99. animations.animate('150ms 100ms cubic-bezier(0.55, 0, 0.55, 0.2)')
  100. ])
  101. ])
  102. };
  103. /**
  104. * @deprecated
  105. * \@breaking-change 8.0.0
  106. * \@docs-private
  107. * @type {?}
  108. */
  109. var transformPanel = matSelectAnimations.transformPanel;
  110. /**
  111. * @deprecated
  112. * \@breaking-change 8.0.0
  113. * \@docs-private
  114. * @type {?}
  115. */
  116. var fadeInContent = matSelectAnimations.fadeInContent;
  117. /**
  118. * @fileoverview added by tsickle
  119. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  120. */
  121. /**
  122. * Returns an exception to be thrown when attempting to change a select's `multiple` option
  123. * after initialization.
  124. * \@docs-private
  125. * @return {?}
  126. */
  127. function getMatSelectDynamicMultipleError() {
  128. return Error('Cannot change `multiple` mode of select after initialization.');
  129. }
  130. /**
  131. * Returns an exception to be thrown when attempting to assign a non-array value to a select
  132. * in `multiple` mode. Note that `undefined` and `null` are still valid values to allow for
  133. * resetting the value.
  134. * \@docs-private
  135. * @return {?}
  136. */
  137. function getMatSelectNonArrayValueError() {
  138. return Error('Value must be an array in multiple-selection mode.');
  139. }
  140. /**
  141. * Returns an exception to be thrown when assigning a non-function value to the comparator
  142. * used to determine if a value corresponds to an option. Note that whether the function
  143. * actually takes two values and returns a boolean is not checked.
  144. * @return {?}
  145. */
  146. function getMatSelectNonFunctionValueError() {
  147. return Error('`compareWith` must be a function.');
  148. }
  149. /**
  150. * @fileoverview added by tsickle
  151. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  152. */
  153. /** @type {?} */
  154. var nextUniqueId = 0;
  155. /**
  156. * The max height of the select's overlay panel
  157. * @type {?}
  158. */
  159. var SELECT_PANEL_MAX_HEIGHT = 256;
  160. /**
  161. * The panel's padding on the x-axis
  162. * @type {?}
  163. */
  164. var SELECT_PANEL_PADDING_X = 16;
  165. /**
  166. * The panel's x axis padding if it is indented (e.g. there is an option group).
  167. * @type {?}
  168. */
  169. var SELECT_PANEL_INDENT_PADDING_X = SELECT_PANEL_PADDING_X * 2;
  170. /**
  171. * The height of the select items in `em` units.
  172. * @type {?}
  173. */
  174. var SELECT_ITEM_HEIGHT_EM = 3;
  175. // TODO(josephperrott): Revert to a constant after 2018 spec updates are fully merged.
  176. /**
  177. * Distance between the panel edge and the option text in
  178. * multi-selection mode.
  179. *
  180. * Calculated as:
  181. * (SELECT_PANEL_PADDING_X * 1.5) + 16 = 40
  182. * The padding is multiplied by 1.5 because the checkbox's margin is half the padding.
  183. * The checkbox width is 16px.
  184. * @type {?}
  185. */
  186. var SELECT_MULTIPLE_PANEL_PADDING_X = SELECT_PANEL_PADDING_X * 1.5 + 16;
  187. /**
  188. * The select panel will only "fit" inside the viewport if it is positioned at
  189. * this value or more away from the viewport boundary.
  190. * @type {?}
  191. */
  192. var SELECT_PANEL_VIEWPORT_PADDING = 8;
  193. /**
  194. * Injection token that determines the scroll handling while a select is open.
  195. * @type {?}
  196. */
  197. var MAT_SELECT_SCROLL_STRATEGY = new core.InjectionToken('mat-select-scroll-strategy');
  198. /**
  199. * \@docs-private
  200. * @param {?} overlay
  201. * @return {?}
  202. */
  203. function MAT_SELECT_SCROLL_STRATEGY_PROVIDER_FACTORY(overlay$$1) {
  204. return (/**
  205. * @return {?}
  206. */
  207. function () { return overlay$$1.scrollStrategies.reposition(); });
  208. }
  209. /**
  210. * \@docs-private
  211. * @type {?}
  212. */
  213. var MAT_SELECT_SCROLL_STRATEGY_PROVIDER = {
  214. provide: MAT_SELECT_SCROLL_STRATEGY,
  215. deps: [overlay.Overlay],
  216. useFactory: MAT_SELECT_SCROLL_STRATEGY_PROVIDER_FACTORY,
  217. };
  218. /**
  219. * Change event object that is emitted when the select value has changed.
  220. */
  221. var /**
  222. * Change event object that is emitted when the select value has changed.
  223. */
  224. MatSelectChange = /** @class */ (function () {
  225. function MatSelectChange(source, value) {
  226. this.source = source;
  227. this.value = value;
  228. }
  229. return MatSelectChange;
  230. }());
  231. // Boilerplate for applying mixins to MatSelect.
  232. /**
  233. * \@docs-private
  234. */
  235. var
  236. // Boilerplate for applying mixins to MatSelect.
  237. /**
  238. * \@docs-private
  239. */
  240. MatSelectBase = /** @class */ (function () {
  241. function MatSelectBase(_elementRef, _defaultErrorStateMatcher, _parentForm, _parentFormGroup, ngControl) {
  242. this._elementRef = _elementRef;
  243. this._defaultErrorStateMatcher = _defaultErrorStateMatcher;
  244. this._parentForm = _parentForm;
  245. this._parentFormGroup = _parentFormGroup;
  246. this.ngControl = ngControl;
  247. }
  248. return MatSelectBase;
  249. }());
  250. /** @type {?} */
  251. var _MatSelectMixinBase = core$1.mixinDisableRipple(core$1.mixinTabIndex(core$1.mixinDisabled(core$1.mixinErrorState(MatSelectBase))));
  252. /**
  253. * Allows the user to customize the trigger that is displayed when the select has a value.
  254. */
  255. var MatSelectTrigger = /** @class */ (function () {
  256. function MatSelectTrigger() {
  257. }
  258. MatSelectTrigger.decorators = [
  259. { type: core.Directive, args: [{
  260. selector: 'mat-select-trigger'
  261. },] },
  262. ];
  263. return MatSelectTrigger;
  264. }());
  265. var MatSelect = /** @class */ (function (_super) {
  266. __extends(MatSelect, _super);
  267. function MatSelect(_viewportRuler, _changeDetectorRef, _ngZone, _defaultErrorStateMatcher, elementRef, _dir, _parentForm, _parentFormGroup, _parentFormField, ngControl, tabIndex, scrollStrategyFactory, _liveAnnouncer) {
  268. var _this = _super.call(this, elementRef, _defaultErrorStateMatcher, _parentForm, _parentFormGroup, ngControl) || this;
  269. _this._viewportRuler = _viewportRuler;
  270. _this._changeDetectorRef = _changeDetectorRef;
  271. _this._ngZone = _ngZone;
  272. _this._dir = _dir;
  273. _this._parentFormField = _parentFormField;
  274. _this.ngControl = ngControl;
  275. _this._liveAnnouncer = _liveAnnouncer;
  276. /**
  277. * Whether or not the overlay panel is open.
  278. */
  279. _this._panelOpen = false;
  280. /**
  281. * Whether filling out the select is required in the form.
  282. */
  283. _this._required = false;
  284. /**
  285. * The scroll position of the overlay panel, calculated to center the selected option.
  286. */
  287. _this._scrollTop = 0;
  288. /**
  289. * Whether the component is in multiple selection mode.
  290. */
  291. _this._multiple = false;
  292. /**
  293. * Comparison function to specify which option is displayed. Defaults to object equality.
  294. */
  295. _this._compareWith = (/**
  296. * @param {?} o1
  297. * @param {?} o2
  298. * @return {?}
  299. */
  300. function (o1, o2) { return o1 === o2; });
  301. /**
  302. * Unique id for this input.
  303. */
  304. _this._uid = "mat-select-" + nextUniqueId++;
  305. /**
  306. * Emits whenever the component is destroyed.
  307. */
  308. _this._destroy = new rxjs.Subject();
  309. /**
  310. * The cached font-size of the trigger element.
  311. */
  312. _this._triggerFontSize = 0;
  313. /**
  314. * `View -> model callback called when value changes`
  315. */
  316. _this._onChange = (/**
  317. * @return {?}
  318. */
  319. function () { });
  320. /**
  321. * `View -> model callback called when select has been touched`
  322. */
  323. _this._onTouched = (/**
  324. * @return {?}
  325. */
  326. function () { });
  327. /**
  328. * The IDs of child options to be passed to the aria-owns attribute.
  329. */
  330. _this._optionIds = '';
  331. /**
  332. * The value of the select panel's transform-origin property.
  333. */
  334. _this._transformOrigin = 'top';
  335. /**
  336. * Emits when the panel element is finished transforming in.
  337. */
  338. _this._panelDoneAnimatingStream = new rxjs.Subject();
  339. /**
  340. * The y-offset of the overlay panel in relation to the trigger's top start corner.
  341. * This must be adjusted to align the selected option text over the trigger text.
  342. * when the panel opens. Will change based on the y-position of the selected option.
  343. */
  344. _this._offsetY = 0;
  345. /**
  346. * This position config ensures that the top "start" corner of the overlay
  347. * is aligned with with the top "start" of the origin by default (overlapping
  348. * the trigger completely). If the panel cannot fit below the trigger, it
  349. * will fall back to a position above the trigger.
  350. */
  351. _this._positions = [
  352. {
  353. originX: 'start',
  354. originY: 'top',
  355. overlayX: 'start',
  356. overlayY: 'top',
  357. },
  358. {
  359. originX: 'start',
  360. originY: 'bottom',
  361. overlayX: 'start',
  362. overlayY: 'bottom',
  363. },
  364. ];
  365. /**
  366. * Whether the component is disabling centering of the active option over the trigger.
  367. */
  368. _this._disableOptionCentering = false;
  369. _this._focused = false;
  370. /**
  371. * A name for this control that can be used by `mat-form-field`.
  372. */
  373. _this.controlType = 'mat-select';
  374. /**
  375. * Aria label of the select. If not specified, the placeholder will be used as label.
  376. */
  377. _this.ariaLabel = '';
  378. /**
  379. * Combined stream of all of the child options' change events.
  380. */
  381. _this.optionSelectionChanges = (/** @type {?} */ (rxjs.defer((/**
  382. * @return {?}
  383. */
  384. function () {
  385. /** @type {?} */
  386. var options = _this.options;
  387. if (options) {
  388. return options.changes.pipe(operators.startWith(options), operators.switchMap((/**
  389. * @return {?}
  390. */
  391. function () { return rxjs.merge.apply(void 0, options.map((/**
  392. * @param {?} option
  393. * @return {?}
  394. */
  395. function (option) { return option.onSelectionChange; }))); })));
  396. }
  397. return _this._ngZone.onStable
  398. .asObservable()
  399. .pipe(operators.take(1), operators.switchMap((/**
  400. * @return {?}
  401. */
  402. function () { return _this.optionSelectionChanges; })));
  403. }))));
  404. /**
  405. * Event emitted when the select panel has been toggled.
  406. */
  407. _this.openedChange = new core.EventEmitter();
  408. /**
  409. * Event emitted when the select has been opened.
  410. */
  411. _this._openedStream = _this.openedChange.pipe(operators.filter((/**
  412. * @param {?} o
  413. * @return {?}
  414. */
  415. function (o) { return o; })), operators.map((/**
  416. * @return {?}
  417. */
  418. function () { })));
  419. /**
  420. * Event emitted when the select has been closed.
  421. */
  422. _this._closedStream = _this.openedChange.pipe(operators.filter((/**
  423. * @param {?} o
  424. * @return {?}
  425. */
  426. function (o) { return !o; })), operators.map((/**
  427. * @return {?}
  428. */
  429. function () { })));
  430. /**
  431. * Event emitted when the selected value has been changed by the user.
  432. */
  433. _this.selectionChange = new core.EventEmitter();
  434. /**
  435. * Event that emits whenever the raw value of the select changes. This is here primarily
  436. * to facilitate the two-way binding for the `value` input.
  437. * \@docs-private
  438. */
  439. _this.valueChange = new core.EventEmitter();
  440. if (_this.ngControl) {
  441. // Note: we provide the value accessor through here, instead of
  442. // the `providers` to avoid running into a circular import.
  443. _this.ngControl.valueAccessor = _this;
  444. }
  445. _this._scrollStrategyFactory = scrollStrategyFactory;
  446. _this._scrollStrategy = _this._scrollStrategyFactory();
  447. _this.tabIndex = parseInt(tabIndex) || 0;
  448. // Force setter to be called in case id was not specified.
  449. _this.id = _this.id;
  450. return _this;
  451. }
  452. Object.defineProperty(MatSelect.prototype, "focused", {
  453. /** Whether the select is focused. */
  454. get: /**
  455. * Whether the select is focused.
  456. * @return {?}
  457. */
  458. function () {
  459. return this._focused || this._panelOpen;
  460. },
  461. /**
  462. * @deprecated Setter to be removed as this property is intended to be readonly.
  463. * @breaking-change 8.0.0
  464. */
  465. set: /**
  466. * @deprecated Setter to be removed as this property is intended to be readonly.
  467. * \@breaking-change 8.0.0
  468. * @param {?} value
  469. * @return {?}
  470. */
  471. function (value) {
  472. this._focused = value;
  473. },
  474. enumerable: true,
  475. configurable: true
  476. });
  477. Object.defineProperty(MatSelect.prototype, "placeholder", {
  478. /** Placeholder to be shown if no value has been selected. */
  479. get: /**
  480. * Placeholder to be shown if no value has been selected.
  481. * @return {?}
  482. */
  483. function () { return this._placeholder; },
  484. set: /**
  485. * @param {?} value
  486. * @return {?}
  487. */
  488. function (value) {
  489. this._placeholder = value;
  490. this.stateChanges.next();
  491. },
  492. enumerable: true,
  493. configurable: true
  494. });
  495. Object.defineProperty(MatSelect.prototype, "required", {
  496. /** Whether the component is required. */
  497. get: /**
  498. * Whether the component is required.
  499. * @return {?}
  500. */
  501. function () { return this._required; },
  502. set: /**
  503. * @param {?} value
  504. * @return {?}
  505. */
  506. function (value) {
  507. this._required = coercion.coerceBooleanProperty(value);
  508. this.stateChanges.next();
  509. },
  510. enumerable: true,
  511. configurable: true
  512. });
  513. Object.defineProperty(MatSelect.prototype, "multiple", {
  514. /** Whether the user should be allowed to select multiple options. */
  515. get: /**
  516. * Whether the user should be allowed to select multiple options.
  517. * @return {?}
  518. */
  519. function () { return this._multiple; },
  520. set: /**
  521. * @param {?} value
  522. * @return {?}
  523. */
  524. function (value) {
  525. if (this._selectionModel) {
  526. throw getMatSelectDynamicMultipleError();
  527. }
  528. this._multiple = coercion.coerceBooleanProperty(value);
  529. },
  530. enumerable: true,
  531. configurable: true
  532. });
  533. Object.defineProperty(MatSelect.prototype, "disableOptionCentering", {
  534. /** Whether to center the active option over the trigger. */
  535. get: /**
  536. * Whether to center the active option over the trigger.
  537. * @return {?}
  538. */
  539. function () { return this._disableOptionCentering; },
  540. set: /**
  541. * @param {?} value
  542. * @return {?}
  543. */
  544. function (value) {
  545. this._disableOptionCentering = coercion.coerceBooleanProperty(value);
  546. },
  547. enumerable: true,
  548. configurable: true
  549. });
  550. Object.defineProperty(MatSelect.prototype, "compareWith", {
  551. /**
  552. * Function to compare the option values with the selected values. The first argument
  553. * is a value from an option. The second is a value from the selection. A boolean
  554. * should be returned.
  555. */
  556. get: /**
  557. * Function to compare the option values with the selected values. The first argument
  558. * is a value from an option. The second is a value from the selection. A boolean
  559. * should be returned.
  560. * @return {?}
  561. */
  562. function () { return this._compareWith; },
  563. set: /**
  564. * @param {?} fn
  565. * @return {?}
  566. */
  567. function (fn) {
  568. if (typeof fn !== 'function') {
  569. throw getMatSelectNonFunctionValueError();
  570. }
  571. this._compareWith = fn;
  572. if (this._selectionModel) {
  573. // A different comparator means the selection could change.
  574. this._initializeSelection();
  575. }
  576. },
  577. enumerable: true,
  578. configurable: true
  579. });
  580. Object.defineProperty(MatSelect.prototype, "value", {
  581. /** Value of the select control. */
  582. get: /**
  583. * Value of the select control.
  584. * @return {?}
  585. */
  586. function () { return this._value; },
  587. set: /**
  588. * @param {?} newValue
  589. * @return {?}
  590. */
  591. function (newValue) {
  592. if (newValue !== this._value) {
  593. this.writeValue(newValue);
  594. this._value = newValue;
  595. }
  596. },
  597. enumerable: true,
  598. configurable: true
  599. });
  600. Object.defineProperty(MatSelect.prototype, "id", {
  601. /** Unique id of the element. */
  602. get: /**
  603. * Unique id of the element.
  604. * @return {?}
  605. */
  606. function () { return this._id; },
  607. set: /**
  608. * @param {?} value
  609. * @return {?}
  610. */
  611. function (value) {
  612. this._id = value || this._uid;
  613. this.stateChanges.next();
  614. },
  615. enumerable: true,
  616. configurable: true
  617. });
  618. /**
  619. * @return {?}
  620. */
  621. MatSelect.prototype.ngOnInit = /**
  622. * @return {?}
  623. */
  624. function () {
  625. var _this = this;
  626. this._selectionModel = new collections.SelectionModel(this.multiple);
  627. this.stateChanges.next();
  628. // We need `distinctUntilChanged` here, because some browsers will
  629. // fire the animation end event twice for the same animation. See:
  630. // https://github.com/angular/angular/issues/24084
  631. this._panelDoneAnimatingStream
  632. .pipe(operators.distinctUntilChanged(), operators.takeUntil(this._destroy))
  633. .subscribe((/**
  634. * @return {?}
  635. */
  636. function () {
  637. if (_this.panelOpen) {
  638. _this._scrollTop = 0;
  639. _this.openedChange.emit(true);
  640. }
  641. else {
  642. _this.openedChange.emit(false);
  643. _this.overlayDir.offsetX = 0;
  644. _this._changeDetectorRef.markForCheck();
  645. }
  646. }));
  647. this._viewportRuler.change()
  648. .pipe(operators.takeUntil(this._destroy))
  649. .subscribe((/**
  650. * @return {?}
  651. */
  652. function () {
  653. if (_this._panelOpen) {
  654. _this._triggerRect = _this.trigger.nativeElement.getBoundingClientRect();
  655. _this._changeDetectorRef.markForCheck();
  656. }
  657. }));
  658. };
  659. /**
  660. * @return {?}
  661. */
  662. MatSelect.prototype.ngAfterContentInit = /**
  663. * @return {?}
  664. */
  665. function () {
  666. var _this = this;
  667. this._initKeyManager();
  668. this._selectionModel.onChange.pipe(operators.takeUntil(this._destroy)).subscribe((/**
  669. * @param {?} event
  670. * @return {?}
  671. */
  672. function (event) {
  673. event.added.forEach((/**
  674. * @param {?} option
  675. * @return {?}
  676. */
  677. function (option) { return option.select(); }));
  678. event.removed.forEach((/**
  679. * @param {?} option
  680. * @return {?}
  681. */
  682. function (option) { return option.deselect(); }));
  683. }));
  684. this.options.changes.pipe(operators.startWith(null), operators.takeUntil(this._destroy)).subscribe((/**
  685. * @return {?}
  686. */
  687. function () {
  688. _this._resetOptions();
  689. _this._initializeSelection();
  690. }));
  691. };
  692. /**
  693. * @return {?}
  694. */
  695. MatSelect.prototype.ngDoCheck = /**
  696. * @return {?}
  697. */
  698. function () {
  699. if (this.ngControl) {
  700. this.updateErrorState();
  701. }
  702. };
  703. /**
  704. * @param {?} changes
  705. * @return {?}
  706. */
  707. MatSelect.prototype.ngOnChanges = /**
  708. * @param {?} changes
  709. * @return {?}
  710. */
  711. function (changes) {
  712. // Updating the disabled state is handled by `mixinDisabled`, but we need to additionally let
  713. // the parent form field know to run change detection when the disabled state changes.
  714. if (changes['disabled']) {
  715. this.stateChanges.next();
  716. }
  717. };
  718. /**
  719. * @return {?}
  720. */
  721. MatSelect.prototype.ngOnDestroy = /**
  722. * @return {?}
  723. */
  724. function () {
  725. this._destroy.next();
  726. this._destroy.complete();
  727. this.stateChanges.complete();
  728. };
  729. /** Toggles the overlay panel open or closed. */
  730. /**
  731. * Toggles the overlay panel open or closed.
  732. * @return {?}
  733. */
  734. MatSelect.prototype.toggle = /**
  735. * Toggles the overlay panel open or closed.
  736. * @return {?}
  737. */
  738. function () {
  739. this.panelOpen ? this.close() : this.open();
  740. };
  741. /** Opens the overlay panel. */
  742. /**
  743. * Opens the overlay panel.
  744. * @return {?}
  745. */
  746. MatSelect.prototype.open = /**
  747. * Opens the overlay panel.
  748. * @return {?}
  749. */
  750. function () {
  751. var _this = this;
  752. if (this.disabled || !this.options || !this.options.length || this._panelOpen) {
  753. return;
  754. }
  755. this._triggerRect = this.trigger.nativeElement.getBoundingClientRect();
  756. // Note: The computed font-size will be a string pixel value (e.g. "16px").
  757. // `parseInt` ignores the trailing 'px' and converts this to a number.
  758. this._triggerFontSize = parseInt(getComputedStyle(this.trigger.nativeElement).fontSize || '0');
  759. this._panelOpen = true;
  760. this._keyManager.withHorizontalOrientation(null);
  761. this._calculateOverlayPosition();
  762. this._highlightCorrectOption();
  763. this._changeDetectorRef.markForCheck();
  764. // Set the font size on the panel element once it exists.
  765. this._ngZone.onStable.asObservable().pipe(operators.take(1)).subscribe((/**
  766. * @return {?}
  767. */
  768. function () {
  769. if (_this._triggerFontSize && _this.overlayDir.overlayRef &&
  770. _this.overlayDir.overlayRef.overlayElement) {
  771. _this.overlayDir.overlayRef.overlayElement.style.fontSize = _this._triggerFontSize + "px";
  772. }
  773. }));
  774. };
  775. /** Closes the overlay panel and focuses the host element. */
  776. /**
  777. * Closes the overlay panel and focuses the host element.
  778. * @return {?}
  779. */
  780. MatSelect.prototype.close = /**
  781. * Closes the overlay panel and focuses the host element.
  782. * @return {?}
  783. */
  784. function () {
  785. if (this._panelOpen) {
  786. this._panelOpen = false;
  787. this._keyManager.withHorizontalOrientation(this._isRtl() ? 'rtl' : 'ltr');
  788. this._changeDetectorRef.markForCheck();
  789. this._onTouched();
  790. }
  791. };
  792. /**
  793. * Sets the select's value. Part of the ControlValueAccessor interface
  794. * required to integrate with Angular's core forms API.
  795. *
  796. * @param value New value to be written to the model.
  797. */
  798. /**
  799. * Sets the select's value. Part of the ControlValueAccessor interface
  800. * required to integrate with Angular's core forms API.
  801. *
  802. * @param {?} value New value to be written to the model.
  803. * @return {?}
  804. */
  805. MatSelect.prototype.writeValue = /**
  806. * Sets the select's value. Part of the ControlValueAccessor interface
  807. * required to integrate with Angular's core forms API.
  808. *
  809. * @param {?} value New value to be written to the model.
  810. * @return {?}
  811. */
  812. function (value) {
  813. if (this.options) {
  814. this._setSelectionByValue(value);
  815. }
  816. };
  817. /**
  818. * Saves a callback function to be invoked when the select's value
  819. * changes from user input. Part of the ControlValueAccessor interface
  820. * required to integrate with Angular's core forms API.
  821. *
  822. * @param fn Callback to be triggered when the value changes.
  823. */
  824. /**
  825. * Saves a callback function to be invoked when the select's value
  826. * changes from user input. Part of the ControlValueAccessor interface
  827. * required to integrate with Angular's core forms API.
  828. *
  829. * @param {?} fn Callback to be triggered when the value changes.
  830. * @return {?}
  831. */
  832. MatSelect.prototype.registerOnChange = /**
  833. * Saves a callback function to be invoked when the select's value
  834. * changes from user input. Part of the ControlValueAccessor interface
  835. * required to integrate with Angular's core forms API.
  836. *
  837. * @param {?} fn Callback to be triggered when the value changes.
  838. * @return {?}
  839. */
  840. function (fn) {
  841. this._onChange = fn;
  842. };
  843. /**
  844. * Saves a callback function to be invoked when the select is blurred
  845. * by the user. Part of the ControlValueAccessor interface required
  846. * to integrate with Angular's core forms API.
  847. *
  848. * @param fn Callback to be triggered when the component has been touched.
  849. */
  850. /**
  851. * Saves a callback function to be invoked when the select is blurred
  852. * by the user. Part of the ControlValueAccessor interface required
  853. * to integrate with Angular's core forms API.
  854. *
  855. * @param {?} fn Callback to be triggered when the component has been touched.
  856. * @return {?}
  857. */
  858. MatSelect.prototype.registerOnTouched = /**
  859. * Saves a callback function to be invoked when the select is blurred
  860. * by the user. Part of the ControlValueAccessor interface required
  861. * to integrate with Angular's core forms API.
  862. *
  863. * @param {?} fn Callback to be triggered when the component has been touched.
  864. * @return {?}
  865. */
  866. function (fn) {
  867. this._onTouched = fn;
  868. };
  869. /**
  870. * Disables the select. Part of the ControlValueAccessor interface required
  871. * to integrate with Angular's core forms API.
  872. *
  873. * @param isDisabled Sets whether the component is disabled.
  874. */
  875. /**
  876. * Disables the select. Part of the ControlValueAccessor interface required
  877. * to integrate with Angular's core forms API.
  878. *
  879. * @param {?} isDisabled Sets whether the component is disabled.
  880. * @return {?}
  881. */
  882. MatSelect.prototype.setDisabledState = /**
  883. * Disables the select. Part of the ControlValueAccessor interface required
  884. * to integrate with Angular's core forms API.
  885. *
  886. * @param {?} isDisabled Sets whether the component is disabled.
  887. * @return {?}
  888. */
  889. function (isDisabled) {
  890. this.disabled = isDisabled;
  891. this._changeDetectorRef.markForCheck();
  892. this.stateChanges.next();
  893. };
  894. Object.defineProperty(MatSelect.prototype, "panelOpen", {
  895. /** Whether or not the overlay panel is open. */
  896. get: /**
  897. * Whether or not the overlay panel is open.
  898. * @return {?}
  899. */
  900. function () {
  901. return this._panelOpen;
  902. },
  903. enumerable: true,
  904. configurable: true
  905. });
  906. Object.defineProperty(MatSelect.prototype, "selected", {
  907. /** The currently selected option. */
  908. get: /**
  909. * The currently selected option.
  910. * @return {?}
  911. */
  912. function () {
  913. return this.multiple ? this._selectionModel.selected : this._selectionModel.selected[0];
  914. },
  915. enumerable: true,
  916. configurable: true
  917. });
  918. Object.defineProperty(MatSelect.prototype, "triggerValue", {
  919. /** The value displayed in the trigger. */
  920. get: /**
  921. * The value displayed in the trigger.
  922. * @return {?}
  923. */
  924. function () {
  925. if (this.empty) {
  926. return '';
  927. }
  928. if (this._multiple) {
  929. /** @type {?} */
  930. var selectedOptions = this._selectionModel.selected.map((/**
  931. * @param {?} option
  932. * @return {?}
  933. */
  934. function (option) { return option.viewValue; }));
  935. if (this._isRtl()) {
  936. selectedOptions.reverse();
  937. }
  938. // TODO(crisbeto): delimiter should be configurable for proper localization.
  939. return selectedOptions.join(', ');
  940. }
  941. return this._selectionModel.selected[0].viewValue;
  942. },
  943. enumerable: true,
  944. configurable: true
  945. });
  946. /** Whether the element is in RTL mode. */
  947. /**
  948. * Whether the element is in RTL mode.
  949. * @return {?}
  950. */
  951. MatSelect.prototype._isRtl = /**
  952. * Whether the element is in RTL mode.
  953. * @return {?}
  954. */
  955. function () {
  956. return this._dir ? this._dir.value === 'rtl' : false;
  957. };
  958. /** Handles all keydown events on the select. */
  959. /**
  960. * Handles all keydown events on the select.
  961. * @param {?} event
  962. * @return {?}
  963. */
  964. MatSelect.prototype._handleKeydown = /**
  965. * Handles all keydown events on the select.
  966. * @param {?} event
  967. * @return {?}
  968. */
  969. function (event) {
  970. if (!this.disabled) {
  971. this.panelOpen ? this._handleOpenKeydown(event) : this._handleClosedKeydown(event);
  972. }
  973. };
  974. /** Handles keyboard events while the select is closed. */
  975. /**
  976. * Handles keyboard events while the select is closed.
  977. * @private
  978. * @param {?} event
  979. * @return {?}
  980. */
  981. MatSelect.prototype._handleClosedKeydown = /**
  982. * Handles keyboard events while the select is closed.
  983. * @private
  984. * @param {?} event
  985. * @return {?}
  986. */
  987. function (event) {
  988. /** @type {?} */
  989. var keyCode = event.keyCode;
  990. /** @type {?} */
  991. var isArrowKey = keyCode === keycodes.DOWN_ARROW || keyCode === keycodes.UP_ARROW ||
  992. keyCode === keycodes.LEFT_ARROW || keyCode === keycodes.RIGHT_ARROW;
  993. /** @type {?} */
  994. var isOpenKey = keyCode === keycodes.ENTER || keyCode === keycodes.SPACE;
  995. /** @type {?} */
  996. var manager = this._keyManager;
  997. // Open the select on ALT + arrow key to match the native <select>
  998. if ((isOpenKey && !keycodes.hasModifierKey(event)) || ((this.multiple || event.altKey) && isArrowKey)) {
  999. event.preventDefault(); // prevents the page from scrolling down when pressing space
  1000. this.open();
  1001. }
  1002. else if (!this.multiple) {
  1003. /** @type {?} */
  1004. var previouslySelectedOption = this.selected;
  1005. if (keyCode === keycodes.HOME || keyCode === keycodes.END) {
  1006. keyCode === keycodes.HOME ? manager.setFirstItemActive() : manager.setLastItemActive();
  1007. event.preventDefault();
  1008. }
  1009. else {
  1010. manager.onKeydown(event);
  1011. }
  1012. /** @type {?} */
  1013. var selectedOption = this.selected;
  1014. // Since the value has changed, we need to announce it ourselves.
  1015. // @breaking-change 8.0.0 remove null check for _liveAnnouncer.
  1016. if (this._liveAnnouncer && selectedOption && previouslySelectedOption !== selectedOption) {
  1017. // We set a duration on the live announcement, because we want the live element to be
  1018. // cleared after a while so that users can't navigate to it using the arrow keys.
  1019. this._liveAnnouncer.announce(((/** @type {?} */ (selectedOption))).viewValue, 10000);
  1020. }
  1021. }
  1022. };
  1023. /** Handles keyboard events when the selected is open. */
  1024. /**
  1025. * Handles keyboard events when the selected is open.
  1026. * @private
  1027. * @param {?} event
  1028. * @return {?}
  1029. */
  1030. MatSelect.prototype._handleOpenKeydown = /**
  1031. * Handles keyboard events when the selected is open.
  1032. * @private
  1033. * @param {?} event
  1034. * @return {?}
  1035. */
  1036. function (event) {
  1037. /** @type {?} */
  1038. var keyCode = event.keyCode;
  1039. /** @type {?} */
  1040. var isArrowKey = keyCode === keycodes.DOWN_ARROW || keyCode === keycodes.UP_ARROW;
  1041. /** @type {?} */
  1042. var manager = this._keyManager;
  1043. if (keyCode === keycodes.HOME || keyCode === keycodes.END) {
  1044. event.preventDefault();
  1045. keyCode === keycodes.HOME ? manager.setFirstItemActive() : manager.setLastItemActive();
  1046. }
  1047. else if (isArrowKey && event.altKey) {
  1048. // Close the select on ALT + arrow key to match the native <select>
  1049. event.preventDefault();
  1050. this.close();
  1051. }
  1052. else if ((keyCode === keycodes.ENTER || keyCode === keycodes.SPACE) && manager.activeItem &&
  1053. !keycodes.hasModifierKey(event)) {
  1054. event.preventDefault();
  1055. manager.activeItem._selectViaInteraction();
  1056. }
  1057. else if (this._multiple && keyCode === keycodes.A && event.ctrlKey) {
  1058. event.preventDefault();
  1059. /** @type {?} */
  1060. var hasDeselectedOptions_1 = this.options.some((/**
  1061. * @param {?} opt
  1062. * @return {?}
  1063. */
  1064. function (opt) { return !opt.disabled && !opt.selected; }));
  1065. this.options.forEach((/**
  1066. * @param {?} option
  1067. * @return {?}
  1068. */
  1069. function (option) {
  1070. if (!option.disabled) {
  1071. hasDeselectedOptions_1 ? option.select() : option.deselect();
  1072. }
  1073. }));
  1074. }
  1075. else {
  1076. /** @type {?} */
  1077. var previouslyFocusedIndex = manager.activeItemIndex;
  1078. manager.onKeydown(event);
  1079. if (this._multiple && isArrowKey && event.shiftKey && manager.activeItem &&
  1080. manager.activeItemIndex !== previouslyFocusedIndex) {
  1081. manager.activeItem._selectViaInteraction();
  1082. }
  1083. }
  1084. };
  1085. /**
  1086. * @return {?}
  1087. */
  1088. MatSelect.prototype._onFocus = /**
  1089. * @return {?}
  1090. */
  1091. function () {
  1092. if (!this.disabled) {
  1093. this._focused = true;
  1094. this.stateChanges.next();
  1095. }
  1096. };
  1097. /**
  1098. * Calls the touched callback only if the panel is closed. Otherwise, the trigger will
  1099. * "blur" to the panel when it opens, causing a false positive.
  1100. */
  1101. /**
  1102. * Calls the touched callback only if the panel is closed. Otherwise, the trigger will
  1103. * "blur" to the panel when it opens, causing a false positive.
  1104. * @return {?}
  1105. */
  1106. MatSelect.prototype._onBlur = /**
  1107. * Calls the touched callback only if the panel is closed. Otherwise, the trigger will
  1108. * "blur" to the panel when it opens, causing a false positive.
  1109. * @return {?}
  1110. */
  1111. function () {
  1112. this._focused = false;
  1113. if (!this.disabled && !this.panelOpen) {
  1114. this._onTouched();
  1115. this._changeDetectorRef.markForCheck();
  1116. this.stateChanges.next();
  1117. }
  1118. };
  1119. /**
  1120. * Callback that is invoked when the overlay panel has been attached.
  1121. */
  1122. /**
  1123. * Callback that is invoked when the overlay panel has been attached.
  1124. * @return {?}
  1125. */
  1126. MatSelect.prototype._onAttached = /**
  1127. * Callback that is invoked when the overlay panel has been attached.
  1128. * @return {?}
  1129. */
  1130. function () {
  1131. var _this = this;
  1132. this.overlayDir.positionChange.pipe(operators.take(1)).subscribe((/**
  1133. * @return {?}
  1134. */
  1135. function () {
  1136. _this._changeDetectorRef.detectChanges();
  1137. _this._calculateOverlayOffsetX();
  1138. _this.panel.nativeElement.scrollTop = _this._scrollTop;
  1139. }));
  1140. };
  1141. /** Returns the theme to be used on the panel. */
  1142. /**
  1143. * Returns the theme to be used on the panel.
  1144. * @return {?}
  1145. */
  1146. MatSelect.prototype._getPanelTheme = /**
  1147. * Returns the theme to be used on the panel.
  1148. * @return {?}
  1149. */
  1150. function () {
  1151. return this._parentFormField ? "mat-" + this._parentFormField.color : '';
  1152. };
  1153. Object.defineProperty(MatSelect.prototype, "empty", {
  1154. /** Whether the select has a value. */
  1155. get: /**
  1156. * Whether the select has a value.
  1157. * @return {?}
  1158. */
  1159. function () {
  1160. return !this._selectionModel || this._selectionModel.isEmpty();
  1161. },
  1162. enumerable: true,
  1163. configurable: true
  1164. });
  1165. /**
  1166. * @private
  1167. * @return {?}
  1168. */
  1169. MatSelect.prototype._initializeSelection = /**
  1170. * @private
  1171. * @return {?}
  1172. */
  1173. function () {
  1174. var _this = this;
  1175. // Defer setting the value in order to avoid the "Expression
  1176. // has changed after it was checked" errors from Angular.
  1177. Promise.resolve().then((/**
  1178. * @return {?}
  1179. */
  1180. function () {
  1181. _this._setSelectionByValue(_this.ngControl ? _this.ngControl.value : _this._value);
  1182. _this.stateChanges.next();
  1183. }));
  1184. };
  1185. /**
  1186. * Sets the selected option based on a value. If no option can be
  1187. * found with the designated value, the select trigger is cleared.
  1188. */
  1189. /**
  1190. * Sets the selected option based on a value. If no option can be
  1191. * found with the designated value, the select trigger is cleared.
  1192. * @private
  1193. * @param {?} value
  1194. * @return {?}
  1195. */
  1196. MatSelect.prototype._setSelectionByValue = /**
  1197. * Sets the selected option based on a value. If no option can be
  1198. * found with the designated value, the select trigger is cleared.
  1199. * @private
  1200. * @param {?} value
  1201. * @return {?}
  1202. */
  1203. function (value) {
  1204. var _this = this;
  1205. if (this.multiple && value) {
  1206. if (!Array.isArray(value)) {
  1207. throw getMatSelectNonArrayValueError();
  1208. }
  1209. this._selectionModel.clear();
  1210. value.forEach((/**
  1211. * @param {?} currentValue
  1212. * @return {?}
  1213. */
  1214. function (currentValue) { return _this._selectValue(currentValue); }));
  1215. this._sortValues();
  1216. }
  1217. else {
  1218. this._selectionModel.clear();
  1219. /** @type {?} */
  1220. var correspondingOption = this._selectValue(value);
  1221. // Shift focus to the active item. Note that we shouldn't do this in multiple
  1222. // mode, because we don't know what option the user interacted with last.
  1223. if (correspondingOption) {
  1224. this._keyManager.setActiveItem(correspondingOption);
  1225. }
  1226. }
  1227. this._changeDetectorRef.markForCheck();
  1228. };
  1229. /**
  1230. * Finds and selects and option based on its value.
  1231. * @returns Option that has the corresponding value.
  1232. */
  1233. /**
  1234. * Finds and selects and option based on its value.
  1235. * @private
  1236. * @param {?} value
  1237. * @return {?} Option that has the corresponding value.
  1238. */
  1239. MatSelect.prototype._selectValue = /**
  1240. * Finds and selects and option based on its value.
  1241. * @private
  1242. * @param {?} value
  1243. * @return {?} Option that has the corresponding value.
  1244. */
  1245. function (value) {
  1246. var _this = this;
  1247. /** @type {?} */
  1248. var correspondingOption = this.options.find((/**
  1249. * @param {?} option
  1250. * @return {?}
  1251. */
  1252. function (option) {
  1253. try {
  1254. // Treat null as a special reset value.
  1255. return option.value != null && _this._compareWith(option.value, value);
  1256. }
  1257. catch (error) {
  1258. if (core.isDevMode()) {
  1259. // Notify developers of errors in their comparator.
  1260. console.warn(error);
  1261. }
  1262. return false;
  1263. }
  1264. }));
  1265. if (correspondingOption) {
  1266. this._selectionModel.select(correspondingOption);
  1267. }
  1268. return correspondingOption;
  1269. };
  1270. /** Sets up a key manager to listen to keyboard events on the overlay panel. */
  1271. /**
  1272. * Sets up a key manager to listen to keyboard events on the overlay panel.
  1273. * @private
  1274. * @return {?}
  1275. */
  1276. MatSelect.prototype._initKeyManager = /**
  1277. * Sets up a key manager to listen to keyboard events on the overlay panel.
  1278. * @private
  1279. * @return {?}
  1280. */
  1281. function () {
  1282. var _this = this;
  1283. this._keyManager = new a11y.ActiveDescendantKeyManager(this.options)
  1284. .withTypeAhead()
  1285. .withVerticalOrientation()
  1286. .withHorizontalOrientation(this._isRtl() ? 'rtl' : 'ltr')
  1287. .withAllowedModifierKeys(['shiftKey']);
  1288. this._keyManager.tabOut.pipe(operators.takeUntil(this._destroy)).subscribe((/**
  1289. * @return {?}
  1290. */
  1291. function () {
  1292. // Restore focus to the trigger before closing. Ensures that the focus
  1293. // position won't be lost if the user got focus into the overlay.
  1294. _this.focus();
  1295. _this.close();
  1296. }));
  1297. this._keyManager.change.pipe(operators.takeUntil(this._destroy)).subscribe((/**
  1298. * @return {?}
  1299. */
  1300. function () {
  1301. if (_this._panelOpen && _this.panel) {
  1302. _this._scrollActiveOptionIntoView();
  1303. }
  1304. else if (!_this._panelOpen && !_this.multiple && _this._keyManager.activeItem) {
  1305. _this._keyManager.activeItem._selectViaInteraction();
  1306. }
  1307. }));
  1308. };
  1309. /** Drops current option subscriptions and IDs and resets from scratch. */
  1310. /**
  1311. * Drops current option subscriptions and IDs and resets from scratch.
  1312. * @private
  1313. * @return {?}
  1314. */
  1315. MatSelect.prototype._resetOptions = /**
  1316. * Drops current option subscriptions and IDs and resets from scratch.
  1317. * @private
  1318. * @return {?}
  1319. */
  1320. function () {
  1321. var _this = this;
  1322. /** @type {?} */
  1323. var changedOrDestroyed = rxjs.merge(this.options.changes, this._destroy);
  1324. this.optionSelectionChanges.pipe(operators.takeUntil(changedOrDestroyed)).subscribe((/**
  1325. * @param {?} event
  1326. * @return {?}
  1327. */
  1328. function (event) {
  1329. _this._onSelect(event.source, event.isUserInput);
  1330. if (event.isUserInput && !_this.multiple && _this._panelOpen) {
  1331. _this.close();
  1332. _this.focus();
  1333. }
  1334. }));
  1335. // Listen to changes in the internal state of the options and react accordingly.
  1336. // Handles cases like the labels of the selected options changing.
  1337. rxjs.merge.apply(void 0, this.options.map((/**
  1338. * @param {?} option
  1339. * @return {?}
  1340. */
  1341. function (option) { return option._stateChanges; }))).pipe(operators.takeUntil(changedOrDestroyed))
  1342. .subscribe((/**
  1343. * @return {?}
  1344. */
  1345. function () {
  1346. _this._changeDetectorRef.markForCheck();
  1347. _this.stateChanges.next();
  1348. }));
  1349. this._setOptionIds();
  1350. };
  1351. /** Invoked when an option is clicked. */
  1352. /**
  1353. * Invoked when an option is clicked.
  1354. * @private
  1355. * @param {?} option
  1356. * @param {?} isUserInput
  1357. * @return {?}
  1358. */
  1359. MatSelect.prototype._onSelect = /**
  1360. * Invoked when an option is clicked.
  1361. * @private
  1362. * @param {?} option
  1363. * @param {?} isUserInput
  1364. * @return {?}
  1365. */
  1366. function (option, isUserInput) {
  1367. /** @type {?} */
  1368. var wasSelected = this._selectionModel.isSelected(option);
  1369. if (option.value == null && !this._multiple) {
  1370. option.deselect();
  1371. this._selectionModel.clear();
  1372. this._propagateChanges(option.value);
  1373. }
  1374. else {
  1375. option.selected ? this._selectionModel.select(option) : this._selectionModel.deselect(option);
  1376. if (isUserInput) {
  1377. this._keyManager.setActiveItem(option);
  1378. }
  1379. if (this.multiple) {
  1380. this._sortValues();
  1381. if (isUserInput) {
  1382. // In case the user selected the option with their mouse, we
  1383. // want to restore focus back to the trigger, in order to
  1384. // prevent the select keyboard controls from clashing with
  1385. // the ones from `mat-option`.
  1386. this.focus();
  1387. }
  1388. }
  1389. }
  1390. if (wasSelected !== this._selectionModel.isSelected(option)) {
  1391. this._propagateChanges();
  1392. }
  1393. this.stateChanges.next();
  1394. };
  1395. /** Sorts the selected values in the selected based on their order in the panel. */
  1396. /**
  1397. * Sorts the selected values in the selected based on their order in the panel.
  1398. * @private
  1399. * @return {?}
  1400. */
  1401. MatSelect.prototype._sortValues = /**
  1402. * Sorts the selected values in the selected based on their order in the panel.
  1403. * @private
  1404. * @return {?}
  1405. */
  1406. function () {
  1407. var _this = this;
  1408. if (this.multiple) {
  1409. /** @type {?} */
  1410. var options_1 = this.options.toArray();
  1411. this._selectionModel.sort((/**
  1412. * @param {?} a
  1413. * @param {?} b
  1414. * @return {?}
  1415. */
  1416. function (a, b) {
  1417. return _this.sortComparator ? _this.sortComparator(a, b, options_1) :
  1418. options_1.indexOf(a) - options_1.indexOf(b);
  1419. }));
  1420. this.stateChanges.next();
  1421. }
  1422. };
  1423. /** Emits change event to set the model value. */
  1424. /**
  1425. * Emits change event to set the model value.
  1426. * @private
  1427. * @param {?=} fallbackValue
  1428. * @return {?}
  1429. */
  1430. MatSelect.prototype._propagateChanges = /**
  1431. * Emits change event to set the model value.
  1432. * @private
  1433. * @param {?=} fallbackValue
  1434. * @return {?}
  1435. */
  1436. function (fallbackValue) {
  1437. /** @type {?} */
  1438. var valueToEmit = null;
  1439. if (this.multiple) {
  1440. valueToEmit = ((/** @type {?} */ (this.selected))).map((/**
  1441. * @param {?} option
  1442. * @return {?}
  1443. */
  1444. function (option) { return option.value; }));
  1445. }
  1446. else {
  1447. valueToEmit = this.selected ? ((/** @type {?} */ (this.selected))).value : fallbackValue;
  1448. }
  1449. this._value = valueToEmit;
  1450. this.valueChange.emit(valueToEmit);
  1451. this._onChange(valueToEmit);
  1452. this.selectionChange.emit(new MatSelectChange(this, valueToEmit));
  1453. this._changeDetectorRef.markForCheck();
  1454. };
  1455. /** Records option IDs to pass to the aria-owns property. */
  1456. /**
  1457. * Records option IDs to pass to the aria-owns property.
  1458. * @private
  1459. * @return {?}
  1460. */
  1461. MatSelect.prototype._setOptionIds = /**
  1462. * Records option IDs to pass to the aria-owns property.
  1463. * @private
  1464. * @return {?}
  1465. */
  1466. function () {
  1467. this._optionIds = this.options.map((/**
  1468. * @param {?} option
  1469. * @return {?}
  1470. */
  1471. function (option) { return option.id; })).join(' ');
  1472. };
  1473. /**
  1474. * Highlights the selected item. If no option is selected, it will highlight
  1475. * the first item instead.
  1476. */
  1477. /**
  1478. * Highlights the selected item. If no option is selected, it will highlight
  1479. * the first item instead.
  1480. * @private
  1481. * @return {?}
  1482. */
  1483. MatSelect.prototype._highlightCorrectOption = /**
  1484. * Highlights the selected item. If no option is selected, it will highlight
  1485. * the first item instead.
  1486. * @private
  1487. * @return {?}
  1488. */
  1489. function () {
  1490. if (this._keyManager) {
  1491. if (this.empty) {
  1492. this._keyManager.setFirstItemActive();
  1493. }
  1494. else {
  1495. this._keyManager.setActiveItem(this._selectionModel.selected[0]);
  1496. }
  1497. }
  1498. };
  1499. /** Scrolls the active option into view. */
  1500. /**
  1501. * Scrolls the active option into view.
  1502. * @private
  1503. * @return {?}
  1504. */
  1505. MatSelect.prototype._scrollActiveOptionIntoView = /**
  1506. * Scrolls the active option into view.
  1507. * @private
  1508. * @return {?}
  1509. */
  1510. function () {
  1511. /** @type {?} */
  1512. var activeOptionIndex = this._keyManager.activeItemIndex || 0;
  1513. /** @type {?} */
  1514. var labelCount = core$1._countGroupLabelsBeforeOption(activeOptionIndex, this.options, this.optionGroups);
  1515. this.panel.nativeElement.scrollTop = core$1._getOptionScrollPosition(activeOptionIndex + labelCount, this._getItemHeight(), this.panel.nativeElement.scrollTop, SELECT_PANEL_MAX_HEIGHT);
  1516. };
  1517. /** Focuses the select element. */
  1518. /**
  1519. * Focuses the select element.
  1520. * @param {?=} options
  1521. * @return {?}
  1522. */
  1523. MatSelect.prototype.focus = /**
  1524. * Focuses the select element.
  1525. * @param {?=} options
  1526. * @return {?}
  1527. */
  1528. function (options) {
  1529. this._elementRef.nativeElement.focus(options);
  1530. };
  1531. /** Gets the index of the provided option in the option list. */
  1532. /**
  1533. * Gets the index of the provided option in the option list.
  1534. * @private
  1535. * @param {?} option
  1536. * @return {?}
  1537. */
  1538. MatSelect.prototype._getOptionIndex = /**
  1539. * Gets the index of the provided option in the option list.
  1540. * @private
  1541. * @param {?} option
  1542. * @return {?}
  1543. */
  1544. function (option) {
  1545. return this.options.reduce((/**
  1546. * @param {?} result
  1547. * @param {?} current
  1548. * @param {?} index
  1549. * @return {?}
  1550. */
  1551. function (result, current, index) {
  1552. return result === undefined ? (option === current ? index : undefined) : result;
  1553. }), undefined);
  1554. };
  1555. /** Calculates the scroll position and x- and y-offsets of the overlay panel. */
  1556. /**
  1557. * Calculates the scroll position and x- and y-offsets of the overlay panel.
  1558. * @private
  1559. * @return {?}
  1560. */
  1561. MatSelect.prototype._calculateOverlayPosition = /**
  1562. * Calculates the scroll position and x- and y-offsets of the overlay panel.
  1563. * @private
  1564. * @return {?}
  1565. */
  1566. function () {
  1567. /** @type {?} */
  1568. var itemHeight = this._getItemHeight();
  1569. /** @type {?} */
  1570. var items = this._getItemCount();
  1571. /** @type {?} */
  1572. var panelHeight = Math.min(items * itemHeight, SELECT_PANEL_MAX_HEIGHT);
  1573. /** @type {?} */
  1574. var scrollContainerHeight = items * itemHeight;
  1575. // The farthest the panel can be scrolled before it hits the bottom
  1576. /** @type {?} */
  1577. var maxScroll = scrollContainerHeight - panelHeight;
  1578. // If no value is selected we open the popup to the first item.
  1579. /** @type {?} */
  1580. var selectedOptionOffset = this.empty ? 0 : (/** @type {?} */ (this._getOptionIndex(this._selectionModel.selected[0])));
  1581. selectedOptionOffset += core$1._countGroupLabelsBeforeOption(selectedOptionOffset, this.options, this.optionGroups);
  1582. // We must maintain a scroll buffer so the selected option will be scrolled to the
  1583. // center of the overlay panel rather than the top.
  1584. /** @type {?} */
  1585. var scrollBuffer = panelHeight / 2;
  1586. this._scrollTop = this._calculateOverlayScroll(selectedOptionOffset, scrollBuffer, maxScroll);
  1587. this._offsetY = this._calculateOverlayOffsetY(selectedOptionOffset, scrollBuffer, maxScroll);
  1588. this._checkOverlayWithinViewport(maxScroll);
  1589. };
  1590. /**
  1591. * Calculates the scroll position of the select's overlay panel.
  1592. *
  1593. * Attempts to center the selected option in the panel. If the option is
  1594. * too high or too low in the panel to be scrolled to the center, it clamps the
  1595. * scroll position to the min or max scroll positions respectively.
  1596. */
  1597. /**
  1598. * Calculates the scroll position of the select's overlay panel.
  1599. *
  1600. * Attempts to center the selected option in the panel. If the option is
  1601. * too high or too low in the panel to be scrolled to the center, it clamps the
  1602. * scroll position to the min or max scroll positions respectively.
  1603. * @param {?} selectedIndex
  1604. * @param {?} scrollBuffer
  1605. * @param {?} maxScroll
  1606. * @return {?}
  1607. */
  1608. MatSelect.prototype._calculateOverlayScroll = /**
  1609. * Calculates the scroll position of the select's overlay panel.
  1610. *
  1611. * Attempts to center the selected option in the panel. If the option is
  1612. * too high or too low in the panel to be scrolled to the center, it clamps the
  1613. * scroll position to the min or max scroll positions respectively.
  1614. * @param {?} selectedIndex
  1615. * @param {?} scrollBuffer
  1616. * @param {?} maxScroll
  1617. * @return {?}
  1618. */
  1619. function (selectedIndex, scrollBuffer, maxScroll) {
  1620. /** @type {?} */
  1621. var itemHeight = this._getItemHeight();
  1622. /** @type {?} */
  1623. var optionOffsetFromScrollTop = itemHeight * selectedIndex;
  1624. /** @type {?} */
  1625. var halfOptionHeight = itemHeight / 2;
  1626. // Starts at the optionOffsetFromScrollTop, which scrolls the option to the top of the
  1627. // scroll container, then subtracts the scroll buffer to scroll the option down to
  1628. // the center of the overlay panel. Half the option height must be re-added to the
  1629. // scrollTop so the option is centered based on its middle, not its top edge.
  1630. /** @type {?} */
  1631. var optimalScrollPosition = optionOffsetFromScrollTop - scrollBuffer + halfOptionHeight;
  1632. return Math.min(Math.max(0, optimalScrollPosition), maxScroll);
  1633. };
  1634. /** Returns the aria-label of the select component. */
  1635. /**
  1636. * Returns the aria-label of the select component.
  1637. * @return {?}
  1638. */
  1639. MatSelect.prototype._getAriaLabel = /**
  1640. * Returns the aria-label of the select component.
  1641. * @return {?}
  1642. */
  1643. function () {
  1644. // If an ariaLabelledby value has been set by the consumer, the select should not overwrite the
  1645. // `aria-labelledby` value by setting the ariaLabel to the placeholder.
  1646. return this.ariaLabelledby ? null : this.ariaLabel || this.placeholder;
  1647. };
  1648. /** Returns the aria-labelledby of the select component. */
  1649. /**
  1650. * Returns the aria-labelledby of the select component.
  1651. * @return {?}
  1652. */
  1653. MatSelect.prototype._getAriaLabelledby = /**
  1654. * Returns the aria-labelledby of the select component.
  1655. * @return {?}
  1656. */
  1657. function () {
  1658. if (this.ariaLabelledby) {
  1659. return this.ariaLabelledby;
  1660. }
  1661. // Note: we use `_getAriaLabel` here, because we want to check whether there's a
  1662. // computed label. `this.ariaLabel` is only the user-specified label.
  1663. if (!this._parentFormField || !this._parentFormField._hasFloatingLabel() ||
  1664. this._getAriaLabel()) {
  1665. return null;
  1666. }
  1667. return this._parentFormField._labelId || null;
  1668. };
  1669. /** Determines the `aria-activedescendant` to be set on the host. */
  1670. /**
  1671. * Determines the `aria-activedescendant` to be set on the host.
  1672. * @return {?}
  1673. */
  1674. MatSelect.prototype._getAriaActiveDescendant = /**
  1675. * Determines the `aria-activedescendant` to be set on the host.
  1676. * @return {?}
  1677. */
  1678. function () {
  1679. if (this.panelOpen && this._keyManager && this._keyManager.activeItem) {
  1680. return this._keyManager.activeItem.id;
  1681. }
  1682. return null;
  1683. };
  1684. /**
  1685. * Sets the x-offset of the overlay panel in relation to the trigger's top start corner.
  1686. * This must be adjusted to align the selected option text over the trigger text when
  1687. * the panel opens. Will change based on LTR or RTL text direction. Note that the offset
  1688. * can't be calculated until the panel has been attached, because we need to know the
  1689. * content width in order to constrain the panel within the viewport.
  1690. */
  1691. /**
  1692. * Sets the x-offset of the overlay panel in relation to the trigger's top start corner.
  1693. * This must be adjusted to align the selected option text over the trigger text when
  1694. * the panel opens. Will change based on LTR or RTL text direction. Note that the offset
  1695. * can't be calculated until the panel has been attached, because we need to know the
  1696. * content width in order to constrain the panel within the viewport.
  1697. * @private
  1698. * @return {?}
  1699. */
  1700. MatSelect.prototype._calculateOverlayOffsetX = /**
  1701. * Sets the x-offset of the overlay panel in relation to the trigger's top start corner.
  1702. * This must be adjusted to align the selected option text over the trigger text when
  1703. * the panel opens. Will change based on LTR or RTL text direction. Note that the offset
  1704. * can't be calculated until the panel has been attached, because we need to know the
  1705. * content width in order to constrain the panel within the viewport.
  1706. * @private
  1707. * @return {?}
  1708. */
  1709. function () {
  1710. /** @type {?} */
  1711. var overlayRect = this.overlayDir.overlayRef.overlayElement.getBoundingClientRect();
  1712. /** @type {?} */
  1713. var viewportSize = this._viewportRuler.getViewportSize();
  1714. /** @type {?} */
  1715. var isRtl = this._isRtl();
  1716. /** @type {?} */
  1717. var paddingWidth = this.multiple ? SELECT_MULTIPLE_PANEL_PADDING_X + SELECT_PANEL_PADDING_X :
  1718. SELECT_PANEL_PADDING_X * 2;
  1719. /** @type {?} */
  1720. var offsetX;
  1721. // Adjust the offset, depending on the option padding.
  1722. if (this.multiple) {
  1723. offsetX = SELECT_MULTIPLE_PANEL_PADDING_X;
  1724. }
  1725. else {
  1726. /** @type {?} */
  1727. var selected = this._selectionModel.selected[0] || this.options.first;
  1728. offsetX = selected && selected.group ? SELECT_PANEL_INDENT_PADDING_X : SELECT_PANEL_PADDING_X;
  1729. }
  1730. // Invert the offset in LTR.
  1731. if (!isRtl) {
  1732. offsetX *= -1;
  1733. }
  1734. // Determine how much the select overflows on each side.
  1735. /** @type {?} */
  1736. var leftOverflow = 0 - (overlayRect.left + offsetX - (isRtl ? paddingWidth : 0));
  1737. /** @type {?} */
  1738. var rightOverflow = overlayRect.right + offsetX - viewportSize.width
  1739. + (isRtl ? 0 : paddingWidth);
  1740. // If the element overflows on either side, reduce the offset to allow it to fit.
  1741. if (leftOverflow > 0) {
  1742. offsetX += leftOverflow + SELECT_PANEL_VIEWPORT_PADDING;
  1743. }
  1744. else if (rightOverflow > 0) {
  1745. offsetX -= rightOverflow + SELECT_PANEL_VIEWPORT_PADDING;
  1746. }
  1747. // Set the offset directly in order to avoid having to go through change detection and
  1748. // potentially triggering "changed after it was checked" errors. Round the value to avoid
  1749. // blurry content in some browsers.
  1750. this.overlayDir.offsetX = Math.round(offsetX);
  1751. this.overlayDir.overlayRef.updatePosition();
  1752. };
  1753. /**
  1754. * Calculates the y-offset of the select's overlay panel in relation to the
  1755. * top start corner of the trigger. It has to be adjusted in order for the
  1756. * selected option to be aligned over the trigger when the panel opens.
  1757. */
  1758. /**
  1759. * Calculates the y-offset of the select's overlay panel in relation to the
  1760. * top start corner of the trigger. It has to be adjusted in order for the
  1761. * selected option to be aligned over the trigger when the panel opens.
  1762. * @private
  1763. * @param {?} selectedIndex
  1764. * @param {?} scrollBuffer
  1765. * @param {?} maxScroll
  1766. * @return {?}
  1767. */
  1768. MatSelect.prototype._calculateOverlayOffsetY = /**
  1769. * Calculates the y-offset of the select's overlay panel in relation to the
  1770. * top start corner of the trigger. It has to be adjusted in order for the
  1771. * selected option to be aligned over the trigger when the panel opens.
  1772. * @private
  1773. * @param {?} selectedIndex
  1774. * @param {?} scrollBuffer
  1775. * @param {?} maxScroll
  1776. * @return {?}
  1777. */
  1778. function (selectedIndex, scrollBuffer, maxScroll) {
  1779. /** @type {?} */
  1780. var itemHeight = this._getItemHeight();
  1781. /** @type {?} */
  1782. var optionHeightAdjustment = (itemHeight - this._triggerRect.height) / 2;
  1783. /** @type {?} */
  1784. var maxOptionsDisplayed = Math.floor(SELECT_PANEL_MAX_HEIGHT / itemHeight);
  1785. /** @type {?} */
  1786. var optionOffsetFromPanelTop;
  1787. // Disable offset if requested by user by returning 0 as value to offset
  1788. if (this._disableOptionCentering) {
  1789. return 0;
  1790. }
  1791. if (this._scrollTop === 0) {
  1792. optionOffsetFromPanelTop = selectedIndex * itemHeight;
  1793. }
  1794. else if (this._scrollTop === maxScroll) {
  1795. /** @type {?} */
  1796. var firstDisplayedIndex = this._getItemCount() - maxOptionsDisplayed;
  1797. /** @type {?} */
  1798. var selectedDisplayIndex = selectedIndex - firstDisplayedIndex;
  1799. // The first item is partially out of the viewport. Therefore we need to calculate what
  1800. // portion of it is shown in the viewport and account for it in our offset.
  1801. /** @type {?} */
  1802. var partialItemHeight = itemHeight - (this._getItemCount() * itemHeight - SELECT_PANEL_MAX_HEIGHT) % itemHeight;
  1803. // Because the panel height is longer than the height of the options alone,
  1804. // there is always extra padding at the top or bottom of the panel. When
  1805. // scrolled to the very bottom, this padding is at the top of the panel and
  1806. // must be added to the offset.
  1807. optionOffsetFromPanelTop = selectedDisplayIndex * itemHeight + partialItemHeight;
  1808. }
  1809. else {
  1810. // If the option was scrolled to the middle of the panel using a scroll buffer,
  1811. // its offset will be the scroll buffer minus the half height that was added to
  1812. // center it.
  1813. optionOffsetFromPanelTop = scrollBuffer - itemHeight / 2;
  1814. }
  1815. // The final offset is the option's offset from the top, adjusted for the height difference,
  1816. // multiplied by -1 to ensure that the overlay moves in the correct direction up the page.
  1817. // The value is rounded to prevent some browsers from blurring the content.
  1818. return Math.round(optionOffsetFromPanelTop * -1 - optionHeightAdjustment);
  1819. };
  1820. /**
  1821. * Checks that the attempted overlay position will fit within the viewport.
  1822. * If it will not fit, tries to adjust the scroll position and the associated
  1823. * y-offset so the panel can open fully on-screen. If it still won't fit,
  1824. * sets the offset back to 0 to allow the fallback position to take over.
  1825. */
  1826. /**
  1827. * Checks that the attempted overlay position will fit within the viewport.
  1828. * If it will not fit, tries to adjust the scroll position and the associated
  1829. * y-offset so the panel can open fully on-screen. If it still won't fit,
  1830. * sets the offset back to 0 to allow the fallback position to take over.
  1831. * @private
  1832. * @param {?} maxScroll
  1833. * @return {?}
  1834. */
  1835. MatSelect.prototype._checkOverlayWithinViewport = /**
  1836. * Checks that the attempted overlay position will fit within the viewport.
  1837. * If it will not fit, tries to adjust the scroll position and the associated
  1838. * y-offset so the panel can open fully on-screen. If it still won't fit,
  1839. * sets the offset back to 0 to allow the fallback position to take over.
  1840. * @private
  1841. * @param {?} maxScroll
  1842. * @return {?}
  1843. */
  1844. function (maxScroll) {
  1845. /** @type {?} */
  1846. var itemHeight = this._getItemHeight();
  1847. /** @type {?} */
  1848. var viewportSize = this._viewportRuler.getViewportSize();
  1849. /** @type {?} */
  1850. var topSpaceAvailable = this._triggerRect.top - SELECT_PANEL_VIEWPORT_PADDING;
  1851. /** @type {?} */
  1852. var bottomSpaceAvailable = viewportSize.height - this._triggerRect.bottom - SELECT_PANEL_VIEWPORT_PADDING;
  1853. /** @type {?} */
  1854. var panelHeightTop = Math.abs(this._offsetY);
  1855. /** @type {?} */
  1856. var totalPanelHeight = Math.min(this._getItemCount() * itemHeight, SELECT_PANEL_MAX_HEIGHT);
  1857. /** @type {?} */
  1858. var panelHeightBottom = totalPanelHeight - panelHeightTop - this._triggerRect.height;
  1859. if (panelHeightBottom > bottomSpaceAvailable) {
  1860. this._adjustPanelUp(panelHeightBottom, bottomSpaceAvailable);
  1861. }
  1862. else if (panelHeightTop > topSpaceAvailable) {
  1863. this._adjustPanelDown(panelHeightTop, topSpaceAvailable, maxScroll);
  1864. }
  1865. else {
  1866. this._transformOrigin = this._getOriginBasedOnOption();
  1867. }
  1868. };
  1869. /** Adjusts the overlay panel up to fit in the viewport. */
  1870. /**
  1871. * Adjusts the overlay panel up to fit in the viewport.
  1872. * @private
  1873. * @param {?} panelHeightBottom
  1874. * @param {?} bottomSpaceAvailable
  1875. * @return {?}
  1876. */
  1877. MatSelect.prototype._adjustPanelUp = /**
  1878. * Adjusts the overlay panel up to fit in the viewport.
  1879. * @private
  1880. * @param {?} panelHeightBottom
  1881. * @param {?} bottomSpaceAvailable
  1882. * @return {?}
  1883. */
  1884. function (panelHeightBottom, bottomSpaceAvailable) {
  1885. // Browsers ignore fractional scroll offsets, so we need to round.
  1886. /** @type {?} */
  1887. var distanceBelowViewport = Math.round(panelHeightBottom - bottomSpaceAvailable);
  1888. // Scrolls the panel up by the distance it was extending past the boundary, then
  1889. // adjusts the offset by that amount to move the panel up into the viewport.
  1890. this._scrollTop -= distanceBelowViewport;
  1891. this._offsetY -= distanceBelowViewport;
  1892. this._transformOrigin = this._getOriginBasedOnOption();
  1893. // If the panel is scrolled to the very top, it won't be able to fit the panel
  1894. // by scrolling, so set the offset to 0 to allow the fallback position to take
  1895. // effect.
  1896. if (this._scrollTop <= 0) {
  1897. this._scrollTop = 0;
  1898. this._offsetY = 0;
  1899. this._transformOrigin = "50% bottom 0px";
  1900. }
  1901. };
  1902. /** Adjusts the overlay panel down to fit in the viewport. */
  1903. /**
  1904. * Adjusts the overlay panel down to fit in the viewport.
  1905. * @private
  1906. * @param {?} panelHeightTop
  1907. * @param {?} topSpaceAvailable
  1908. * @param {?} maxScroll
  1909. * @return {?}
  1910. */
  1911. MatSelect.prototype._adjustPanelDown = /**
  1912. * Adjusts the overlay panel down to fit in the viewport.
  1913. * @private
  1914. * @param {?} panelHeightTop
  1915. * @param {?} topSpaceAvailable
  1916. * @param {?} maxScroll
  1917. * @return {?}
  1918. */
  1919. function (panelHeightTop, topSpaceAvailable, maxScroll) {
  1920. // Browsers ignore fractional scroll offsets, so we need to round.
  1921. /** @type {?} */
  1922. var distanceAboveViewport = Math.round(panelHeightTop - topSpaceAvailable);
  1923. // Scrolls the panel down by the distance it was extending past the boundary, then
  1924. // adjusts the offset by that amount to move the panel down into the viewport.
  1925. this._scrollTop += distanceAboveViewport;
  1926. this._offsetY += distanceAboveViewport;
  1927. this._transformOrigin = this._getOriginBasedOnOption();
  1928. // If the panel is scrolled to the very bottom, it won't be able to fit the
  1929. // panel by scrolling, so set the offset to 0 to allow the fallback position
  1930. // to take effect.
  1931. if (this._scrollTop >= maxScroll) {
  1932. this._scrollTop = maxScroll;
  1933. this._offsetY = 0;
  1934. this._transformOrigin = "50% top 0px";
  1935. return;
  1936. }
  1937. };
  1938. /** Sets the transform origin point based on the selected option. */
  1939. /**
  1940. * Sets the transform origin point based on the selected option.
  1941. * @private
  1942. * @return {?}
  1943. */
  1944. MatSelect.prototype._getOriginBasedOnOption = /**
  1945. * Sets the transform origin point based on the selected option.
  1946. * @private
  1947. * @return {?}
  1948. */
  1949. function () {
  1950. /** @type {?} */
  1951. var itemHeight = this._getItemHeight();
  1952. /** @type {?} */
  1953. var optionHeightAdjustment = (itemHeight - this._triggerRect.height) / 2;
  1954. /** @type {?} */
  1955. var originY = Math.abs(this._offsetY) - optionHeightAdjustment + itemHeight / 2;
  1956. return "50% " + originY + "px 0px";
  1957. };
  1958. /** Calculates the amount of items in the select. This includes options and group labels. */
  1959. /**
  1960. * Calculates the amount of items in the select. This includes options and group labels.
  1961. * @private
  1962. * @return {?}
  1963. */
  1964. MatSelect.prototype._getItemCount = /**
  1965. * Calculates the amount of items in the select. This includes options and group labels.
  1966. * @private
  1967. * @return {?}
  1968. */
  1969. function () {
  1970. return this.options.length + this.optionGroups.length;
  1971. };
  1972. /** Calculates the height of the select's options. */
  1973. /**
  1974. * Calculates the height of the select's options.
  1975. * @private
  1976. * @return {?}
  1977. */
  1978. MatSelect.prototype._getItemHeight = /**
  1979. * Calculates the height of the select's options.
  1980. * @private
  1981. * @return {?}
  1982. */
  1983. function () {
  1984. return this._triggerFontSize * SELECT_ITEM_HEIGHT_EM;
  1985. };
  1986. /**
  1987. * Implemented as part of MatFormFieldControl.
  1988. * @docs-private
  1989. */
  1990. /**
  1991. * Implemented as part of MatFormFieldControl.
  1992. * \@docs-private
  1993. * @param {?} ids
  1994. * @return {?}
  1995. */
  1996. MatSelect.prototype.setDescribedByIds = /**
  1997. * Implemented as part of MatFormFieldControl.
  1998. * \@docs-private
  1999. * @param {?} ids
  2000. * @return {?}
  2001. */
  2002. function (ids) {
  2003. this._ariaDescribedby = ids.join(' ');
  2004. };
  2005. /**
  2006. * Implemented as part of MatFormFieldControl.
  2007. * @docs-private
  2008. */
  2009. /**
  2010. * Implemented as part of MatFormFieldControl.
  2011. * \@docs-private
  2012. * @return {?}
  2013. */
  2014. MatSelect.prototype.onContainerClick = /**
  2015. * Implemented as part of MatFormFieldControl.
  2016. * \@docs-private
  2017. * @return {?}
  2018. */
  2019. function () {
  2020. this.focus();
  2021. this.open();
  2022. };
  2023. Object.defineProperty(MatSelect.prototype, "shouldLabelFloat", {
  2024. /**
  2025. * Implemented as part of MatFormFieldControl.
  2026. * @docs-private
  2027. */
  2028. get: /**
  2029. * Implemented as part of MatFormFieldControl.
  2030. * \@docs-private
  2031. * @return {?}
  2032. */
  2033. function () {
  2034. return this._panelOpen || !this.empty;
  2035. },
  2036. enumerable: true,
  2037. configurable: true
  2038. });
  2039. MatSelect.decorators = [
  2040. { type: core.Component, args: [{selector: 'mat-select',
  2041. exportAs: 'matSelect',
  2042. template: "<div cdk-overlay-origin class=\"mat-select-trigger\" aria-hidden=\"true\" (click)=\"toggle()\" #origin=\"cdkOverlayOrigin\" #trigger><div class=\"mat-select-value\" [ngSwitch]=\"empty\"><span class=\"mat-select-placeholder\" *ngSwitchCase=\"true\">{{placeholder || '\u00A0'}}</span> <span class=\"mat-select-value-text\" *ngSwitchCase=\"false\" [ngSwitch]=\"!!customTrigger\"><span *ngSwitchDefault>{{triggerValue || '\u00A0'}}</span><ng-content select=\"mat-select-trigger\" *ngSwitchCase=\"true\"></ng-content></span></div><div class=\"mat-select-arrow-wrapper\"><div class=\"mat-select-arrow\"></div></div></div><ng-template cdk-connected-overlay cdkConnectedOverlayLockPosition cdkConnectedOverlayHasBackdrop cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\" [cdkConnectedOverlayScrollStrategy]=\"_scrollStrategy\" [cdkConnectedOverlayOrigin]=\"origin\" [cdkConnectedOverlayOpen]=\"panelOpen\" [cdkConnectedOverlayPositions]=\"_positions\" [cdkConnectedOverlayMinWidth]=\"_triggerRect?.width\" [cdkConnectedOverlayOffsetY]=\"_offsetY\" (backdropClick)=\"close()\" (attach)=\"_onAttached()\" (detach)=\"close()\"><div class=\"mat-select-panel-wrap\" [@transformPanelWrap]><div #panel class=\"mat-select-panel {{ _getPanelTheme() }}\" [ngClass]=\"panelClass\" [@transformPanel]=\"multiple ? 'showing-multiple' : 'showing'\" (@transformPanel.done)=\"_panelDoneAnimatingStream.next($event.toState)\" [style.transformOrigin]=\"_transformOrigin\" [style.font-size.px]=\"_triggerFontSize\" (keydown)=\"_handleKeydown($event)\"><ng-content></ng-content></div></div></ng-template>",
  2043. styles: [".mat-select{display:inline-block;width:100%;outline:0}.mat-select-trigger{display:inline-table;cursor:pointer;position:relative;box-sizing:border-box}.mat-select-disabled .mat-select-trigger{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.mat-select-value{display:table-cell;max-width:0;width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mat-select-value-text{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mat-select-arrow-wrapper{display:table-cell;vertical-align:middle}.mat-form-field-appearance-fill .mat-select-arrow-wrapper{transform:translateY(-50%)}.mat-form-field-appearance-outline .mat-select-arrow-wrapper{transform:translateY(-25%)}.mat-form-field-appearance-standard.mat-form-field-has-label .mat-select:not(.mat-select-empty) .mat-select-arrow-wrapper{transform:translateY(-50%)}.mat-form-field-appearance-standard .mat-select.mat-select-empty .mat-select-arrow-wrapper{transition:transform .4s cubic-bezier(.25,.8,.25,1)}._mat-animation-noopable.mat-form-field-appearance-standard .mat-select.mat-select-empty .mat-select-arrow-wrapper{transition:none}.mat-select-arrow{width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid;margin:0 4px}.mat-select-panel-wrap{flex-basis:100%}.mat-select-panel{min-width:112px;max-width:280px;overflow:auto;-webkit-overflow-scrolling:touch;padding-top:0;padding-bottom:0;max-height:256px;min-width:100%;border-radius:4px}@media (-ms-high-contrast:active){.mat-select-panel{outline:solid 1px}}.mat-select-panel .mat-optgroup-label,.mat-select-panel .mat-option{font-size:inherit;line-height:3em;height:3em}.mat-form-field-type-mat-select:not(.mat-form-field-disabled) .mat-form-field-flex{cursor:pointer}.mat-form-field-type-mat-select .mat-form-field-label{width:calc(100% - 18px)}.mat-select-placeholder{transition:color .4s .133s cubic-bezier(.25,.8,.25,1)}._mat-animation-noopable .mat-select-placeholder{transition:none}.mat-form-field-hide-placeholder .mat-select-placeholder{color:transparent;-webkit-text-fill-color:transparent;transition:none;display:block}"],
  2044. inputs: ['disabled', 'disableRipple', 'tabIndex'],
  2045. encapsulation: core.ViewEncapsulation.None,
  2046. changeDetection: core.ChangeDetectionStrategy.OnPush,
  2047. host: {
  2048. 'role': 'listbox',
  2049. '[attr.id]': 'id',
  2050. '[attr.tabindex]': 'tabIndex',
  2051. '[attr.aria-label]': '_getAriaLabel()',
  2052. '[attr.aria-labelledby]': '_getAriaLabelledby()',
  2053. '[attr.aria-required]': 'required.toString()',
  2054. '[attr.aria-disabled]': 'disabled.toString()',
  2055. '[attr.aria-invalid]': 'errorState',
  2056. '[attr.aria-owns]': 'panelOpen ? _optionIds : null',
  2057. '[attr.aria-multiselectable]': 'multiple',
  2058. '[attr.aria-describedby]': '_ariaDescribedby || null',
  2059. '[attr.aria-activedescendant]': '_getAriaActiveDescendant()',
  2060. '[class.mat-select-disabled]': 'disabled',
  2061. '[class.mat-select-invalid]': 'errorState',
  2062. '[class.mat-select-required]': 'required',
  2063. '[class.mat-select-empty]': 'empty',
  2064. 'class': 'mat-select',
  2065. '(keydown)': '_handleKeydown($event)',
  2066. '(focus)': '_onFocus()',
  2067. '(blur)': '_onBlur()',
  2068. },
  2069. animations: [
  2070. matSelectAnimations.transformPanelWrap,
  2071. matSelectAnimations.transformPanel
  2072. ],
  2073. providers: [
  2074. { provide: formField.MatFormFieldControl, useExisting: MatSelect },
  2075. { provide: core$1.MAT_OPTION_PARENT_COMPONENT, useExisting: MatSelect }
  2076. ],
  2077. },] },
  2078. ];
  2079. /** @nocollapse */
  2080. MatSelect.ctorParameters = function () { return [
  2081. { type: scrolling.ViewportRuler },
  2082. { type: core.ChangeDetectorRef },
  2083. { type: core.NgZone },
  2084. { type: core$1.ErrorStateMatcher },
  2085. { type: core.ElementRef },
  2086. { type: bidi.Directionality, decorators: [{ type: core.Optional }] },
  2087. { type: forms.NgForm, decorators: [{ type: core.Optional }] },
  2088. { type: forms.FormGroupDirective, decorators: [{ type: core.Optional }] },
  2089. { type: formField.MatFormField, decorators: [{ type: core.Optional }] },
  2090. { type: forms.NgControl, decorators: [{ type: core.Self }, { type: core.Optional }] },
  2091. { type: String, decorators: [{ type: core.Attribute, args: ['tabindex',] }] },
  2092. { type: undefined, decorators: [{ type: core.Inject, args: [MAT_SELECT_SCROLL_STRATEGY,] }] },
  2093. { type: a11y.LiveAnnouncer }
  2094. ]; };
  2095. MatSelect.propDecorators = {
  2096. trigger: [{ type: core.ViewChild, args: ['trigger', { static: false },] }],
  2097. panel: [{ type: core.ViewChild, args: ['panel', { static: false },] }],
  2098. overlayDir: [{ type: core.ViewChild, args: [overlay.CdkConnectedOverlay, { static: false },] }],
  2099. options: [{ type: core.ContentChildren, args: [core$1.MatOption, { descendants: true },] }],
  2100. optionGroups: [{ type: core.ContentChildren, args: [core$1.MatOptgroup,] }],
  2101. panelClass: [{ type: core.Input }],
  2102. customTrigger: [{ type: core.ContentChild, args: [MatSelectTrigger, { static: false },] }],
  2103. placeholder: [{ type: core.Input }],
  2104. required: [{ type: core.Input }],
  2105. multiple: [{ type: core.Input }],
  2106. disableOptionCentering: [{ type: core.Input }],
  2107. compareWith: [{ type: core.Input }],
  2108. value: [{ type: core.Input }],
  2109. ariaLabel: [{ type: core.Input, args: ['aria-label',] }],
  2110. ariaLabelledby: [{ type: core.Input, args: ['aria-labelledby',] }],
  2111. errorStateMatcher: [{ type: core.Input }],
  2112. sortComparator: [{ type: core.Input }],
  2113. id: [{ type: core.Input }],
  2114. openedChange: [{ type: core.Output }],
  2115. _openedStream: [{ type: core.Output, args: ['opened',] }],
  2116. _closedStream: [{ type: core.Output, args: ['closed',] }],
  2117. selectionChange: [{ type: core.Output }],
  2118. valueChange: [{ type: core.Output }]
  2119. };
  2120. return MatSelect;
  2121. }(_MatSelectMixinBase));
  2122. /**
  2123. * @fileoverview added by tsickle
  2124. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  2125. */
  2126. var MatSelectModule = /** @class */ (function () {
  2127. function MatSelectModule() {
  2128. }
  2129. MatSelectModule.decorators = [
  2130. { type: core.NgModule, args: [{
  2131. imports: [
  2132. common.CommonModule,
  2133. overlay.OverlayModule,
  2134. core$1.MatOptionModule,
  2135. core$1.MatCommonModule,
  2136. ],
  2137. exports: [formField.MatFormFieldModule, MatSelect, MatSelectTrigger, core$1.MatOptionModule, core$1.MatCommonModule],
  2138. declarations: [MatSelect, MatSelectTrigger],
  2139. providers: [MAT_SELECT_SCROLL_STRATEGY_PROVIDER]
  2140. },] },
  2141. ];
  2142. return MatSelectModule;
  2143. }());
  2144. exports.MatSelectModule = MatSelectModule;
  2145. exports.MAT_SELECT_SCROLL_STRATEGY_PROVIDER_FACTORY = MAT_SELECT_SCROLL_STRATEGY_PROVIDER_FACTORY;
  2146. exports.SELECT_PANEL_MAX_HEIGHT = SELECT_PANEL_MAX_HEIGHT;
  2147. exports.SELECT_PANEL_PADDING_X = SELECT_PANEL_PADDING_X;
  2148. exports.SELECT_PANEL_INDENT_PADDING_X = SELECT_PANEL_INDENT_PADDING_X;
  2149. exports.SELECT_ITEM_HEIGHT_EM = SELECT_ITEM_HEIGHT_EM;
  2150. exports.SELECT_MULTIPLE_PANEL_PADDING_X = SELECT_MULTIPLE_PANEL_PADDING_X;
  2151. exports.SELECT_PANEL_VIEWPORT_PADDING = SELECT_PANEL_VIEWPORT_PADDING;
  2152. exports.MAT_SELECT_SCROLL_STRATEGY = MAT_SELECT_SCROLL_STRATEGY;
  2153. exports.MAT_SELECT_SCROLL_STRATEGY_PROVIDER = MAT_SELECT_SCROLL_STRATEGY_PROVIDER;
  2154. exports.MatSelectChange = MatSelectChange;
  2155. exports.MatSelectTrigger = MatSelectTrigger;
  2156. exports.MatSelect = MatSelect;
  2157. exports.matSelectAnimations = matSelectAnimations;
  2158. exports.transformPanel = transformPanel;
  2159. exports.fadeInContent = fadeInContent;
  2160. Object.defineProperty(exports, '__esModule', { value: true });
  2161. })));
  2162. //# sourceMappingURL=material-select.umd.js.map