Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ describe('IgxInput', () => {
RequiredTwoWayDataBoundInputComponent,
DataBoundDisabledInputComponent,
ReactiveFormComponent,
InputsWithSameNameAttributesComponent
InputsWithSameNameAttributesComponent,
ToggleRequiredWithNgModelInputComponent
],
imports: [
IgxInputGroupModule,
Expand Down Expand Up @@ -247,6 +248,7 @@ describe('IgxInput', () => {
});

it('When updating two inputs with same attribute names through ngModel, label should responds', fakeAsync(() => {

const fix = TestBed.createComponent(InputsWithSameNameAttributesComponent);
fix.detectChanges();

Expand Down Expand Up @@ -319,6 +321,116 @@ describe('IgxInput', () => {
fix.detectChanges();
expect(firstInputGroup.nativeElement.classList.contains('igx-input-group--invalid')).toBe(true);
}));

it('Should style input when required is toggled dynamically.', () => {
const fixture = TestBed.createComponent(ToggleRequiredWithNgModelInputComponent);
fixture.detectChanges();

const instance = fixture.componentInstance;
const input = instance.igxInputs.toArray()[1];
const inputGroup = instance.igxInputGroups.toArray()[1];

expect(input.required).toBe(false);
expect(inputGroup.isRequired).toBeFalsy();
expect(input.valid).toBe(IgxInputState.INITIAL);
expect(inputGroup.element.nativeElement.classList.contains(INPUT_GROUP_REQUIRED_CSS_CLASS)).toBe(false);

dispatchInputEvent('focus', input.nativeElement, fixture);
expect(input.valid).toBe(IgxInputState.INITIAL);

input.value = '123';
dispatchInputEvent('input', input.nativeElement, fixture);
expect(input.valid).toBe(IgxInputState.INITIAL);
expect(inputGroup.element.nativeElement.classList.contains(INPUT_GROUP_VALID_CSS_CLASS)).toBe(false);

dispatchInputEvent('blur', input.nativeElement, fixture);
expect(input.valid).toBe(IgxInputState.INITIAL);
expect(inputGroup.element.nativeElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(false);
expect(inputGroup.element.nativeElement.classList.contains(INPUT_GROUP_VALID_CSS_CLASS)).toBe(false);

instance.isRequired = true;
fixture.detectChanges();

expect(input.required).toBe(true);

expect(inputGroup.isRequired).toBeTruthy();
expect(input.valid).toBe(IgxInputState.INITIAL);
expect(inputGroup.element.nativeElement.classList.contains(INPUT_GROUP_REQUIRED_CSS_CLASS)).toBe(true);

dispatchInputEvent('focus', input.nativeElement, fixture);
expect(input.valid).toBe(IgxInputState.INITIAL);

input.value = '';
dispatchInputEvent('input', input.nativeElement, fixture);
expect(inputGroup.element.nativeElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(true);

dispatchInputEvent('blur', input.nativeElement, fixture);
expect(inputGroup.element.nativeElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(true);

input.value = '123';
dispatchInputEvent('input', input.nativeElement, fixture);
expect(inputGroup.element.nativeElement.classList.contains(INPUT_GROUP_VALID_CSS_CLASS)).toBe(true);

dispatchInputEvent('blur', input.nativeElement, fixture);
expect(input.valid).toBe(IgxInputState.INITIAL);
expect(inputGroup.element.nativeElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(false);
expect(inputGroup.element.nativeElement.classList.contains(INPUT_GROUP_VALID_CSS_CLASS)).toBe(false);
});

it('Should style input with ngModel when required is toggled dynamically.', () => {
const fixture = TestBed.createComponent(ToggleRequiredWithNgModelInputComponent);
fixture.detectChanges();

const instance = fixture.componentInstance;
const input = instance.igxInputs.toArray()[0];
const inputGroup = instance.igxInputGroups.toArray()[0];

expect(input.required).toBe(false);
expect(inputGroup.isRequired).toBeFalsy();
expect(input.valid).toBe(IgxInputState.INITIAL);
expect(inputGroup.element.nativeElement.classList.contains(INPUT_GROUP_REQUIRED_CSS_CLASS)).toBe(false);

dispatchInputEvent('focus', input.nativeElement, fixture);
expect(input.valid).toBe(IgxInputState.INITIAL);

input.value = '123';
dispatchInputEvent('input', input.nativeElement, fixture);
expect(inputGroup.element.nativeElement.classList.contains(INPUT_GROUP_VALID_CSS_CLASS)).toBe(true);

dispatchInputEvent('blur', input.nativeElement, fixture);
expect(input.valid).toBe(IgxInputState.INITIAL);
expect(inputGroup.element.nativeElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(false);
expect(inputGroup.element.nativeElement.classList.contains(INPUT_GROUP_VALID_CSS_CLASS)).toBe(false);

instance.isRequired = true;
fixture.detectChanges();

expect(input.required).toBe(true);

expect(inputGroup.isRequired).toBeTruthy();
expect(input.valid).toBe(IgxInputState.INITIAL);
expect(inputGroup.element.nativeElement.classList.contains(INPUT_GROUP_REQUIRED_CSS_CLASS)).toBe(true);

dispatchInputEvent('focus', input.nativeElement, fixture);
expect(input.valid).toBe(IgxInputState.INITIAL);

input.value = '';
dispatchInputEvent('input', input.nativeElement, fixture);
dispatchInputEvent('blur', input.nativeElement, fixture);
expect(inputGroup.element.nativeElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(true);

dispatchInputEvent('focus', input.nativeElement, fixture);
expect(inputGroup.element.nativeElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(true);

input.value = '123';
dispatchInputEvent('input', input.nativeElement, fixture);
expect(inputGroup.element.nativeElement.classList.contains(INPUT_GROUP_VALID_CSS_CLASS)).toBe(true);

dispatchInputEvent('blur', input.nativeElement, fixture);
expect(input.valid).toBe(IgxInputState.INITIAL);
expect(inputGroup.element.nativeElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(false);
expect(inputGroup.element.nativeElement.classList.contains(INPUT_GROUP_VALID_CSS_CLASS)).toBe(false);
});
});

@Component({ template: `
Expand Down Expand Up @@ -529,6 +641,26 @@ class ReactiveFormComponent {
}
}

@Component({ template: `<igx-input-group>
<label for="test" igxLabel>Test</label>
<input name="test" type="text" igxInput [(ngModel)]="data" [required]="isRequired"/>
</igx-input-group>
<igx-input-group>
<label for="test" igxLabel>Test</label>
<input name="test" type="text" igxInput [value]="data1" [required]="isRequired"/>
</igx-input-group>` })
class ToggleRequiredWithNgModelInputComponent {
@ViewChildren(IgxInputDirective)
public igxInputs: QueryList<IgxInputDirective>;

@ViewChildren(IgxInputGroupComponent)
public igxInputGroups: QueryList<IgxInputGroupComponent>;

public data = '';
public data1 = '';
public isRequired = false;
}

function testRequiredValidation(inputElement, fixture) {
dispatchInputEvent('focus', inputElement, fixture);
inputElement.value = 'test';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ export enum IgxInputState {
}

@Directive({
selector: '[igxInput]'
selector: '[igxInput]',
exportAs: 'igxInput'
})
export class IgxInputDirective implements AfterViewInit, OnDestroy {
private _valid = IgxInputState.INITIAL;
Expand Down Expand Up @@ -92,6 +93,40 @@ export class IgxInputDirective implements AfterViewInit, OnDestroy {
public get disabled() {
return this.nativeElement.hasAttribute('disabled');
}

/**
* Sets the `required` property.
* ```html
* <input-group>
* <input igxInput #igxInput [required]="true">
* </input-group>
* ```
* @memberof IgxInputDirective
*/
@Input()
public set required(value: boolean) {
if (typeof value === 'boolean') {
this.nativeElement.required = this.inputGroup.isRequired = value;

if (value && !this.nativeElement.checkValidity()) {
this._valid = IgxInputState.INVALID;
} else {
this._valid = IgxInputState.INITIAL;
}
}
}

/**
* Gets whether the igxInput is required.
* ```typescript
* let isRequired = this.igxInput.required;
* ```
* @memberof IgxInputDirective
*/
public get required() {
return this.nativeElement.hasAttribute('required');
}

/**
* Sets/gets whether the `"igx-input-group__input"` class is added to the host element.
* Default value is `false`.
Expand Down Expand Up @@ -227,16 +262,6 @@ export class IgxInputDirective implements AfterViewInit, OnDestroy {
}
}
}
/**
* Gets whether the igxInput is required.
* ```typescript
* let isRequired = this.igxInput.required;
* ```
* @memberof IgxInputDirective
*/
public get required() {
return this.nativeElement.hasAttribute('required');
}
/**
* Gets whether the igxInput has a placeholder.
* ```typescript
Expand Down Expand Up @@ -287,6 +312,18 @@ export class IgxInputDirective implements AfterViewInit, OnDestroy {
public get valid(): IgxInputState {
return this._valid;
}

/**
* Gets whether the igxInput is valid.
* ```typescript
* let valid = this.igxInput.isValid;
* ```
* @memberof IgxInputDirective
*/
public get isValid(): boolean {
return this.valid !== IgxInputState.INVALID;
}

/**
* Sets the state of the igxInput.
* ```typescript
Expand Down
10 changes: 10 additions & 0 deletions src/app/input-group/input-group.sample.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@
<div class="samples">
<input-group-child-sample></input-group-child-sample>

<h3 class="sample-title">Line Style Input with required @Input</h3>
<form class="form">
<igx-input-group>
<label igxLabel>Required</label>
<input igxInput #myInput="igxInput" [value]="value" [required]="isRequired"/>
<igx-hint *ngIf="!myInput.isValid">This is required</igx-hint>
</igx-input-group>
<button igxButton (click)="toggleRequired()">Toggle required</button>
</form>

<h3 class="sample-title">Line Style Input</h3>
<form class="form">
<!-- Basic text field -->
Expand Down
7 changes: 7 additions & 0 deletions src/app/input-group/input-group.sample.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,11 @@ export class InputGroupSampleComponent {
firstName: 'Oke',
lastName: 'Nduka'
};

public isRequired = true;
public value = '';

public toggleRequired() {
this.isRequired = !this.isRequired;
}
}
25 changes: 23 additions & 2 deletions src/app/time-picker/time-picker.sample.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<section class="sample-content">
<article class="timepicker-column">
<h4 class="sample-title">Time Picker with Dropdown</h4>
<div class="sample-description">{{showDate()}}</div>
<div class="sample-description">{{showDate(date)}}</div>
<div class="preview" style="width: 200px">
<igx-time-picker #tp (onValueChanged)="valueChanged($event)"
(onValidationFailed)="validationFailed($event)" [mode]="mode" [isSpinLoop]="isSpinLoop"
Expand All @@ -16,7 +16,6 @@ <h4 class="sample-title">Time Picker with Dropdown</h4>
<article class="timepicker-column">
<h4 class="sample-title">Horizontal Time Picker</h4>
<p class="sample-description">AM/PM Time format</p>
<p class="sample-description"> </p>
<div class="preview">
<igx-time-picker format="h:mm tt"></igx-time-picker>
</div>
Expand Down Expand Up @@ -51,5 +50,27 @@ <h4 class="sample-title">Templated Time Picker</h4>
</igx-time-picker>
</div>
</article>
<article class="timepicker-column">
<h4 class="sample-title">Templated Time Picker</h4>
<p class="sample-description">Time picker with required input group</p>
<div class="preview">
<igx-time-picker #templatedTimePicker [value]="today">
<ng-template igxTimePickerTemplate
let-openDialog="openDialog"
let-value="value">
<igx-input-group [supressInputAutofocus]="true">
<label igxLabel>Required</label>
<igx-prefix (click)="openDialog()">
<igx-icon>access_time</igx-icon>
</igx-prefix>
<input igxInput [value]="showDate(value)" [required]="isRequired"/>
<igx-suffix igxRipple (click)="change()">
<igx-icon fontSet="material">star</igx-icon>
</igx-suffix>
</igx-input-group>
</ng-template>
</igx-time-picker>
</div>
</article>
</section>
</div>
25 changes: 16 additions & 9 deletions src/app/time-picker/time-picker.sample.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,29 @@ import { IgxTimePickerComponent, InteractionMode } from 'igniteui-angular';
templateUrl: 'time-picker.sample.html'
})
export class TimePickerSampleComponent {
max = "19:00";
min = "09:00";
max = '19:00';
min = '09:00';

itemsDelta = { hours: 1, minutes: 5 };
format = "hh:mm tt";
format = 'hh:mm tt';
isSpinLoop = true;
isVertical = true;
public mode = InteractionMode.DropDown;
mode = InteractionMode.DropDown;

date = new Date(2018, 10, 27, 17, 45, 0, 0);
today = new Date(Date.now());

showDate() {
return this.date ? this.date.toLocaleString() : 'Value is null.';
isRequired = true;

@ViewChild('tp', { read: IgxTimePickerComponent })
public tp: IgxTimePickerComponent;

showDate(date) {
return date ? date.toLocaleString() : 'Value is null.';
}

change() {
this.isRequired = !this.isRequired;
}

valueChanged(event) {
Expand All @@ -29,7 +39,4 @@ export class TimePickerSampleComponent {
validationFailed(event) {
console.log(event);
}

@ViewChild('tp', { read: IgxTimePickerComponent })
public tp: IgxTimePickerComponent;
}