Skip to content

Instantly share code, notes, and snippets.

@aegyed91
Created November 30, 2016 14:01
Show Gist options
  • Save aegyed91/4d5f75faac28101081721f6ce36d876b to your computer and use it in GitHub Desktop.
Save aegyed91/4d5f75faac28101081721f6ce36d876b to your computer and use it in GitHub Desktop.
address google api places typeahead angular 2 formgroup integrated hax thing
<div class="form-group" [ngClass]="{'has-danger': feedback && !state.valid && !state.control.pristine }">
<label *ngIf="label" class="form-control-label">{{label}}</label>
<ng-content></ng-content>
<div *ngIf="feedback && !state.valid && !state.pristine">
<div *ngIf="state.hasError('required')" class="form-control-feedback">Required field.</div>
<div *ngIf="state.hasError('minlength')" class="form-control-feedback">Has to be at least {{state.getError('minlength').requiredLength}} characters long.</div>
<div *ngIf="state.hasError('maxlength')" class="form-control-feedback">Has to be less than {{state.getError('maxlength').requiredLength}} characters long.</div>
<div *ngIf="state.hasError('incorrectFileExtension')" class="form-control-feedback">File extension has to be <code>{{state.getError('incorrectFileExtension').requiredFileExtension}}</code>.</div>
<div *ngIf="state.hasError('incorrectFileSize')" class="form-control-feedback">File size has to be between <code>{{state.getError('incorrectFileSize').requiredMinFileSize / 1024}} - {{state.getError('incorrectFileSize').requiredMaxFileSize / 1024}} kilobyte</code>.</div>
<div *ngIf="state.hasError('invalidEmail')" class="form-control-feedback">Invalid email address.</div>
<div *ngIf="state.hasError('invalidTime')" class="form-control-feedback">Time has to be between <code>{{(state.getError('invalidTime').reqMinHour) | amDateFormat: state.getError('invalidTime').is24Hrs ? 'HH:mm' : 'hh:mmA'}}</code> - <code>{{(state.getError('invalidTime').reqMaxHour) | amDateFormat: state.getError('invalidTime').is24Hrs ? 'HH:mm' : 'hh:mmA'}}</code>.</div>
<!-- NON GENERAL ERR MESSAGES -->
<div *ngIf="state.control.hasError('uniqueProjectName')" class="form-control-feedback">Project name is not unique.</div>
</div>
<div *ngIf="debug">
<pre><code>{{state.control.errors | json}}</code></pre>
<pre><code>{{state.control.value | json}}</code></pre>
</div>
</div>
import { Component, ContentChild, Input } from '@angular/core';
import { FormControlName } from '@angular/forms';
import { IS_DEV } from '../../constants';
@Component({
selector: 'form-group-c',
templateUrl: './form-group.c.html',
styles: [`
:host { display: block; }
`]
})
export class FormGroupC {
@Input() label: string;
@Input() feedback = true;
@Input() debug = false && IS_DEV;
@ContentChild(FormControlName) state;
}
<form [formGroup]="form" novalidate (submit)="onSubmit($event, form.value)">
<div formGroupName="available" class="row">
<div class="col-sm-6">
<form-group-c label="Available from *">
<ngb-timepicker formControlName="from"></ngb-timepicker>
</form-group-c>
</div>
<div class="col-sm-6">
<form-group-c label="Available until *">
<ngb-timepicker formControlName="until"></ngb-timepicker>
</form-group-c>
</div>
</div>
<form-group-c label="Minimum time between two meeting">
<ngb-timepicker [meridian]="false" formControlName="timeBw2Meetin"></ngb-timepicker>
</form-group-c>
<form-group-c label="Preferred meeting places">
<input #typeahead type="text" class="form-control" [ngbTypeahead]="search"
[resultFormatter]="formatter" [inputFormatter]="formatter" (selectItem)="selectPlace($event, typeahead)"/>
<span *ngIf="searching">searching...</span>
<div class="form-control-feedback" *ngIf="searchFailed">Sorry, suggestions could not be loaded.</div>
<div *ngIf="selectedPlaces.length" class="multiselect-container">
<span *ngFor="let place of selectedPlaces" class="multiselect-item btn btn-secondary btn-sm">
<a class="close" (click)="remove(place)">×</a>
<span>{{place}}</span>
</span>
</div>
<select multiple formControlName="prefPlaces" class="form-control hidden-xs-up">
<option *ngFor="let place of selectedPlaces" [value]="place" selected>{{place}}</option>
</select>
</form-group-c>
<form-group-c label="Send notification X hours/minutes before meeting">
<ngb-timepicker [meridian]="false" formControlName="notifyB4"></ngb-timepicker>
</form-group-c>
<form-group-c label="Maximum length of a meeting">
<ngb-timepicker [meridian]="false" formControlName="maxLen"></ngb-timepicker>
</form-group-c>
<form-group-c label="How many meetings per day">
<input formControlName="numPerDay" class="form-control" type="number">
</form-group-c>
<button-c btnCls="btn-primary btn-lg btn-block" [isLoding]="submitPending" [disabled]="submitPending || !form.valid">
Submit
</button-c>
<alert-list-c [alerts]="formAlerts">
<hr>
</alert-list-c>
</form>
<hr>
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators, FormArray } from '@angular/forms';
import { IAlert, IPreferencesData, ITimePicker } from '../../../../shared/interfaces';
import { ResMsgHandlerS } from '../../../../shared/services/res-msg-handler.s';
import { UserSt } from '../../user.st';
import { UserS } from '../../user.s';
import { NgbTimepickerConfig, NgbTypeaheadSelectItemEvent } from '@ng-bootstrap/ng-bootstrap';
import { GoogPlacesS } from '../../../../shared/services/goog-places.s';
import { required } from '../../../../shared/validators/index';
import { Observable } from 'rxjs';
// import { timepicker } from '../../../../shared/validators/index';
@Component({
selector: 'preferences-c',
templateUrl: './preferences.c.html',
styleUrls: ['./preferences.c.css'],
providers: [NgbTimepickerConfig]
})
export class PreferencesC implements OnInit {
form: FormGroup;
submitPending = false;
formAlerts: IAlert[] = [];
searching = false;
searchFailed = false;
selectedPlaces: string[] = [];
selectPlace(evt: NgbTypeaheadSelectItemEvent, self) {
evt.preventDefault();
self.value = '';
this.selectedPlaces.push(evt.item.formatted_address);
this.notifyPrefPlacesControl();
}
remove(item: string) {
this.selectedPlaces.splice(this.selectedPlaces.indexOf(item), 1);
this.notifyPrefPlacesControl();
}
notifyPrefPlacesControl() {
this.form.get('prefPlaces').setValue(this.selectedPlaces);
this.form.get('prefPlaces').markAsDirty();
this.form.get('prefPlaces').markAsTouched();
}
constructor(private formBuilder: FormBuilder, private timePickerConf: NgbTimepickerConfig, private mh: ResMsgHandlerS,
public userSt: UserSt, public userS: UserS, private googPlacesS: GoogPlacesS) {
Object.assign(this.timePickerConf, {
meridian: true,
seconds: false,
minuteStep: 15
});
this.selectedPlaces.push(...this.userSt.get('meetinPref.prefPlaces'));
}
ngOnInit() {
this.form = this.formBuilder.group({
available: this.formBuilder.group({
from: [this.dateToTimePickerObj(this.userSt.get('meetinPref.available.from')), [Validators.required/*timepicker(10, 18, this.is24Hours)*/]],
until: [this.dateToTimePickerObj(this.userSt.get('meetinPref.available.until')), [Validators.required]]
}),
timeBw2Meetin: [this.dateToTimePickerObj(this.userSt.get('meetinPref.timeBw2Meetin')), [Validators.required]],
prefPlaces: [this.selectedPlaces, [required()]],
notifyB4: [this.dateToTimePickerObj(this.userSt.get('meetinPref.notifyB4')), [Validators.required]],
maxLen: [this.dateToTimePickerObj(this.userSt.get('meetinPref.maxLen')), [Validators.required]],
numPerDay: [this.userSt.get('meetinPref.numPerDay'), [Validators.required]]
});
}
search = (text$: Observable<string>) => {
return text$
.debounceTime(300)
.distinctUntilChanged()
.do(() => this.searching = true)
.switchMap(query =>
Observable.fromPromise(this.googPlacesS.search(query))
.do(() => this.searchFailed = false)
.catch(() => {
this.searchFailed = true;
return Observable.of([]);
}))
.do(() => this.searching = false);
};
formatter(x) {
return x.formatted_address;
};
onSubmit(evt, data: IPreferencesData) {
evt.preventDefault();
this.submitPending = true;
const normData = Object.assign(data, {
available: {
from: this.TimePickerObjToDate(data.available.from),
until: this.TimePickerObjToDate(data.available.until)
},
timeBw2Meetin: this.TimePickerObjToDate(data.timeBw2Meetin),
notifyB4: this.TimePickerObjToDate(data.notifyB4),
maxLen: this.TimePickerObjToDate(data.maxLen)
});
this.userS.setMeetingPref(normData).then(res => {
this.userSt.assign(res.user);
this.submitPending = false;
this.mh.showInToastr(res.message);
}).catch(err => {
this.mh.showInToastr(err, 1);
this.submitPending = false;
});
}
TimePickerObjToDate(tData: ITimePicker) {
const d = new Date();
d.setMilliseconds(0);
d.setSeconds(0);
d.setMinutes(tData.minute);
d.setHours(tData.hour);
return d;
}
dateToTimePickerObj(timestamp) {
const d = new Date(timestamp);
return {
hour: d.getHours(),
minute: d.getMinutes()
};
}
}
import { ValidatorFn, AbstractControl } from '@angular/forms';
import { isNull, isEmpty } from 'lodash';
export function requiredValidator(): ValidatorFn {
return (control: AbstractControl): {[key: string]: any} => {
if (isNull(control.value) || isEmpty(control.value)) {
return {required: true};
}
return null;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment