Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(form): map field #44

Merged
merged 2 commits into from
May 8, 2017
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
31 changes: 31 additions & 0 deletions src/demo-app/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,35 @@
</md-card-content>
</md-card>

<md-card>
<md-card-subtitle>Form module</md-card-subtitle>
<md-card-title>map-field.component</md-card-title>
<md-card-content>
<form [formGroup]="demoForm">

<div class="igo-map-field-container">
<igo-map-field
formControlName="location"
[placeholder]="'Location' | translate"
[decimals]="8"
[readonly]="false"
[layers]="map.layers$ | async"
[view]="contextService.context$.value ? (contextService.context$ | async).map.view : undefined">
</igo-map-field>
</div>

<div class="igo-form-button-group">
<button
md-raised-button
type="button"
[disabled]="!demoForm.valid"
(click)="handleFormSubmit(demoForm.value, demoForm.valid)">
{{'Submit' | translate}}
</button>
</div>

</form>
</md-card-content>
</md-card>

</md-sidenav-container>
7 changes: 6 additions & 1 deletion src/demo-app/app/app.component.styl
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,9 @@ md-sidenav {
md-sidenav p {
width: 200px;
padding: 20px;
}
}

.igo-map-field-container {
width: 300px;
height: 200px;
}
20 changes: 19 additions & 1 deletion src/demo-app/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms';

import { ContextService, Feature, FeatureService, IgoMap,
LanguageService, MessageService, OverlayService,
Expand All @@ -13,13 +14,19 @@ export class AppComponent implements OnInit {

public map = new IgoMap();
public searchTerm: string;
public demoForm: FormGroup;

get locationField () {
return (<FormControl>this.demoForm.controls['location']);
}

constructor(public contextService: ContextService,
public featureService: FeatureService,
public messageService: MessageService,
public overlayService: OverlayService,
public toolService: ToolService,
public language: LanguageService) {}
public language: LanguageService,
private formBuilder: FormBuilder) {}

ngOnInit() {
// If you do not want to load a context from a file,
Expand All @@ -28,6 +35,12 @@ export class AppComponent implements OnInit {
// as the contexts in ../contexts/

this.contextService.loadContext('_default');

this.demoForm = this.formBuilder.group({
location: ['', [
Validators.required
]]
});
}

handleSearch(term: string) {
Expand All @@ -50,4 +63,9 @@ export class AppComponent implements OnInit {
this.featureService.unfocusFeature();
this.overlayService.clear();
}

handleFormSubmit(data: any, isValid: boolean) {
console.log(data);
console.log(isValid);
}
}
4 changes: 3 additions & 1 deletion src/demo-app/assets/locale/en.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{
"Search for an address or a place": "Search for an address or a place"
"Location": "Location",
"Search for an address or a place": "Search for an address or a place",
"Submit": "Submit"
}
4 changes: 3 additions & 1 deletion src/demo-app/assets/locale/fr.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{
"Search for an address or a place": "Rechercher une adresse, un lieu ou une couche"
"Location": "Localisation",
"Search for an address or a place": "Rechercher une adresse, un lieu ou une couche",
"Submit": "Soumettre"
}
1 change: 1 addition & 0 deletions src/lib/form/fields/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './map-field';
1 change: 1 addition & 0 deletions src/lib/form/fields/map-field/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './map-field.component';
11 changes: 11 additions & 0 deletions src/lib/form/fields/map-field/map-field.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<div>
<md-input-container>
<input
mdInput
[placeholder]="placeholder"
[readonly]="readonly"
[ngModel]="value"
(ngModelChange)="handleValueChange($event)">
</md-input-container>
<igo-map-browser [map]="map" [view]="view"></igo-map-browser>
</div>
34 changes: 34 additions & 0 deletions src/lib/form/fields/map-field/map-field.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { IgoSharedModule } from '../../../shared';
import { MapBrowserComponent } from '../../../map';

import { MapFieldComponent } from './map-field.component';

describe('MapFieldComponent', () => {
let component: MapFieldComponent;
let fixture: ComponentFixture<MapFieldComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
IgoSharedModule,
],
declarations: [
MapBrowserComponent,
MapFieldComponent
]
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(MapFieldComponent);
component = fixture.componentInstance;
});

it('should create', () => {
expect(component).toBeTruthy();
});

});
15 changes: 15 additions & 0 deletions src/lib/form/fields/map-field/map-field.component.styl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
@require '../../../../style/var.styl';

:host {
position: relative;
display: block;
}

:host, .igo-map-browser-target {
width: 100%;
height: 100%;
}

input {
width: 100%
}
153 changes: 153 additions & 0 deletions src/lib/form/fields/map-field/map-field.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import { Component, Input, forwardRef,
AfterViewInit, OnDestroy } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

import { IgoMap, MapViewOptions } from '../../../map';
import { Layer } from '../../../layer';


@Component({
selector: 'igo-map-field',
templateUrl: './map-field.component.html',
styleUrls: ['./map-field.component.styl'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => MapFieldComponent),
multi: true
}
]
})
export class MapFieldComponent
implements AfterViewInit, OnDestroy, ControlValueAccessor {

@Input()
get placeholder() { return this._placeholder; }
set placeholder(value: string) {
this._placeholder = value;
}
private _placeholder: string;

@Input()
get decimals(): number { return this._decimals; }
set decimals(value: number) {
this._decimals = value;
}
private _decimals: number = 6;

@Input()
get readonly(): boolean { return this._readonly; }
set readonly(value: boolean) {
this._readonly = value;
}
protected _readonly: boolean = false;

@Input()
get value(): [number, number] { return this._value; }
set value(value: [number, number]) {
this.map.clearOverlay();

if (value === undefined) {
this._value = value;
this.onChange(this._value);
return;
}

if (!isNaN(+value[0]) && !isNaN(+value[1])) {
const values = [+value[0], +value[1]] as [number, number];

this.addOverlay(values);

this._value = [
+values[0].toFixed(this.decimals),
+values[1].toFixed(this.decimals)
];

this.onChange(this._value);
this.onTouched();
}
}
private _value: [number, number];

@Input()
get view(): MapViewOptions { return this._view; }
set view(value: MapViewOptions) {
this._view = value;
if (this.map !== undefined) {
this.map.setView(value);
}
}
protected _view: MapViewOptions;

@Input()
get layers(): Layer[] { return this._layers; }
set layers(value: Layer[]) {
this._layers = value;
this.map.removeLayers();
this.map.addLayers(value);
}
private _layers: Layer[];

public map = new IgoMap();
public projection = 'EPSG:4326';

onChange: any = () => {};
onTouched: any = () => {};

constructor() {}

ngAfterViewInit() {
this.map.olMap.on('singleclick', this.handleMapClick, this);
}

ngOnDestroy() {
this.map.olMap.un('singleclick', this.handleMapClick, this);
}

registerOnChange(fn: Function) {
this.onChange = fn;
}

registerOnTouched(fn: Function) {
this.onTouched = fn;
}

writeValue(value: [number, number]) {
if (value) {
this.value = value;
}
}

handleValueChange(value: string) {
this.value = this.parseValue(value);
}

private handleMapClick(event: ol.MapBrowserEvent) {
this.value = ol.proj.transform(
event.coordinate, this.map.projection, this.projection);
}

private parseValue(value: string): [number, number] | undefined {
if (value === undefined || value === '') {
return undefined;
}

const values = value.split(',').filter(v => v !== '');
if (values.length === 2) {
return [+values[0], +values[1]];
}

return undefined;
}

private addOverlay(coordinates: [number, number]) {
const geometry = new ol.geom.Point(
ol.proj.transform(coordinates, this.projection, this.map.projection));
const extent = geometry.getExtent();
const feature = new ol.Feature({geometry: geometry});

this.map.moveToExtent(extent);
this.map.addOverlay(feature);
}

}
1 change: 1 addition & 0 deletions src/lib/form/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './module';
30 changes: 30 additions & 0 deletions src/lib/form/module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { NgModule, ModuleWithProviders } from '@angular/core';

import { IgoSharedModule } from '../shared';
import { IgoMapModule } from '../map';

import { MapFieldComponent } from './fields/map-field';


@NgModule({
imports: [
IgoSharedModule,
IgoMapModule
],
exports: [
MapFieldComponent
],
declarations: [
MapFieldComponent
]
})
export class IgoFormModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: IgoFormModule,
providers: []
};
}
}

export * from './fields';
10 changes: 6 additions & 4 deletions src/lib/map/map-browser/map-browser.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,19 @@ export class MapBrowserComponent implements AfterViewInit {
set map(value: IgoMap) {
this._map = value;
}
private _map: IgoMap;
protected _map: IgoMap;

@Input()
get view(): MapViewOptions { return this._view; }
set view(value: MapViewOptions) {
this._view = value;
this.map.setView(value);
if (this.map !== undefined) {
this.map.setView(value);
}
}
private _view: MapViewOptions;
protected _view: MapViewOptions;

public id: string = 'igo-map-target';
public id: string = `igo-map-target-${new Date().getTime()}`;

constructor() {}

Expand Down
Loading