No such property: geometry when updating feature in openlayers 3 - Geoserver - ajax

I am working on a webmapping app with Openlayers 3, Postgresql and Geoserver 2.8, I want to make a WFS-T transactions for drawing and updating so I followed this steps https://medium.com/#goldrydigital/wfs-t-with-openlayers-3-16-6fb6a820ac58
Here is my modification code :
var dirty = {};
select.getFeatures().on('add', function(e) {
e.element.on('change', function(e) {
dirty[e.target.getId()] = true;
});
});
var clone;
select.getFeatures().on('remove', function(e) {
var f = e.element;
if (dirty[f.getId()]){
delete dirty[f.getId()];
featureProperties = f.getProperties();
delete featureProperties.boundedBy;
clone = new ol.Feature(featureProperties);
clone.setId(f.getId());
clone.setGeometryName("the_geom");
}
});
var node = formatwfs.writeTransaction(null, [clone], null, {
featureNS: "myNameSpace",
featureType: "myLayer"
});
$.ajax({
type: "POST",
url: "http://localhost:8080/geoserver/wfs",
data: new XMLSerializer().serializeToString(node),
contentType: 'text/xml',
success: function(data) {
alert((new XMLSerializer()).serializeToString(data));
},
error: function(e) {
var errorMsg = e? (e.status + ' ' + e.statusText) : "";
alert('Error saving this feature to GeoServer.<br><br>'
+ errorMsg);
},
context: this
});
the drawing part works fine but for the updating I get an error:
<ows:ExceptionText>No such property: geometry</ows:ExceptionText>
the geometry column in my table and layer is "the_geom" so I double check it on my code with setGeometryName("the_geom") but yet when I make the AJAX call I get the error above.
The first thing that came to my mind is to change the geometry column name in my postgresql table to geometry and republish the layer in geoserver, but I want to know first if there is any less obedient solution for this, thanks in advance
After changing the geometry column name in postgresql to "geometry" I get now another error :
<ows:ExceptionText>java.lang.NullPointerException</ows:ExceptionText>

I changed the geometry column name into "geometry" and after that the error relative to the Java null pointer came, then I found out that the XML code generated was wrong and needs to be modified for it refers to a wrong typeName feature:myLayer while it should be myNameSpace:myLayer for this one all I had to do was to replace it with Javascript :
var str=new XMLSerializer().serializeToString(node);
var data=str.replace("feature:myLayer","myNameSpace:myLayer");

In addition to Hicham Zouarhi's solution you can also change geometry type like this:
//Change feature name
const find_feature = `feature:${layerName}`;
const re_feature = new RegExp(find_feature, "g");
//Change feature geometry column
const find_geometry = `<Property><Name>geometry</Name>`;
const re_geometry = new RegExp(find_geometry, "g");
const payload = xs.serializeToString(formatWFS.writeTransaction(null, f, null, formatGML))
.replace(re_feature, `Bugra:${layerName}`)
.replace(re_geometry, `<Property><Name>${layerGeometryColumn}</Name>`);

Related

How to load a .csv file into crossfilter with d3?

I am trying to load a .csv file into crossfilter for further use it with dc.js and d3. However, if the ndx = crossfilter(data_) is not inside d3.csv(..., it does not work. Is it possible to load data using d3 inside a global/outside variable (in this case ndx)?
var ndx;
private method(){
var data_;
d3.csv("samples.csv", function(data){
var format = d3.timeParse("%m-%y");
data.forEach(function(d: any) {
d.date = format(d.date);
});
data_ = d3.csvParse(data);
});
ndx = crossfilter(data_);
}
How can I load it into crossfilter?
Am I obligated to use crossfilter inside the d3.csv(.. call?
Solution:
I made my .csv became a .json and I loaded it 'synchronously'. Observe below.
var ndx;
private method(){
var data_ = (function() {
var json: any = null;
$.ajax({
'async': false,
'global': false,
'url': "samples.json",
'dataType': "json",
'success': function (data:any) {
json = data;
}
});
return json;
})();
ndx = crossfilter(data_);
}
Observe:
'async': false
This happens because the callback function is executed asynchronously, once the data is returned. This means that if you put the charting code outside of the callback, you are going to get the empty array that you defined because no data has been returned yet.

Trouble Adding Markers to Google Maps via Ajax

What I am trying to achieve:
Generate Map
Get Bounds information for Map
Make Ajax call passing Bounds information, data returned is Marker info
Populate Map with Markers
I am stuck because I cannot get the Ajax call to trigger.
The code seems to stop running after the alert("ajax ready"). I have a breakpoint on my controller action which never gets hit.
The only error I am getting is that "nE is undefined", however if I put in an alert the line after I am setting the value, then the the value is shown, so am not even sure that is relevant.
I have worked successfully with an earlier version of Google Maps, V3 seems a bit different. I couldn't get the lines of code to set the bounds to run until they were placed in an event listener. I tried the same with the Ajax call but doesn't make a difference.
I do know that I am not adding the markers to the map within the ajax call, I have yet to get to that part.
Javascript:
function initMap() {
var markers = [];
var map = new google.maps.Map(document.getElementById('local-map'), {
center: { lat: 51.509865, lng: -0.118092 },
zoom: 15
});
var bounds = undefined;
var nE = undefined;
var sW = undefined;
google.maps.event.addListener(map, 'bounds_changed', function () {
bounds = map.getBounds();
nE = bounds.getNorthEast();
sW = bounds.getSouthWest();
});
alert("ajax ready");
$.ajax({
type: "POST",
url: '/Home/GetMapMarkers',
data: { neLatitude: nE.lat(), neLongitude: ne.lng(), swLatitude: sW.lat(), swLongitude: sW.lng() }
}).done(function (data) {
for (i = 0; i < data.length; i++)
{
var marker = new google.maps.Marker({
position: new google.maps.LatLng(data[i].Latitude, data[i].Longitude),
map: map,
title: data[i].RestaurantName
});
markers.push(marker);
}
});
}
The "bounds_changed" listener will fire asynchronously when the map bounds changes. You need to put your AJAX call inside its callback function (when/where the new bounds is available):
google.maps.event.addListener(map, 'bounds_changed', function () {
bounds = map.getBounds();
nE = bounds.getNorthEast();
sW = bounds.getSouthWest();
alert("ajax ready");
$.ajax({
type: "POST",
url: '/Home/GetMapMarkers',
data: { neLatitude: nE.lat(), neLongitude: ne.lng(), swLatitude: sW.lat(), swLongitude: sW.lng() }
}).done(function (data) {
for (i = 0; i < data.length; i++)
{
var marker = new google.maps.Marker({
position: new google.maps.LatLng(data[i].Latitude, data[i].Longitude),
map: map,
title: data[i].RestaurantName
});
markers.push(marker);
}
});
});

Parse Cloud Code Save Issue

I wrote some backend code for a Parse.com mobile app a couple of years ago, and have just been asked to add a feature. However, I found that after a small tweak the code wouldn't succeed. So, I rolled back to the working copy, downloaded, then deployed that back and it wouldn't work either! I wonder if this is a change in the Parse software?
The code is failing at the save method as all the logs are fine until then. The log for the error case shows 'No message provided'. If I don't use the message attribute it just shows '{}', so I presume it's empty. I have put the promise resolution in the error case to stop the job timing out while I debug. One thing I have never understood is why I have to make two Seed objects and piggy-back off one to save correctly. If I did a.save(null,...) it wouldn't work.
Any help would be fantastic. Thanks!
PS: Apologies for the indenting below - it is correct in my file.
function flush() {
//Clear the previous records from the class.
var Seed = Parse.Object.extend("Seeds");
var _ = require("underscore");
var arr = [];
var query = new Parse.Query(Seed);
return query.find().then(function(oldSeeds) {
_.each(oldSeeds, function(oldSeed) {
arr.push(oldSeed.destroy());
});
return Parse.Promise.when(arr);
});
}
Parse.Cloud.job("fetchjson", function(request, status) {
var url = 'someurl';
flush().then(function() { Parse.Cloud.httpRequest({url: url}).then(function(httpResponse){
var Seed = Parse.Object.extend("Seeds");
var jsonobj = JSON.parse(httpResponse.text);
var _ = require("underscore");
var results = [];
// do NOT iterate arrays with `for... in loops`
_.each(jsonobj.seeds, function(s) {
var p = new Parse.Promise();
results.push(p); // Needs to be done here or when() will execute immediately with no promises.
var seed = new Seed();
var a = new Seed(s);
var image_url = a.get("image")
//Get the JSON.
Parse.Cloud.httpRequest({url: image_url}).then(function(response) {
console.log("Fetching image at URL: " + image_url);
//Create a new image object and save, passing ref through promise.
var file = new Parse.File('thumb.jpg', { base64: response.buffer.toString('base64', 0, response.buffer.length) });
return file.save();
}).then(function(thumb) {
console.log("Attaching thumb to object");
//Set image ref as object attribute.
a.set("imageFile", thumb);
console.log("Parsing views into viewsint");
//Save decimal string as int into another attribute.
a.set("viewsInt", parseInt(a.get("views")));
console.log("Parsing description into descriptionarray");
//Save string as array into another attribute.
var dar = new Array(1);
//dar[0] = a.get("description")
a.set("descriptionarray", [a.get("description")]);
}, function(error) {
console.log("Error occurred :(");
}).then(function(){
console.log("Saving object");
//Save the object and resolve the promise so we can stop.
seed.save(a,{
success: function(successData){
console.log(successData);
p.resolve(successData);
},
error: function(error){
console.log(error.message);
p.resolve(error);
}
});
});
});
// .when waits for all promises to be resolved. This is async baby!
Parse.Promise.when(results).then(function(data){
console.log("All objects saved");
status.success("Updated Succesfully");
});
}, function(error) {
//Oh noes :'(
console.error('Request failed with response code ' + httpResponse.status);
status.error("Update Failed");
});
});
});
I changed your code a bit and put some comments to explain:
// DEFINE THESE ON THE TOP. NO NEED TO REPEAT.
var _ = require("underscore");
var Seed = Parse.Object.extend("Seeds");
function flush() {
//Clear the previous records from the class.
var arr = [];
var query = new Parse.Query(Seed);
return query.find().then(function(oldSeeds) {
_.each(oldSeeds, function(oldSeed) {
arr.push(oldSeed.destroy());
});
return Parse.Promise.when(arr);
});
}
Parse.Cloud.job("fetchjson", function(request, status) {
var url = 'someurl';
flush().then(function() {
Parse.Cloud.httpRequest({url: url}).then(function(httpResponse){
var jsonobj = JSON.parse(httpResponse.text);
var results = [];
_.each(jsonobj.seeds, function(s) {
// ONE SEED OBJECT WITH INITIAL SET OF DATA FROM JSON
var seed = new Seed(s);
var image_url = seed.get("image")
// A SERIAL PROMISE FOR EACH SEED
var promise = Parse.Cloud.httpRequest({url: image_url}).then(function(response) {
console.log("Fetching image at URL: " + image_url);
//Create a new image object and save, passing ref through promise.
var file = new Parse.File('thumb.jpg', { base64: response.buffer.toString('base64', 0, response.buffer.length) });
return file.save();
}).then(function(thumb) {
// SETTING MORE PROPERTIES
//Set image ref as object attribute.
console.log("Attaching thumb to object");
seed.set("imageFile", thumb);
//Save decimal string as int into another attribute.
console.log("Parsing views into viewsint");
seed.set("viewsInt", parseInt(seed.get("views")));
//Save string as array into another attribute.
console.log("Parsing description into descriptionarray");
seed.set("descriptionarray", [seed.get("description")]);
// SAVING THE OBJECT
console.log("Saving object");
return seed.save();
});
// PUSH THIS PROMISE TO THE ARRAY TO PERFORM IN PARALLEL
results.push(promise);
});
Parse.Promise.when(results).then(function(data){
console.log("All objects saved");
status.success("Updated Succesfully");
});
}, function(error) {
console.error('Request failed with response code ' + httpResponse.status);
status.error("Update Failed");
});
});
});
Thanks knshn. I had refactored the code a lot since that version (including several of the changes you made), but I had posted the version that was identical to that which was working fine before. Your changes let me see the right error. For some reason doing the simple single object implementation didn't work for me originally, hence the nasty workaround. It works now though.
I have now found the culprit - the Seed class had an attribute called 'id'. With the old version this worked fine, but when I deployed that code now it gave an error 101: 'object not found for update'. This must be because the new Parse code is mixing that up with the internal objectId and getting confused that the id is different to what it expects. I wonder how that could still work with the rollback though. Perhaps the at version was tagged to use the older Parse code.
My fix was to use a different name for the id - 'seed_id'.

Reduce Repetitiion with AJAX JSON Calls to an API

I have about 15 copies of the following code on my site. The only things changing are the url, longitude, latitude, and the marker variable title. How can I chop this up and reduce the repetition?
$.ajax({
url: "http://api.wunderground.com/api/<api_key>/conditions/q/pws:KCASANFR128.json",
dataType: "jsonp",
success: function(parsed_json) {
var location = parsed_json['current_observation']['observation_location']['city'];
var temp_f = parsed_json['current_observation']['temp_f'];
var weather = parsed_json['current_observation']['weather'].toLowerCase();
var iconUrl = parsed_json['current_observation']['icon_url'];
var iconPic = new MyIcon(iconUrl);
var markerRichmond = new L.Marker(new L.LatLng(37.779806, -122.471895), {icon: iconPic});
markerRichmond.bindPopup("Current temperature in " +location+ " is: " +temp_f+ " and it is " + weather);
map.addLayer(markerRichmond);
}});
You could make a function which takes in those variables and feeds them to the ajax call. Then you would only need one copy of this ajax block, which you could call by calling the getWeather function
function getWeather(url, lat, long, title){
$.ajax({
url: url,
dataType: "jsonp",
success: function(parsed_json) {
var location = parsed_json['current_observation']['observation_location']['city'];
var temp_f = parsed_json['current_observation']['temp_f'];
var weather = parsed_json['current_observation']['weather'].toLowerCase();
var iconUrl = parsed_json['current_observation']['icon_url'];
var iconPic = new MyIcon(iconUrl);
var markerRichmond = new L.Marker(new L.LatLng(lat, long), {icon: iconPic});
markerRichmond.bindPopup(title);
map.addLayer(markerRichmond);
}
});
}
I am not sure if I handled the title correctly here, but you get the idea. If you give an idea of how the title may change, I can fix the code accordingly.
Hope this helps.
var current_observation = parsed_json['current_observation'];
This also shortens amount of times parsed. Then you can refer to your variable as
current_observation['observation_location']['city'];

Sencha Touch refresh list after data in store has been changed

i want to do the following:
I have a store which gets JSON data from the server. The JSON looks like this:
{"id":"1","name":"Name1","address":"exampleaddress1","lat":"48.366268","lng":"10.892320","distance":"0"},{...}]
My model and store:
Ext.regModel('Filiale', {
fields: ['id', 'name', 'address', 'distance', 'lat', 'lng'],
});
var ListStore = new Ext.data.Store({
model: 'Filiale',
id: 'ListStore',
autoLoad: false,
fields:['name', 'address', 'distance'],
proxy: {
type: 'ajax',
url : 'http://example.com/getSomeJson.php',
reader: {
type: 'json'
}
},
listeners: {
load: function(){
ListStore.each(function(store){
var newData = getDistance(store.data); // this function calculates the distance from currentLocation to the received address
console.log(newData); // i see a object in the console, with the correct calculated distance
console.log(newData.distance); // this shows the old distance which is set to '0' in the databse
//at this point i want to update the received records with the new distance, but the list always shows the old distance
});
}
}
});
I don't understand, why the two console.logs show different values for the distance. Can anyone explain that to me ?
My List:
var listPanel = new Ext.List({
title: 'ListStore',
store: ListStore,
id: 'addresslist',
itemTpl: '<div class="contact">{name}, {address}, {distance}</div>',
rendered: false,
listeners: {
beforerender: function(){
ListStore.load();
}
}
});
my function to calculate the distance:
var getDistance = function(dataset){
navigator.geolocation.getCurrentPosition(function(position){
var start = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
//add current position marker to map
var marker = new google.maps.Marker({
map: mapPanel.map,
position: start
});
var end = new google.maps.LatLng(dataset.lat, dataset.lng);
var service = new google.maps.DirectionsService();
var request = {
origin: start,
destination: end,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
service.route(request, function(result, status){
if (status == google.maps.DirectionsStatus.OK) {
dataset.distance = result.routes[0].legs[0].distance.value / 1000;
}
});
});
return dataset;
};
And as i said, the distance is correctly calculated and the objects gets returned... but i'm unable to update the records in the store or the list...
I don't understand, why the two console.logs show different values for the distance. Can anyone explain that to me ?
Are You using Chrome? Chrome console sometimes has problems with up-to-date console data
And as i said, the distance is correctly calculated and the objects gets returned... but i'm unable to update the records in the store or the list...
Records in the store in Your script are always up-to-date - in JS obejcts are passed by reference, so You don't even have to return newData - store object will be updated automatically
Just after adding some values to store type:
listpanel.refresh()
to load current store to list

Resources