Disable sticky of page header if bottom is on the view. Inputs finish all types

This commit is contained in:
Konstantinos Triantafyllou 2022-03-30 20:47:47 +03:00
parent 31516e8f55
commit da6f220ae0
5 changed files with 247 additions and 299 deletions

View File

@ -1,4 +1,4 @@
import {Component, ElementRef, EventEmitter, OnDestroy, OnInit, Output, ViewChild} from "@angular/core";
import {AfterViewInit, Component, ElementRef, EventEmitter, OnDestroy, OnInit, Output, ViewChild} from "@angular/core";
import {Subscription} from "rxjs";
declare var UIkit;
@ -8,8 +8,8 @@ declare var UIkit;
template: `
<div id="page_content">
<div id="header">
<div id="page_content_header" uk-sticky="media: @m" [attr.offset]="offset">
<div #header class="uk-container uk-container-large uk-padding-remove-vertical">
<div id="page_content_header" [attr.uk-sticky]="shouldSticky?'media: @m':null" [attr.offset]="shouldSticky?offset:null">
<div class="uk-container uk-container-large uk-padding-remove-vertical">
<div class="uk-padding-small uk-padding-remove-vertical">
<ng-content select="[header]"></ng-content>
</div>
@ -24,42 +24,57 @@ declare var UIkit;
</div>
`,
})
export class PageContentComponent implements OnInit, OnDestroy {
export class PageContentComponent implements OnInit, AfterViewInit, OnDestroy {
public offset: number;
public sticky: boolean = false;
public shouldSticky: boolean = true;
@Output()
public stickyEmitter: EventEmitter<boolean> = new EventEmitter<boolean>();
@ViewChild("header") public header: ElementRef;
private current;
private observer: IntersectionObserver;
private subscriptions: any[] = [];
constructor() {
}
ngOnInit() {
if (typeof window !== "undefined") {
this.current = window.pageYOffset;
if (typeof document !== "undefined") {
this.initSticky();
}
}
ngAfterViewInit() {
if(typeof document !== "undefined") {
let bottom = document.getElementById('bottom');
if(bottom) {
this.observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
this.shouldSticky = !entry.isIntersecting;
this.initSticky();
})
});
this.observer.observe(bottom);
}
}
}
initSticky() {
this.clear();
this.subscriptions.push(UIkit.util.on(document, 'active', '#sticky-menu', (): void => {
this.offset = Number.parseInt(getComputedStyle(document.documentElement).getPropertyValue('--structure-header-height'));
}));
this.subscriptions.push(UIkit.util.on(document, 'inactive', '#sticky-menu', (): void => {
this.offset = 0;
}));
this.subscriptions.push(UIkit.util.on(document, 'active', '#page_content_header', (): void => {
this.sticky = true;
this.stickyEmitter.emit(this.sticky);
}));
this.subscriptions.push(UIkit.util.on(document, 'inactive', '#page_content_header', (): void => {
this.sticky = false;
this.stickyEmitter.emit(this.sticky);
}));
if(this.shouldSticky) {
this.subscriptions.push(UIkit.util.on(document, 'active', '#sticky-menu', () => {
this.offset = Number.parseInt(getComputedStyle(document.documentElement).getPropertyValue('--structure-header-height'));
}));
this.subscriptions.push(UIkit.util.on(document, 'inactive', '#sticky-menu', () => {
this.offset = 0;
}));
this.subscriptions.push(UIkit.util.on(document, 'active', '#page_content_header', () => {
this.sticky = true;
this.stickyEmitter.emit(this.sticky);
}));
this.subscriptions.push(UIkit.util.on(document, 'inactive', '#page_content_header', () => {
this.sticky = false;
this.stickyEmitter.emit(this.sticky);
}));
}
}
clear() {
@ -74,5 +89,8 @@ export class PageContentComponent implements OnInit, OnDestroy {
ngOnDestroy() {
this.clear();
if(this.observer) {
this.observer.disconnect();
}
}
}

View File

@ -44,12 +44,6 @@ export class LayoutService {
* Add activeMenuItem: string on data of route config, if page should activate a specific MenuItem and route url does not match.
*/
private activeMenuItemSubject: BehaviorSubject<string> = new BehaviorSubject<string>("");
/**
* Add isStickyPageHeader:
*/
private isStickyPageHeaderSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
sub: any;
ngOnDestroy() {
@ -176,12 +170,4 @@ export class LayoutService {
setActiveMenuItem(value: string) {
this.activeMenuItemSubject.next(value);
}
get isStickyPageHeader(): Observable<boolean> {
return this.isStickyPageHeaderSubject.asObservable();
}
setIsStickyPageHeader(value: boolean) {
this.isStickyPageHeaderSubject.next(value);
}
}

View File

@ -26,8 +26,8 @@ declare var UIkit;
</div>
</ng-template>
<ng-template [ngIf]="form.get('groups') && availableGroups">
<div class="uk-grid uk-grid-small" uk-grid>
<span style="opacity: 0.5;" class="uk-text-bold uk-margin-small-top">Send to: </span>
<!--<div class="uk-grid uk-grid-small" uk-grid>
<span style="opacity: 0.5;" class="uk-text-bold uk-margin-top">Send to: </span>
<div [class.uk-hidden]="focused" class="uk-width-expand uk-margin-small" (click)="focus($event)">
<span *ngIf="groups.length === 0" class="placeholder">Add a recipient</span>
<span *ngIf="groups.length > 0" [attr.uk-tooltip]="(groups.length > 2)?groups.join(', '):null">
@ -35,24 +35,25 @@ declare var UIkit;
<span *ngIf="groups.length > 2" style="opacity: 0.5; margin-left: 4px">+ {{groups.length - 2}} more</span>
</span>
</div>
<div #recipients dashboard-input type="chips" [options]="availableGroups" [class.uk-hidden]="!focused"
panelClass="uk-text-small" [showOptionsOnEmpty]="false"
inputClass="input-borderless" class="uk-width-expand" (focusEmitter)="onFocus($event)" [panelWidth]="400"
[smallChip]="true" [gridSmall]="true" [formInput]="form.get('groups')">
</div>
</div>
</div>-->
<div class="uk-grid uk-grid-small uk-margin-top" uk-grid>
<div>
<notification-user [name]="user.firstname" [surname]="user.lastname"></notification-user>
</div>
<div dashboard-input [formInput]="form.get('message')"
[rows]="4" placeholder="Send a notification"
type="textarea" class="uk-width-expand">
<div tools class="uk-margin-top uk-width-1-1 uk-flex uk-flex-right">
<button *ngIf="!sending && message" (click)="sendNotification()"
class="uk-button uk-button-small uk-button-secondary">Send</button>
<button *ngIf="sending || !message" (click)="sendNotification()"
class="uk-button uk-button-small uk-button-secondary" disabled>Send</button>
<div class="uk-width-expand">
<div #recipients dashboard-input type="chips" [options]="availableGroups" [showOptionsOnEmpty]="false"
class="uk-width-expand" (focusEmitter)="onFocus($event)" placeholder="Sent to"
[formInput]="form.get('groups')">
</div>
<div dashboard-input [formInput]="form.get('message')"
[rows]="4" placeholder="Write a notification"
type="textarea" class="uk-margin-top">
<div tools class="uk-margin-top uk-width-1-1 uk-flex uk-flex-right">
<button *ngIf="!sending && message" (click)="sendNotification()"
class="uk-button uk-button-small uk-button-secondary">Send</button>
<button *ngIf="sending || !message" (click)="sendNotification()"
class="uk-button uk-button-small uk-button-secondary" disabled>Send</button>
</div>
</div>
</div>
</div>

View File

@ -2,48 +2,38 @@
--input-placeholder-color: var(--placeholder-color);
--input-background: transparent;
--input-shadow: none;
--input-padding: 20px;
--input-border: none;
--input-color: var(--grey-color);
--input-color-disabled: var(--disable-color);
--input-background-disabled: var(--muted-color);
--input-options-background: transparent;
--input-options-divider: 1px solid var(--muted-color);
--input-options-background-active: var(--table-color);
--input-options-color-active: var(--dark-color);
--input-danger-color: #BB121A;
}
/** Input Container*/
.input-container {
/** Input wrapper*/
.input-wrapper {
box-shadow: var(--input-shadow);
border: var(--input-border);
background: var(--input-background);
border-radius: 6px;
position: relative;
}
.input-container.disabled {
background-color: var(--input-background-disabled);
}
.input-container.opened {
z-index: 1;
}
/** Input wrapper*/
.input-wrapper {
padding: 20px 0 20px 20px;
padding: var(--input-padding) 0 var(--input-padding) var(--input-padding);
cursor: text;
position: relative;
color: var(--input-color);
}
.input-wrapper.danger {
border: 1px solid var(--input-danger-color);
}
.input-wrapper.select {
cursor: pointer;
}
.input-container.disabled > .input-wrapper {
.input-wrapper.disabled {
cursor: not-allowed !important;
user-select: none;
background-color: var(--input-background-disabled);
color: var(--input-color-disabled);
}
@ -57,10 +47,14 @@
overflow: hidden;
pointer-events: none;
color: var(--input-placeholder-color);
padding: 20px;
padding: var(--input-padding);
}
.input-container.disabled > .input-wrapper > .placeholder {
.input-wrapper.danger > .placeholder {
color: var(--input-danger-color);
}
.input-wrapper.disabled > .placeholder {
color: var(--input-color-disabled);
}
@ -68,100 +62,87 @@
position: absolute;
font-size: 16px;
line-height: 24px;
top: 32px;
top: calc(var(--input-padding) + 15px);
transform: translateY(-50%);
transition: all 0.5s ease 0s;
}
.input-container.focused > .input-wrapper > .placeholder > label {
.input-wrapper.focused > .placeholder > label {
top: 15px;
font-size: 12px;
line-height: 18px;
}
/* Icon */
.input-wrapper.danger .icon {
color: var(--input-danger-color);
}
/** Input */
.input-wrapper .input {
outline: 0 none !important;
box-shadow: none;
border-radius: 0;
border: 0 none;
padding: 0 20px 0 0;
padding: 0 var(--input-padding) 0 0;
background: transparent !important;
color: inherit;
width: 100%;
min-height: 24px;
min-height: 32px;
font-size: inherit;
line-height: inherit;
resize: none;
cursor: inherit;
display: flex;
flex-direction: column;
justify-content: center;
}
.input-wrapper .uk-grid .input {
min-height: 27px;
margin-top: 5px;
}
.input-wrapper .input:disabled {
background: transparent;
}
.input-wrapper .input::placeholder {
color: transparent;
.input-wrapper:not(.focused) .input.search {
opacity: 0;
}
/* Tools */
.input-wrapper > .tools {
max-height: 0;
transition: max-height 0.3s linear;
overflow: hidden;
padding-right: 20px;
}
.input-container.focused > .input-wrapper > .tools {
max-height: 100px;
padding-right: var(--input-padding);
}
/* Options */
.input-container > .options {
max-height: 0;
overflow: hidden;
transition: max-height 0.2s linear;
background: var(--input-options-background);
}
.input-container.opened > .options {
.uk-dropdown.options {
max-height: 200px;
overflow: auto;
}
.input-container > .options > ul {
margin: 0;
padding: 1px;
list-style: none;
/* Chips */
.input-wrapper .chip {
max-width: calc(100% - var(--input-padding));
margin-top: 5px;
}
.input-container > .options > ul > li > a {
padding: 10px 15px;
background: transparent;
color: var(--input-placeholder-color);
display: block;
.input-wrapper .chip .uk-label {
padding: 5px 20px;
}
.input-container > .options > ul > li:nth-child(n+2) {
border-top: var(--input-options-divider);
}
.input-container > .options > ul > li:last-child {
border-radius: 0 0 6px 6px;
}
.input-container > .options > ul > li:hover > a, .input-container > .options > ul > li.uk-active > a{
background: var(--input-options-background-active);
color: var(--input-options-color-active);
font-weight: 600;
}
/** Modifiers */
/** Modifiers */
.inner {
--input-shadow: var(--shadow-inset);
--input-background: var(--default-color);
--input-options-background: transparent;
--input-options-border: none;
}
.flat {
--input-background: var(--light-color);
--input-border: 1px solid var(--muted-color);
--input-options-background: transparent;
--input-options-border: none;
}

View File

@ -14,10 +14,7 @@ import {
} from "@angular/core";
import {AbstractControl, FormArray, FormControl, ValidatorFn} from "@angular/forms";
import {HelperFunctions} from "../../utils/HelperFunctions.class";
import {Observable, of, Subscription} from "rxjs";
import {MatAutocompleteSelectedEvent} from "@angular/material/autocomplete";
import {map, startWith} from "rxjs/operators";
import {MatChipInputEvent} from "@angular/material/chips";
import {Subscription} from "rxjs";
import {EnvProperties} from "../../utils/properties/env-properties";
import {properties} from "../../../../environments/environment";
@ -28,6 +25,8 @@ export interface Option {
label: string
}
declare var UIkit;
/**
* WARNING! dashboard-input selector is @deprecated, use input instead
*
@ -35,131 +34,68 @@ export interface Option {
@Component({
selector: '[dashboard-input], [input]',
template: `
<div class="input-container" [ngClass]="inputClass" [class.disabled]="formControl.disabled"
[class.focused]="(focused && type !== 'select') || formControl.value" [class.opened]="opened">
<div #inputBox class="input-wrapper" [class.select]="type === 'select'">
<div class="placeholder">
<label>{{placeholder}} <sup *ngIf="required">*</sup></label>
</div>
<div class="uk-flex" [class.uk-flex-middle]="type !== 'textarea'">
<ng-template [ngIf]="type === 'text' || type === 'URL' || type === 'logoURL'">
<input #input class="input" [formControl]="formAsControl">
</ng-template>
<ng-template [ngIf]="type === 'textarea'">
<textarea #textArea class="input" [rows]="rows" [formControl]="formAsControl"></textarea>
</ng-template>
<ng-template [ngIf]="type === 'select'">
<div class="input">{{getLabel(formControl.value)}}</div>
</ng-template>
<div *ngIf="formControl.disabled || icon || type === 'select'" class="uk-margin-small-left uk-margin-right">
<icon *ngIf="formControl.disabled" [name]="'lock'" [flex]="true"></icon>
<icon *ngIf="formControl.enabled && icon" [name]="icon" [flex]="true"></icon>
<icon *ngIf="formControl.enabled && !icon" name="arrow_drop_down" [flex]="true"></icon>
<div #inputBox class="input-wrapper" [class.focused]="(focused && type !== 'select') || formAsControl?.value || formAsArray?.length > 0"
[ngClass]="inputClass" [class.disabled]="formControl.disabled" [class.select]="type === 'select'"
[class.danger]="(formControl.invalid && (formControl.touched || searchControl?.touched)) || (searchControl?.invalid && searchControl?.touched)">
<div *ngIf="!hasPlaceholder" class="placeholder">
<label>{{placeholder}} <sup *ngIf="required">*</sup></label>
</div>
<div class="uk-flex" [class.uk-flex-middle]="type !== 'textarea'">
<ng-template [ngIf]="type === 'text' || type === 'URL' || type === 'logoURL'">
<input #input class="input" [attr.placeholder]="hasPlaceholder?placeholder:null" [formControl]="formAsControl">
</ng-template>
<ng-template [ngIf]="type === 'textarea'">
<textarea #textArea class="input" [attr.placeholder]="hasPlaceholder?placeholder:null" [rows]="rows" [formControl]="formAsControl"></textarea>
</ng-template>
<ng-template [ngIf]="type === 'select'">
<div class="input">{{getLabel(formControl.value)}}</div>
</ng-template>
<ng-template [ngIf]="type === 'autocomplete'">
<div class="uk-grid uk-width-expand" uk-grid>
<div *ngIf="formControl.value" class="chip">
<div class="uk-label uk-flex uk-flex-middle">
<span>{{getLabel(formControl.value)}}</span>
<icon (click)="resetSearch($event)" class="uk-link-text uk-margin-small-left clickable" [flex]="true"
name="close" ratio="0.7"></icon>
</div>
</div>
<div class="uk-width-expand">
<input [class.uk-hidden]="formControl.value" [attr.placeholder]="hasPlaceholder?placeholder:null" #searchInput class="input search" [formControl]="searchControl">
</div>
</div>
</div>
<div class="tools">
<ng-content select="[tools]"></ng-content>
</ng-template>
<ng-template [ngIf]="type === 'chips'">
<div class="uk-grid uk-grid-small uk-grid-row-collapse uk-width-expand" uk-grid>
<div *ngFor="let chip of formAsArray.controls; let i=index" class="chip">
<div class="uk-label uk-flex uk-flex-middle">
<span class="uk-text-truncate uk-width-expand">{{getLabel(chip.value)}}</span>
<icon (click)="remove(i)" class="uk-link-text uk-margin-small-left clickable" [flex]="true"
name="close" ratio="0.7"></icon>
</div>
</div>
<div class="uk-width-expand uk-flex uk-flex-column uk-flex-center">
<input #searchInput class="input search" [attr.placeholder]="hasPlaceholder?placeholder:null" [formControl]="searchControl">
</div>
</div>
</ng-template>
<div *ngIf="formControl.disabled || icon || type === 'select'" class="uk-margin-small-left uk-margin-right icon">
<icon *ngIf="formControl.disabled" [name]="'lock'" [flex]="true"></icon>
<icon *ngIf="formControl.enabled && icon" [name]="icon" [flex]="true"></icon>
<icon *ngIf="formControl.enabled && !icon" name="arrow_drop_down" [flex]="true"></icon>
</div>
</div>
<div #optionBox class="options">
<ul *ngIf="options?.length > 1">
<li *ngFor="let option of options" [class.uk-active]="formControl.value === option.value">
<a (click)="selectOption(option)">{{option.label}}</a>
</li>
</ul>
<div class="tools">
<ng-content select="[tools]"></ng-content>
</div>
</div>
<!--<ng-template [ngIf]="type === 'select'">
<div [ngClass]="inputClass"
[attr.uk-tooltip]="formControl.disabled?'title: This field is not editable; pos: bottom-left':null"
[class.clickable]="formControl.enabled"
[class.uk-form-danger]="formControl.invalid && formControl.touched" (click)="openSelect()">
<mat-form-field class="uk-width-1-1">
<mat-select #select [required]="required" [value]="null"
(openedChange)="stopPropagation()" [formControl]="formAsControl"
[disableOptionCentering]="true">
<mat-option *ngIf="placeholder" class="uk-hidden" [value]="''">{{placeholder}}</mat-option>
<mat-option *ngFor="let option of options" [value]="option.value"
[attr.uk-tooltip]="(tooltip) ? option.label : null">
{{option.label}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</ng-template>-->
<ng-template [ngIf]="type === 'autocomplete'">
<div [ngClass]="inputClass"
[attr.uk-tooltip]="formControl.disabled?'title: This field is not editable; pos: bottom-left':null"
[class.clickable]="formControl.enabled"
[class.uk-form-danger]="formControl.invalid && formControl.touched" (click)="openSelect()">
<mat-form-field class="uk-width-1-1">
<mat-chip-list #chipList>
<mat-chip *ngIf="formControl.value" [selectable]="false" [removable]="removable"
[attr.uk-tooltip]="getLabel(formControl.value)">
<span class="uk-flex uk-flex-middle uk-width-1-1">
<span class="uk-width-expand uk-text-truncate"
[class.uk-text-small]="smallChip">{{getLabel(formControl.value)}}</span>
<icon name="remove_circle" class="mat-chip-remove" [flex]="true" [ratio]="smallChip?0.8:1"
(click)="resetSearch($event)"></icon>
</span>
</mat-chip>
<div [class.uk-hidden]="formControl.value" class="uk-width-expand uk-position-relative chip-input">
<input #searchInput [formControl]="searchControl" [matAutocomplete]="auto"
[matChipInputFor]="chipList" [matAutocompleteConnectedTo]="origin">
<div *ngIf="placeholder && !searchInput.value" class="placeholder uk-width-1-1"
(click)="searchInput.focus()">{{placeholder}}</div>
</div>
<div class="uk-width-1-1 uk-invisible" matAutocompleteOrigin #origin="matAutocompleteOrigin"></div>
</mat-chip-list>
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="formControl.setValue($event.option.value)"
[class]="panelClass" [panelWidth]="panelWidth">
<mat-option *ngFor="let option of filteredOptions | async" [value]="option.value"
[attr.uk-tooltip]="option.label">
{{option.label}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</div>
</ng-template>
<ng-template [ngIf]="type === 'chips'">
<div [ngClass]="inputClass"
[attr.uk-tooltip]="formControl.disabled?'title: This field is not editable; pos: bottom-left':null"
[class.clickable]="formControl.enabled"
[class.uk-form-danger]="formControl.invalid && searchControl.invalid && searchControl.touched"
(click)="openSelect()">
<mat-form-field class="uk-width-1-1">
<mat-chip-list #chipList>
<mat-chip *ngFor="let chip of formAsArray.controls; let i=index" [selectable]="false"
[removable]="removable" [attr.uk-tooltip]="getLabel(chip.value)">
<span class="uk-flex uk-flex-middle uk-width-1-1">
<span class="uk-width-expand uk-text-truncate"
[class.uk-text-small]="smallChip">{{getLabel(chip.value)}}</span>
<icon name="remove_circle" class="mat-chip-remove" [flex]="true" [ratio]="smallChip?0.8:1"
(click)="removed(i)"></icon>
</span>
</mat-chip>
<div class="uk-width-expand uk-position-relative chip-input">
<input #searchInput style="width: calc(100% - 8px) !important;" [formControl]="searchControl"
[matAutocomplete]="auto"
[matChipInputFor]="chipList" [matAutocompleteConnectedTo]="origin"
[matChipInputAddOnBlur]="addExtraChips && searchControl.value"
(matChipInputTokenEnd)="add($event)">
<div *ngIf="placeholder && !searchControl.value" class="placeholder uk-width-1-1"
(click)="searchInput.focus()">{{placeholder}}</div>
</div>
<div class="uk-width-1-1 uk-invisible" matAutocompleteOrigin #origin="matAutocompleteOrigin"></div>
</mat-chip-list>
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)" [class]="panelClass"
[panelWidth]="panelWidth">
<mat-option *ngFor="let option of filteredOptions | async" [value]="option.value"
[attr.uk-tooltip]="option.label">
{{option.label}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</div>
</ng-template>
<span *ngIf="formControl.invalid && formControl.touched" class="uk-text-danger input-message">
<div class="options uk-dropdown" *ngIf="filteredOptions && filteredOptions.length > 1 && opened" #optionBox uk-dropdown="pos: bottom-justify; mode: hover; offset: 15;">
<ul class="uk-nav uk-dropdown-nav">
<li *ngFor="let option of filteredOptions" [class.uk-active]="formControl.value === option.value">
<a (click)="selectOption(option, $event)">{{option.label}}</a>
</li>
</ul>
</div>
<span *ngIf="formControl.invalid && formControl.touched" class="uk-text-danger">
<span *ngIf="formControl.errors.error">{{formControl.errors.error}}</span>
<span
*ngIf="type === 'URL' || type === 'logoURL'">Please provide a valid URL (e.g. https://example.com)</span>
@ -199,6 +135,7 @@ export class InputComponent implements OnInit, OnDestroy, AfterViewInit, OnChang
/** @deprecated */
@Input('hint') hint = null;
@Input('placeholder') placeholder = '';
@Input('staticPlaceholder') staticPlaceholder: boolean = false;
@Input() inputClass: string = 'inner';
/** Extra element Right or Left of the input */
/** @deprecated */
@ -233,7 +170,7 @@ export class InputComponent implements OnInit, OnDestroy, AfterViewInit, OnChang
private initValue: any;
private subscriptions: any[] = [];
/** Chips && Autocomplete*/
public filteredOptions: Observable<Option[]>;
public filteredOptions: Option[] = [];
public searchControl: FormControl;
@Input() tooltip: boolean = true;
@ViewChild('inputBox') inputBox: ElementRef;
@ -248,23 +185,12 @@ export class InputComponent implements OnInit, OnDestroy, AfterViewInit, OnChang
@HostListener('document:click', ['$event'])
click(event) {
this.focused = (this.inputBox && this.inputBox.nativeElement.contains(event.target));
if (this.focused) {
if(this.input) {
this.input.nativeElement.focus();
} else if(this.textArea) {
this.textArea.nativeElement.focus();
}
this.open(!this.opened);
} else {
this.open(false);
}
this.focusEmitter.emit(this.focused);
this.focus(this.inputBox && this.inputBox.nativeElement.contains(event.target));
}
ngOnInit() {
if(!this.formControl) {
if(Array.isArray(this.value)) {
if (!this.formControl) {
if (Array.isArray(this.value)) {
this.formControl = new FormArray([]);
this.value.forEach(value => {
this.formAsArray.push(new FormControl(value, this.validators));
@ -273,28 +199,26 @@ export class InputComponent implements OnInit, OnDestroy, AfterViewInit, OnChang
this.formControl = new FormControl(this.value);
this.formControl.setValidators(this.validators);
}
if(this.disabled) {
if (this.disabled) {
this.formControl.disable();
}
}
}
ngAfterViewInit() {
/** If options are available set max-height base on input-wrapper height */
if(this.options && this.options.length > 1) {
setTimeout(() => {
this.elementRef.nativeElement.style.maxHeight = this.inputBox.nativeElement.clientHeight + 'px';
}, 0);
}
this.reset();
}
ngOnChanges(changes: SimpleChanges) {
if (changes.formControl || changes.validators) {
if (changes.formControl || changes.validators || changes.options) {
this.reset();
}
}
ngOnDestroy(): void {
this.unsubscribe();
}
get formAsControl(): FormControl {
if (this.formControl instanceof FormControl) {
return this.formControl;
@ -311,6 +235,10 @@ export class InputComponent implements OnInit, OnDestroy, AfterViewInit, OnChang
}
}
get hasPlaceholder() {
return this.staticPlaceholder && this.type !== 'select';
}
reset() {
this.secure = true;
this.unsubscribe();
@ -318,19 +246,21 @@ export class InputComponent implements OnInit, OnDestroy, AfterViewInit, OnChang
if (this.type === 'logoURL') {
this.secure = (!this.initValue || this.initValue.includes('https://'));
}
if (this.options) {
this.filteredOptions = this.filter('');
}
if (this.type === 'chips' || this.type === 'autocomplete') {
if (this.options) {
this.filteredOptions = of(this.options);
this.searchControl = new FormControl('', this.validators);
this.subscriptions.push(this.searchControl.valueChanges.subscribe(value => {
this.searchControl = new FormControl('', this.validators);
this.subscriptions.push(this.searchControl.valueChanges.subscribe(value => {
this.filteredOptions = this.filter(value);
if (this.focused) {
this.open(true);
setTimeout(() => {
this.searchInput.nativeElement.focus();
this.searchInput.nativeElement.value = value;
}, 0);
}));
this.filteredOptions = this.searchControl.valueChanges.pipe(startWith(''),
map(option => this.filter(option)));
}
}
}));
}
if (this.formControl && this.formControl.validator) {
let validator = this.formControl.validator({} as AbstractControl);
@ -365,24 +295,14 @@ export class InputComponent implements OnInit, OnDestroy, AfterViewInit, OnChang
});
}
ngOnDestroy(): void {
this.unsubscribe();
}
stopPropagation() {
event.stopPropagation();
}
removed(index: number) {
remove(index: number) {
this.formAsArray.removeAt(index);
this.formAsArray.markAsDirty();
this.searchControl.setValue('');
this.stopPropagation();
}
selected(event: MatAutocompleteSelectedEvent): void {
this.formAsArray.push(new FormControl(event.option.value));
this.formAsArray.markAsDirty();
this.focus(true);
this.searchControl.setValue('');
this.stopPropagation();
}
@ -399,13 +319,13 @@ export class InputComponent implements OnInit, OnDestroy, AfterViewInit, OnChang
return options.filter(option => option.label.toLowerCase().indexOf(filterValue) != -1);
}
add(event: MatChipInputEvent) {
if (this.addExtraChips && event.value && this.searchControl.valid) {
add() {
if (this.addExtraChips && this.searchControl.value && this.searchControl.valid) {
this.stopPropagation();
this.formAsArray.push(new FormControl(event.value, this.validators));
this.formAsArray.push(new FormControl(this.searchControl.value, this.validators));
this.formAsArray.markAsDirty();
this.focus(true);
this.searchControl.setValue('');
this.searchInput.nativeElement.value = '';
}
}
@ -414,23 +334,65 @@ export class InputComponent implements OnInit, OnDestroy, AfterViewInit, OnChang
return (option) ? option.label : value;
}
focus(value: boolean) {
if(this.focused) {
this.formControl.markAsTouched();
}
this.focused = value;
if (this.focused) {
if (this.input) {
this.input.nativeElement.focus();
} else if (this.textArea) {
this.textArea.nativeElement.focus();
} else if (this.searchInput) {
this.searchInput.nativeElement.focus();
}
if (this.type === 'select') {
this.open(!this.opened);
} else if (this.type !== 'autocomplete' || !this.formControl.value) {
this.open(true);
}
} else {
this.open(false);
if (this.searchControl) {
this.add();
}
}
this.focusEmitter.emit(this.focused);
}
open(value: boolean) {
this.opened = value && this.formControl.enabled;
setTimeout(() => {
this.optionBox.nativeElement.style.overflow = this.opened?'auto':'hidden';
}, this.opened?200:0);
if(this.optionBox) {
if (this.opened) {
UIkit.dropdown(this.optionBox.nativeElement).show();
} else {
UIkit.dropdown(this.optionBox.nativeElement).hide();
}
}
}, 0);
}
resetSearch(event: any) {
event.stopPropagation();
this.searchControl.setValue('');
this.formControl.markAsDirty();
this.formControl.setValue(null);
this.focus(true);
this.searchControl.setValue('');
}
selectOption(option: Option) {
if(this.formAsControl) {
this.formAsControl.setValue(option.value);
selectOption(option: Option, event) {
if(this.formControl.enabled) {
if (this.formAsControl) {
this.formAsControl.setValue(option.value);
} else if (this.formAsArray) {
this.formAsArray.push(new FormControl(option.value));
this.formAsArray.markAsDirty();
event.stopPropagation();
this.focus(true);
this.searchControl.setValue('');
}
}
}
}