ngx-bootstrap-component-loader.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. import { EventEmitter, Injector, ElementRef, TemplateRef, Injectable, ComponentFactoryResolver, NgZone, ApplicationRef } from '@angular/core';
  2. import { listenToTriggersV2, registerOutsideClick, registerEscClick } from 'ngx-bootstrap/utils';
  3. import { PositioningService } from 'ngx-bootstrap/positioning';
  4. /**
  5. * @fileoverview added by tsickle
  6. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  7. */
  8. /**
  9. * @template T
  10. */
  11. class BsComponentRef {
  12. }
  13. /**
  14. * @fileoverview added by tsickle
  15. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  16. */
  17. /**
  18. * @copyright Valor Software
  19. * @copyright Angular ng-bootstrap team
  20. */
  21. class ContentRef {
  22. /**
  23. * @param {?} nodes
  24. * @param {?=} viewRef
  25. * @param {?=} componentRef
  26. */
  27. constructor(
  28. /* tslint:disable-next-line: no-any */
  29. nodes, viewRef,
  30. /* tslint:disable-next-line: no-any */
  31. componentRef) {
  32. this.nodes = nodes;
  33. this.viewRef = viewRef;
  34. this.componentRef = componentRef;
  35. }
  36. }
  37. /**
  38. * @fileoverview added by tsickle
  39. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  40. */
  41. /**
  42. * @template T
  43. */
  44. class ComponentLoader {
  45. /**
  46. * Do not use this directly, it should be instanced via
  47. * `ComponentLoadFactory.attach`
  48. * \@internal
  49. * @param {?} _viewContainerRef
  50. * @param {?} _renderer
  51. * @param {?} _elementRef
  52. * @param {?} _injector
  53. * @param {?} _componentFactoryResolver
  54. * @param {?} _ngZone
  55. * @param {?} _applicationRef
  56. * @param {?} _posService
  57. */
  58. // tslint:disable-next-line
  59. constructor(_viewContainerRef, _renderer, _elementRef, _injector, _componentFactoryResolver, _ngZone, _applicationRef, _posService) {
  60. this._viewContainerRef = _viewContainerRef;
  61. this._renderer = _renderer;
  62. this._elementRef = _elementRef;
  63. this._injector = _injector;
  64. this._componentFactoryResolver = _componentFactoryResolver;
  65. this._ngZone = _ngZone;
  66. this._applicationRef = _applicationRef;
  67. this._posService = _posService;
  68. this.onBeforeShow = new EventEmitter();
  69. /* tslint:disable-next-line: no-any*/
  70. this.onShown = new EventEmitter();
  71. /* tslint:disable-next-line: no-any*/
  72. this.onBeforeHide = new EventEmitter();
  73. this.onHidden = new EventEmitter();
  74. this._providers = [];
  75. this._isHiding = false;
  76. /**
  77. * A selector used if container element was not found
  78. */
  79. this.containerDefaultSelector = 'body';
  80. this._listenOpts = {};
  81. this._globalListener = Function.prototype;
  82. }
  83. /**
  84. * @return {?}
  85. */
  86. get isShown() {
  87. if (this._isHiding) {
  88. return false;
  89. }
  90. return !!this._componentRef;
  91. }
  92. /**
  93. * @param {?} compType
  94. * @return {?}
  95. */
  96. attach(compType) {
  97. this._componentFactory = this._componentFactoryResolver
  98. .resolveComponentFactory(compType);
  99. return this;
  100. }
  101. // todo: add behaviour: to target element, `body`, custom element
  102. /**
  103. * @param {?=} container
  104. * @return {?}
  105. */
  106. to(container) {
  107. this.container = container || this.container;
  108. return this;
  109. }
  110. /**
  111. * @param {?=} opts
  112. * @return {?}
  113. */
  114. position(opts) {
  115. this.attachment = opts.attachment || this.attachment;
  116. /* tslint:disable-next-line: no-unnecessary-type-assertion */
  117. this._elementRef = ((/** @type {?} */ (opts.target))) || this._elementRef;
  118. return this;
  119. }
  120. /**
  121. * @param {?} provider
  122. * @return {?}
  123. */
  124. provide(provider) {
  125. this._providers.push(provider);
  126. return this;
  127. }
  128. // todo: appendChild to element or document.querySelector(this.container)
  129. /**
  130. * @param {?=} opts
  131. * @return {?}
  132. */
  133. show(opts = {}) {
  134. this._subscribePositioning();
  135. this._innerComponent = null;
  136. if (!this._componentRef) {
  137. this.onBeforeShow.emit();
  138. this._contentRef = this._getContentRef(opts.content, opts.context, opts.initialState);
  139. /** @type {?} */
  140. const injector = Injector.create({
  141. providers: this._providers,
  142. parent: this._injector
  143. });
  144. this._componentRef = this._componentFactory.create(injector, this._contentRef.nodes);
  145. this._applicationRef.attachView(this._componentRef.hostView);
  146. // this._componentRef = this._viewContainerRef
  147. // .createComponent(this._componentFactory, 0, injector, this._contentRef.nodes);
  148. this.instance = this._componentRef.instance;
  149. Object.assign(this._componentRef.instance, opts);
  150. if (this.container instanceof ElementRef) {
  151. this.container.nativeElement.appendChild(this._componentRef.location.nativeElement);
  152. }
  153. if (typeof this.container === 'string' && typeof document !== 'undefined') {
  154. /** @type {?} */
  155. const selectedElement = document.querySelector(this.container) ||
  156. document.querySelector(this.containerDefaultSelector);
  157. selectedElement.appendChild(this._componentRef.location.nativeElement);
  158. }
  159. if (!this.container &&
  160. this._elementRef &&
  161. this._elementRef.nativeElement.parentElement) {
  162. this._elementRef.nativeElement.parentElement.appendChild(this._componentRef.location.nativeElement);
  163. }
  164. // we need to manually invoke change detection since events registered
  165. // via
  166. // Renderer::listen() are not picked up by change detection with the
  167. // OnPush strategy
  168. if (this._contentRef.componentRef) {
  169. this._innerComponent = this._contentRef.componentRef.instance;
  170. this._contentRef.componentRef.changeDetectorRef.markForCheck();
  171. this._contentRef.componentRef.changeDetectorRef.detectChanges();
  172. }
  173. this._componentRef.changeDetectorRef.markForCheck();
  174. this._componentRef.changeDetectorRef.detectChanges();
  175. this.onShown.emit(this._componentRef.instance);
  176. }
  177. this._registerOutsideClick();
  178. return this._componentRef;
  179. }
  180. /**
  181. * @return {?}
  182. */
  183. hide() {
  184. if (!this._componentRef) {
  185. return this;
  186. }
  187. this._posService.deletePositionElement(this._componentRef.location);
  188. this.onBeforeHide.emit(this._componentRef.instance);
  189. /** @type {?} */
  190. const componentEl = this._componentRef.location.nativeElement;
  191. componentEl.parentNode.removeChild(componentEl);
  192. if (this._contentRef.componentRef) {
  193. this._contentRef.componentRef.destroy();
  194. }
  195. this._componentRef.destroy();
  196. if (this._viewContainerRef && this._contentRef.viewRef) {
  197. this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._contentRef.viewRef));
  198. }
  199. if (this._contentRef.viewRef) {
  200. this._contentRef.viewRef.destroy();
  201. }
  202. this._contentRef = null;
  203. this._componentRef = null;
  204. this._removeGlobalListener();
  205. this.onHidden.emit();
  206. return this;
  207. }
  208. /**
  209. * @return {?}
  210. */
  211. toggle() {
  212. if (this.isShown) {
  213. this.hide();
  214. return;
  215. }
  216. this.show();
  217. }
  218. /**
  219. * @return {?}
  220. */
  221. dispose() {
  222. if (this.isShown) {
  223. this.hide();
  224. }
  225. this._unsubscribePositioning();
  226. if (this._unregisterListenersFn) {
  227. this._unregisterListenersFn();
  228. }
  229. }
  230. /**
  231. * @param {?} listenOpts
  232. * @return {?}
  233. */
  234. listen(listenOpts) {
  235. this.triggers = listenOpts.triggers || this.triggers;
  236. this._listenOpts.outsideClick = listenOpts.outsideClick;
  237. this._listenOpts.outsideEsc = listenOpts.outsideEsc;
  238. listenOpts.target = listenOpts.target || this._elementRef.nativeElement;
  239. /** @type {?} */
  240. const hide = (this._listenOpts.hide = (/**
  241. * @return {?}
  242. */
  243. () => listenOpts.hide ? listenOpts.hide() : void this.hide()));
  244. /** @type {?} */
  245. const show = (this._listenOpts.show = (/**
  246. * @param {?} registerHide
  247. * @return {?}
  248. */
  249. (registerHide) => {
  250. listenOpts.show ? listenOpts.show(registerHide) : this.show(registerHide);
  251. registerHide();
  252. }));
  253. /** @type {?} */
  254. const toggle = (/**
  255. * @param {?} registerHide
  256. * @return {?}
  257. */
  258. (registerHide) => {
  259. this.isShown ? hide() : show(registerHide);
  260. });
  261. this._unregisterListenersFn = listenToTriggersV2(this._renderer, {
  262. target: listenOpts.target,
  263. triggers: listenOpts.triggers,
  264. show,
  265. hide,
  266. toggle
  267. });
  268. return this;
  269. }
  270. /**
  271. * @return {?}
  272. */
  273. _removeGlobalListener() {
  274. if (this._globalListener) {
  275. this._globalListener();
  276. this._globalListener = null;
  277. }
  278. }
  279. /**
  280. * @param {?} vRef
  281. * @param {?} template
  282. * @return {?}
  283. */
  284. attachInline(vRef,
  285. /* tslint:disable-next-line: no-any*/
  286. template) {
  287. this._inlineViewRef = vRef.createEmbeddedView(template);
  288. return this;
  289. }
  290. /**
  291. * @return {?}
  292. */
  293. _registerOutsideClick() {
  294. if (!this._componentRef || !this._componentRef.location) {
  295. return;
  296. }
  297. // why: should run after first event bubble
  298. if (this._listenOpts.outsideClick) {
  299. /** @type {?} */
  300. const target = this._componentRef.location.nativeElement;
  301. setTimeout((/**
  302. * @return {?}
  303. */
  304. () => {
  305. this._globalListener = registerOutsideClick(this._renderer, {
  306. targets: [target, this._elementRef.nativeElement],
  307. outsideClick: this._listenOpts.outsideClick,
  308. hide: (/**
  309. * @return {?}
  310. */
  311. () => this._listenOpts.hide())
  312. });
  313. }));
  314. }
  315. if (this._listenOpts.outsideEsc) {
  316. /** @type {?} */
  317. const target = this._componentRef.location.nativeElement;
  318. this._globalListener = registerEscClick(this._renderer, {
  319. targets: [target, this._elementRef.nativeElement],
  320. outsideEsc: this._listenOpts.outsideEsc,
  321. hide: (/**
  322. * @return {?}
  323. */
  324. () => this._listenOpts.hide())
  325. });
  326. }
  327. }
  328. /**
  329. * @return {?}
  330. */
  331. getInnerComponent() {
  332. return this._innerComponent;
  333. }
  334. /**
  335. * @private
  336. * @return {?}
  337. */
  338. _subscribePositioning() {
  339. if (this._zoneSubscription || !this.attachment) {
  340. return;
  341. }
  342. this.onShown.subscribe((/**
  343. * @return {?}
  344. */
  345. () => {
  346. this._posService.position({
  347. element: this._componentRef.location,
  348. target: this._elementRef,
  349. attachment: this.attachment,
  350. appendToBody: this.container === 'body'
  351. });
  352. }));
  353. this._zoneSubscription = this._ngZone.onStable.subscribe((/**
  354. * @return {?}
  355. */
  356. () => {
  357. if (!this._componentRef) {
  358. return;
  359. }
  360. this._posService.calcPosition();
  361. }));
  362. }
  363. /**
  364. * @private
  365. * @return {?}
  366. */
  367. _unsubscribePositioning() {
  368. if (!this._zoneSubscription) {
  369. return;
  370. }
  371. this._zoneSubscription.unsubscribe();
  372. this._zoneSubscription = null;
  373. }
  374. /**
  375. * @private
  376. * @param {?} content
  377. * @param {?=} context
  378. * @param {?=} initialState
  379. * @return {?}
  380. */
  381. _getContentRef(
  382. /* tslint:disable-next-line: no-any*/
  383. content,
  384. /* tslint:disable-next-line: no-any*/
  385. context,
  386. /* tslint:disable-next-line: no-any*/
  387. initialState) {
  388. if (!content) {
  389. return new ContentRef([]);
  390. }
  391. if (content instanceof TemplateRef) {
  392. if (this._viewContainerRef) {
  393. /** @type {?} */
  394. const _viewRef = this._viewContainerRef
  395. .createEmbeddedView(content, context);
  396. _viewRef.markForCheck();
  397. return new ContentRef([_viewRef.rootNodes], _viewRef);
  398. }
  399. /** @type {?} */
  400. const viewRef = content.createEmbeddedView({});
  401. this._applicationRef.attachView(viewRef);
  402. return new ContentRef([viewRef.rootNodes], viewRef);
  403. }
  404. if (typeof content === 'function') {
  405. /** @type {?} */
  406. const contentCmptFactory = this._componentFactoryResolver.resolveComponentFactory(content);
  407. /** @type {?} */
  408. const modalContentInjector = Injector.create({
  409. providers: this._providers,
  410. parent: this._injector
  411. });
  412. /** @type {?} */
  413. const componentRef = contentCmptFactory.create(modalContentInjector);
  414. Object.assign(componentRef.instance, initialState);
  415. this._applicationRef.attachView(componentRef.hostView);
  416. return new ContentRef([[componentRef.location.nativeElement]], componentRef.hostView, componentRef);
  417. }
  418. return new ContentRef([[this._renderer.createText(`${content}`)]]);
  419. }
  420. }
  421. /**
  422. * @fileoverview added by tsickle
  423. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  424. */
  425. class ComponentLoaderFactory {
  426. /**
  427. * @param {?} _componentFactoryResolver
  428. * @param {?} _ngZone
  429. * @param {?} _injector
  430. * @param {?} _posService
  431. * @param {?} _applicationRef
  432. */
  433. constructor(_componentFactoryResolver, _ngZone, _injector, _posService, _applicationRef) {
  434. this._componentFactoryResolver = _componentFactoryResolver;
  435. this._ngZone = _ngZone;
  436. this._injector = _injector;
  437. this._posService = _posService;
  438. this._applicationRef = _applicationRef;
  439. }
  440. /**
  441. *
  442. * @template T
  443. * @param {?} _elementRef
  444. * @param {?} _viewContainerRef
  445. * @param {?} _renderer
  446. * @return {?}
  447. */
  448. createLoader(_elementRef, _viewContainerRef, _renderer) {
  449. return new ComponentLoader(_viewContainerRef, _renderer, _elementRef, this._injector, this._componentFactoryResolver, this._ngZone, this._applicationRef, this._posService);
  450. }
  451. }
  452. ComponentLoaderFactory.decorators = [
  453. { type: Injectable }
  454. ];
  455. /** @nocollapse */
  456. ComponentLoaderFactory.ctorParameters = () => [
  457. { type: ComponentFactoryResolver },
  458. { type: NgZone },
  459. { type: Injector },
  460. { type: PositioningService },
  461. { type: ApplicationRef }
  462. ];
  463. export { BsComponentRef, ComponentLoader, ComponentLoaderFactory, ContentRef };
  464. //# sourceMappingURL=ngx-bootstrap-component-loader.js.map