In openlayers 5 I have a vector layer and I try to create code to get the properties of a feature after it is clicked.
This is my code so far
var selectClick = new Select({
condition: click,
layers:this.vectorlayer
});
this.olmap.addInteraction(selectClick);
var selectedFeatures = selectClick.getFeatures();
and then I have tried
selectClick.on('select', ()=>{console.log(selectedFeatures);});
and
selectedFeatures.on('add', function(event) {
console.log( selectClick.getFeatures());
});
and I get
ERROR TypeError: arr.indexOf is not a function
in both cases.
What am I doing wrong? My ultimate goal is to do something like
selectClick.getFeatures().feature.properties.id, since the geoJSON I am loading, also has some metadata properties in it.
So, how can I get the selected feature ?
Thanks
Another "whoops" moment. The error had to do with the syntax of the selectClick and how I set the layers var. I set the this.vectorlayer just as a var, but it should be inside an array, hence the array-related, indexOf error.
The code in ol5+angular6 now is
this.vectorsource = new VectorSource({});
this.vectorlayer = new VectorLayer({
source: this.vectorsource
});
this.view = new OlView({
center: OlProj.fromLonLat([6.661594, 50.433237]),
zoom: 2,
});
this.olmap = new OlMap({
target: 'map',
layers: [this.tilelayer,this.vectorlayer],
view: this.view,
projection: 'EPSG:3857'
});
var selectClick = new Select({
condition: click,
layers:[this.vectorlayer]//this should be in an array, you silly codebot
});
this.olmap.addInteraction(selectClick);
selectClick.on(
'select', function(){
console.log(selectClick.getFeatures().item(0).values_);// contains metadata properties of geoJSON
}
);
Thanks
Related
I have a List, bound to an entityset from mainService. Same view contains a filter field. Once user enters some filtering criteria, the read should happen. I am already reading the OData entityset, results are coming back. But I have no luck to let the table be bound to that result
The binding in XML View
<List
id="list"
width="auto"
class="sapFDynamicPageAlignContent"
items= "{/ItProjHeadSet}"
busyIndicatorDelay="{masterView>/delay}"
noDataText="{masterView>/noDataText}"
mode="{= ${device>/system/phone} ? 'None' : 'SingleSelectMaster'}"
growing="true"
growingScrollToLoad="true"
updateFinished=".onUpdateFinished"
selectionChange=".onSelectionChange">
Then, when the GO button of the smart filter bar is clicked, I am triggering the onSearch event as follows:
onSearchProjects : function (oEvent) {
var oMasterPage = this.getView().byId("masterPage");
var that = this;
var aTokens = this._oMultiInput.getTokens();
var aMultiFilters = aTokens.map(function (oToken) {
var oProperties = oToken.data("range");
return new Filter({
path: oProperties.keyField,
operator: FilterOperator[oProperties.operation],
value1: oProperties.value1,
value2: oProperties.value2
});
});
oMasterPage.setBusy(true);
//Filter
this.getOwnerComponent().getModel().read("/ItProjHeadSet", {
filters: aMultiFilters,
success: function (oData) {
var list = that.getView().byId("list");
var projectModel = new JSONModel(oData);
var oModel = that.getView().getModel("/ItProjHeadSet");
oModel.setData(projectModel);
oModel.updateBindings(true);
error: function (oData) {
MessageToast.show(that.getResourceBundle().getText("noProjectsFetched"));
}
});
oMasterPage.setBusy(false);
},
The problem then is that although I am receiving the corresponding successful results in the read, the setData seems that it is happening to a different model than the one bound to the list.
Am I doing the right model update in the Success read?
Regards,
Martin
Solved by my own, by getting the list binding then applying filters:
List.getBinding("items").filter(aMultiFilters, "Application");
then there was no need to getOwnerComponent and all that
In my openlayers 5 (based on a angular 6 app), I am implementing a functionality where you search for something, query the db, the db brings back some geoJSON and I render this geoJSON data in a ol vector layer.
There are two different ways to search, so there are two different forms that bring back geoJSOn to the same ol vector.
Of course, before rendering the data, I have to clear out the layer.
This is my code
ngOnInit() {//initialize some params and the ol map
//bring results-as you type - pure angular
this.results = this.myForm.valueChanges.pipe(
switchMap( formdata => this.mapcmsService.searchName(formdata.name, formdata.cepDrop))
);//pipe
this.tilesource = new OlXYZ({
url:'http://tile.stamen.com/terrain/{z}/{x}/{y}.jpg'
});
this.tilelayer = new OlTileLayer({
source: this.tilesource
});
this.vectorsource = new VectorSource({});
this.vectorlayer = new VectorLayer({
source: this.vectorsource
});
this.view = new OlView({
center: OlProj.fromLonLat([6.661594, 50.433237]),
zoom: 2,
});
this.olmap = new OlMap({
target: 'map',
layers: [this.tilelayer,this.vectorlayer],
view: this.view,
projection: 'EPSG:3857'
});
const selectClick = new Select({
condition: click,
layers:[this.vectorlayer]
});
this.olmap.addInteraction(selectClick);
selectClick.on(
'select', ()=>{
const values = selectClick.getFeatures().item(0).values_;
this.getDetails(values.id);
}
);
} //closes ngOnInit
Outside the ngOnInit, after the initialization,there are the two different functions that bring geoJSON to the same ol vector layer. They basically do the same thing.
searchById(id){
this.map_loading = true;
this.myService.getById(id).subscribe((data) =>{
this.vectorsource.refresh();
this.vectorsource.clear();
const fff = (new GeoJSON()).readFeatures(data.data);
this.vectorsource.addFeatures(fff);
this.map_loading = false;
})
}//searchById
and
searchCategories(){
this.map_loading = true;
this.myService.categoriesSearch(this.categoriesForm.value).subscribe((data) =>{
this.vectorsource.refresh();
this.vectorsource.clear();
const fff = (new GeoJSON()).readFeatures(data.data);
this.vectorsource.addFeatures(fff);
this.map_loading = false;
})
}//searchCategories
The problem is that the ol vector source is not always cleared before new features are added. I search for something, features are rendered. I search again , and sometimes, the old features remain on the map, along with the new ones.
I did a silly move to add refresh with clean and nothing is fixed. This is not standard, eg every other search. This randomly happen and I dont have a clue how to debug it. Please advice
Thanks
Is there an unique id for each feature?
I had the same problem that features were loaded constantly. I used the bbox-strategy and every time I moved the map, it loaded all the features in the extent, even if they were already there.
I had to set an unique id in the data for my features, so OpenLayers can refer to the existing ones if you load new ones. This randomness maybe comes through the generated ids for the features, that are sometimes equal to the new ones and sometimes not.
Dont know if that faces your problem, it just flew into my brain while I read that.
I am trying to create a website that filters data from a Fusion table onto a google map using a select list. I can't find the correct way to pass a variable through a JS query (or at least just the dropdown list value.) Can anyone help?
Here is my current code...I would want the place, schools and price variables to be in WHERE clauses. So I want to replace the word AVON with the value of the select list.
<script>
var map;
function initialize() {
var indy = new google.maps.LatLng(39.788945, -86.149937);
var place = document.getElementById("citydrop").value;
var schools = document.getElementById("schooldrop").value;
var price = document.getElementById("pricedrop").value;
map = new google.maps.Map(document.getElementById('map-canvas'), {
center: indy,
zoom: 10
});
var layer = new google.maps.FusionTablesLayer({
query: {
select: 'Address',
from: '1DsfPFeKrW2pegZhfSRJmLqYrlJc0HLF3nZcK4kQ',
where: "'CITY' = AVON"
}
});
layer.setMap(map);
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
Another note: citydrop, schooldrop and pricedrop are the ID's for select lists. Thanks for any help!
Couple of issue here. Your var place, var schools, var price need to be globals, i.e.outside your initialize(){ ... } function. Put them under where var map; is. Just the var price, etc. You can leave the setting of them where they are.
Replace:
where: "'CITY' = AVON"
With:
where: "'CITY' = 'AVON' AND 'SCHOOLS' = '" + schools + "' AND 'PRICE' = '" + price + '";
Do you have more than 1 school? The syntax might change if so. Get it working with 1 first then ask how to handle multiple schools. I think it's CONTAINS.
I use Places library to autocomplete address input. Search is limited to only one city, and I get output like this:
"Rossiya, Moskva, Leninskiy prospekt 28"
How to hide "Rossiya, Moskva"? ...
My query:
function() {
// Search bounds
var p1 = new google.maps.LatLng(54.686534, 35.463867);
var p2 = new google.maps.LatLng(56.926993, 39.506836);
self.options = {
bounds : new google.maps.LatLngBounds(p1, p2),
componentRestrictions: {country: 'ru'},
};
var elements = document.querySelectorAll('.address');
for ( var i = 0; i < elements.length; i++) {
var autocomplete = new google.maps.places.Autocomplete(elements[i],
self.options);
}
You can but you have to replace the value of the input field in two places.
Example:
var autocomplete = new google.maps.places.Autocomplete(input, placesOptions);
var input = document.getElementById('searchTextField');
inside the 'place_changed' event you need to do the following:
placeResult = autocomplete.getPlace();
//This will get only the address
input.value = placeResult.name;
This will change the value in the searchtextfield to the street address.
The second place is a bit tricky:
input.addEventListener('blur', function(){
// timeoutfunction allows to force the autocomplete field to only display the street name.
if(placeResult){ setTimeout(function(){ input.value = placeResult.name; }, 1); } });
The reason why we have to do this is because if you only add the event listener for blur, google places will populate the input field with the full address, so you have to 'wait' for google to update and then force your change by waiting some miliseconds.
Try it without the setTimeout function and you will see what I mean.
EDIT
You can't. I had it the other way around, that you were just looking for a city. There is no way to only print out the street name (I'm assuming that's a street name) from the address component.
OPPOSITE OF WHAT WAS ASKED
From the docs:
the (cities) type collection instructs the Place service to return results that match either locality or administrative_area3.
var input = document.getElementById('searchTextField');
var options = {
bounds: defaultBounds,
types: ['(cities)']
};
autocomplete = new google.maps.places.Autocomplete(input, options);
in result u have hash and from it u can get part what u want:
google.maps.event.addListener(autocomplete, 'place_changed', function() {
var place = autocomplete.getPlace();
now from "place" u can get it
place.geometry.location.lat()
and for address
place.address_components[0] or place.address_components[1] ...
depends on what u want to get
I had a very similar problem which indeed was solvable. This in an Angular 2 project but it should be applicable elsewhere as well. I filter my results for establishments, and wanted to show only the name and hide the address part of the result. This did the trick for me, a function executing once you select a suggestion:
getAddress(place: Object) {
this.zone.run(() => {
this.establishment = place['name'];
});
where zone is an NgZone component injected in the constructor and this.establishment is the variable tied to [(NgModel)] in the input field.
Inside place_changed set a timeout function:
var streetString = place.address_components[0] or place.address_components[1];
window.setTimeout(function() {
$('input').val(streetString);
}, 200);
This solution worked for me.
I'm trying to get an jquery ajax callback function to update the background colour of a table cell, but I can't get it to work.
I have the following code (which produces no errors in Firebug):
$(".tariffdate").click(function () {
var property_id = $('#property_id').attr("value");
var tariff_id = $('#tariff_id').attr("value");
var tariff_date = $(this).attr("id");
$.post("/admin/properties/my_properties/booking/edit/*", { property_id: property_id, tariff_id: tariff_id, tariff_date: tariff_date },
function(data){
var bgcol = '#' + data;
$(this).css('background-color',bgcol);
alert("Color Me: " + bgcol);
});
I've added the alert just to confirm I'm getting the expected data back (a 6 digit hexadecimal code), and I am - but the background of my table cell stubbornly refuses to change.
All the table cells have the class .tariffdate but also have individual ID.
As a test, I tried creating a hover function for that class:
$(".tariffdate").hover(function () {
$(this).css('background-color','#ff0000');
});
The above works fine - so I'm really confused as to why my callback function is not functioning. Any ideas?
In the AJAX completed handler the instance of this is changed to the ajax object. You'll need to save the instance of this to an object and use that object. For example:
$(".tariffdate").click(function () {
var property_id = $('#property_id').attr("value");
var tariff_id = $('#tariff_id').attr("value");
var tariff_date = $(this).attr("id");
var tariff = $(this);
$.post("/admin/properties/my_properties/booking/edit/*",
{ property_id: property_id, tariff_id: tariff_id, tariff_date: tariff_date },
function(data) {
var bgcol = '#' + data;
tariff.css('background-color',bgcol);
alert("Color Me: " + bgcol);
}
);
});
Check what the "this" variable is in you ajax callback function. I suspect that it's not referring to .tariffdate