I am attempting wfs-t on openlayers 3 with the following code:
var formatWFS = new ol.format.WFS();
var formatGML = new ol.format.GML({
featureNS: 'http://argeomatica.com',
featureType: 'playa_sample',
srsName: 'EPSG:3857'
});
var transactWFS = function(p,f) {
switch(p) {
case 'insert':
node = formatWFS.writeTransaction([f],null,null,formatGML);
break;
case 'update':
node = formatWFS.writeTransaction(null,[f],null,formatGML);
break;
case 'delete':
node = formatWFS.writeTransaction(null,null,[f],formatGML);
break;
}
s = new XMLSerializer();
str = s.serializeToString(node);
$.ajax('https://gsx.geolytix.net/geoserver/geolytix_wfs',{
type: 'POST',
dataType: 'xml',
processData: false,
contentType: 'text/xml',
data: str
}).done();
}
However, when I run an update transaction (ajax call), it sends the geometry column as "geometry". I need to change it to be upper case "GEOM":
...
<Property>
<Name>geometry</Name>
...
should be:
...
<Property>
<Name>GEOM</Name>
...
I tried setting the feature with a hidden property I found (geometryName_):
f.geometryName_ = "GEOM";
But that does not work. Any help changing the feature to pass "GEOM" to the ajax call would be appreciated. Thanks
Update # 1
As suggested by Bart, I added setGeometryName:
case 'update':
f.setGeometryName("GEOM");
node = formatWFS.writeTransaction(null,[f],null,formatGML);
break;
But that causes openlayers 3 js to error out at:
ol.interaction.Modify.prototype.addFeature_
..
if (geometry.getType() in this.SEGMENT_WRITERS) <-- errors out here
Error: unable to get property getType object is null
I assume that you draw a feature with ol.transaction.Draw if that is the case you need to set your geometry name in the draw interaction object geometryName:'the_geom' befor you call 'drawend' event
var interaction = new ol.interaction.Draw({
type: 'MultiPolygon',
source: Source,
geometryName:'the_geom'
});
if you set the geometryName after drawing is finished (WRONG using feature.setGeometryName())openlayers will send a null object to the server.
Problem Solved!
Created a work-around to solve the problem. If someone has a better solution, please post your answer.
Step 1 - Modify the switch/case statement as follows:
...
case 'insert':
// Insert Parameter for new GEOMETRY NODE
f.set('GEOM', f.getGeometry());
node = formatWFS.writeTransaction([f], null, null, formatGML);
// Remove default lower case geometry node
removeLowerCaseGeometryNodeForInsert(node);
break;
case 'update':
// Update Parameter for new GEOMETRY NODE
f.set('GEOM', f.getGeometry());
node = formatWFS.writeTransaction(null, [f], null, formatGML);
// Remove lower case geometry node which will cause update to fail
removeNodeForWfsUpdate(node, "geometry");
break;
...
Step 2 - Add the following functions to your code:
function removeLowerCaseGeometryNodeForInsert(node)
{
var geometryNodes = node.getElementsByTagName("geometry"), element;
while (geometryNode = geometryNodes[0])
{
geometryNode.parentNode.removeChild(geometryNode);
}
}
function removeNodeForWfsUpdate(node, valueToRemove)
{
var propNodes = node.getElementsByTagName("Property");
for (var i = 0; i < propNodes.length; i++)
{
var propNode = propNodes[i];
var propNameNode = propNode.firstElementChild;
var propNameNodeValue = propNameNode.firstChild;
if (propNameNodeValue.nodeValue === valueToRemove)
{
propNode.parentNode.removeChild(propNode);
break;
}
}
}
Related
I have two model properties:
ng-model="category.name" mandatory field
ng-model="category.desc" optional
This is how I am sending data to the server (ASP.net)
var rdt = "{'dt':" + JSON.stringify($scope.category) + "}";
However, if an optional property has an unassigned value, the property name is not found server side and gives an error. Are there any ways to retain unassigned properties of JSON?
You have several solutions:
Solution 1: Initialize the variables in your scope for example:
$scope.category.desc = null
Solution 2: Create a function to take care of that
function ToJson(object, properties) {
var result = {};
for(var i = 0; i < properties.lenght; i++) {
var property = properties[i];
if(!object[property]) {
result[property] = null;
} else {
result[property] = object[property];
}
}
return JSON.stringify(result);
}
// And then use it like this:
var rdt = "{'dt':" + ToJson($scope.category, ["name", "desc"]) + "}";
Here is what I have tried.
I have tried dot notation and quotes. None of them seem to work. What exactly could be the problem?
var clientsList;
Client.find({}, function(err, clients) {
clientsList = clients;
// I have 10 clients in the loop
for (var j = 0; j < clientsList.length; j++) {
var x = clientsList[j];
x.count = "20";
//x["count"] = "20";
console.log(x);
}
});
Existing Client object
{"name":"abcd", "email":"abc#gmail.com"}
I'm unable to add the count key value pair into the client object. What could be the problem?
I suspect the object you're being given by Client.find has extensions prevented (it's sealed or frozen).
You can create a new object with the original's own, enumerable properties plus your count property using ES2018 spread notation:
x = {...x, count: "20"};
...or ES2015's Object.assign:
x = Object.assign({}, x, {count: "20"});
If the array is also sealed or frozen, you can copy it and its objects like this:
clientList = clients.map(client => {
return {...client, count: "20"}; // Or with `Object.assign`
});
or even with the concise form of the arrow function:
clientList = clients.map(client => ({...client, count: "20"}));
Side note: This pattern:
var clientsList;
Client.find({}, function(err, clients) {
clientsList = clients;
// ...
});
...often suggests that you intend to use clientsList in code following the Client.find call and expect it to have the result from that call's callback. See this question's answers for why, if you're doing that, it doesn't work.
This is my code:
const Discord = require('discord.js');
const client = new Discord.Client();
const TOKEN = "***********";
const PREFIX = "!";
client.on("ready", function () {
console.log("Ready!");
});
client.on("message", function (message) {
if (message.author.equals(client.user)) return;
if (!message.content.startsWith(PREFIX)) return;
var args = message.content.substring(PREFIX.length).split(" ");
switch (args[0]) {
case "rules":
var _embed = new Discord.RichEmbed()
.setTitle("Ruleset")
.addField("Where is my order?", "Theres only one proper way to recive an order and help. Its a command .ticket")
.addField("Why AZATEJ is such a bitch?", "If my status is 'dont disturb' and hue is way more red than green it means I have a reason to do so, im not a dick, but i recive a shitload of messages on daily route with stupid quiestions.")
.addField("Dont ask stupid questions", "Stupid doesnt mean basic, we are up to help you but before you'll contact anyone read twice explanation documents and use a ticket.")
.setColor(0x00FFFF)
.setFooter("This message is coool !")
.setThumbnail(message.author.avatarURL);
message.channel.send(_embed);
break;
case "spotify":
var uID = message.author.id;
for (let i = 0; i < ftpr.buyers.length; i++) {
if (uID === ftpr.buyers[i].id) {
var _embed = new Discord.RichEmbed()
.setTitle("Spotify")
.addField("Username", "testsda#yahoo.com")
.addField("Password", "ithastobe8")
.setColor(0x00FFFF)
.setFooter("Sincerely, LajgaardMoneyService")
.setThumbnail(message.author.avatarURL);
message.author.send(_embed);
console.log(message.author.username + "(" + JSON.stringify(ftpr.buyers[i].id) + ") Just used the command !spotify");
break;
}
else {
message.channel.send(message.author + "You haven't got a valid subscription. This command is locked until a new one is obtained!");
break;
}
}
break;
}
});
client.on('guildMemberAdd', function(member) {
console.log("User " + member.id + " has joined the server!");
//var role = member.guild.roles.find("name", "Google!");
var myRole = member.guild.roles.find("name", "Google!");
member.addRole(myRole);
});
client.login(TOKEN);
This is the JSON file:
{
"buyers": [
{
"id": "1331499609509724162"
},
{
"id": "181336616164392960"
},
{
"id": "266389854122672128"
}
]
}
When the bot is running and im changing one of the ID's the check function in case "spotify": is still using the old id. I do not want to restart the program every time the json file updates as it should be running 24/7. I have tried const fs = require("fs"); method but it gave me this error: TypeError: Cannot read property 'buyers' of undefined json
Sincerely, Oscar
const fs = require("fs"); just loads the module. Put that at the top of your file.
To read the json file each time you need to check user IDs (inefficient, but should get things working), put this at the top of your spotify case:
case "spotify":
var yourjsonfile = fs.readFileSync("yourjsonfile.json");
var ftpr = JSON.parse(yourjsonfile);
var uID = message.author.id;
for (let i = 0; i < ftpr.buyers.length; i++) {
if (uID === ftpr.buyers[i].id) {
Again, this is very inefficient - you are reloading the file every time you need to check it, and it uses readFileSync(), which blocks until the file is read (it is better to utilize node's asynchronous features). So as the JSON file grows larger, this will run slower. But at that point you probably need a database or some other mechanism for persisting and querying your data.
I am using script.google.com to create a custom connector that can read CSV data from drive.google.com and send the data to Googles data studio.
When running the connector and inserting a simple table inside the data studio, I receive a simple that the request could not be processed because of an server error. The error id is changing every time I "re-publish" the script.
This is
function getData(request) {
var dataSchema = [];
request.fields.forEach(function(field) {
for (var i = 0; i < csvDataSchema.length; i++) {
if (csvDataSchema[i].name === field.name) {
dataSchema.push(csvDataSchema[i]);
break;
}
}
});
csvFile = UrlFetchApp.fetch("https://drive.google.com/uc?export=download&id=" + request.configParams.documentId);
var csvData = Utilities.parseCsv(csvFile);
var data = [];
csvData.forEach(function(row) {
data.push({
values: row
});
});
console.log( {
schema: dataSchema,
rows: data
} );
return {
schema: dataSchema,
rows: data
};
};
This is the csvDataSchema:
var csvDataSchema = [
{
name: 'date',
label: 'Date',
dataType: 'STRING',
semantics: {
conceptType: 'DIMENSION'
}
},
{
name: 'nanoseconds',
label: 'nanoseconds',
dataType: 'NUMBER',
semantics: {
"isReaggregatable": true,
conceptType: 'METRIC'
}
},{
name: 'size',
label: 'Size of Testfile in MByte',
dataType: 'STRING',
semantics: {
"isReaggregatable": false,
conceptType: 'DIMENSION'
}
}
];
And this is the result of the getData function, stringified:
{"schema":[{"name":"date","label":"Date","dataType":"STRING","semantics":{"conceptType":"DIMENSION"}},{"name":"size","label":"Size of Testfile in MByte","dataType":"STRING","semantics":{"isReaggregatable":false,"conceptType":"DIMENSION"}}],"rows":[{"values":["2017-05-23",123,"1"]},{"values":["2017-05-23",123,"1"]}]}
It perfectly fits to the reference. I am providing more information, but following the tutorial it should work, anyways.
Those are the fields provided in request:
And this is what getDate returns:
So, what I am wondering first is: Why is there a random error id? And what could be wrong with my script?
You should only return fields/columns included in request. Currently, data contains all fields that are in csvFile. Depending on your chart element in your dashboard, request will most likely contain only a subset of your full schema. See example implementation at the Data Studio Open Source repo.
If this does not solve the problem, you should setup error handing and check if the error is occurring at any specific line.
#Minhaz Kazi gave the missing hint:
As I did not "dynamically" filled the response object in getData, I always returned all three columns.
With my code above the only thing I had to do is adding the third column as a dimension or a metric.
So I changed my code to dynamically return the columns so it will fit to the response. For this I had to implement an function that will transform the CSV-data into an object.
This is the getData() function now:
function getData(request) {
var url = "https://drive.google.com/uc?export=download&id="
+ request.configParams.documentId;
var csvFile = UrlFetchApp.fetch(url);
var csvData = Utilities.parseCsv(csvFile);
var sourceData = csvToObject(csvData);
var data = [];
sourceData.forEach(function(row) {
var values = [];
dataSchema.forEach(function(field) {
switch(field.name) {
case 'date':
values.push(row.date);
break;
case 'nanoseconds':
values.push(row.nanoseconds);
break;
case 'size':
values.push(row.size);
break;
default:
values.push('');
}
});
data.push({
values: values
});
});
return {
schema: dataSchema,
rows: data
};
};}
And this is the function to convert the CSV data to an object:
function csvToObject(array) {
var headers = array[0];
var jsonData = [];
for ( var i = 1, length = array.length; i < length; i++ )
{
var row = array[i];
var data = {};
for ( var x = 0; x < row.length; x++ )
{
data[headers[x]] = row[x];
}
jsonData.push(data);
}
return jsonData;
}
(it's based on a so-solution from here, I modified it to fit my source CSV data)
I have a Java object where the person object contains a displayName object. I have converted it to a JSON object for my JSP. The data looks like the following:
var people = [
{"id":52959,"displayName":{"firstName":"Jim","lastName":"Doe","middleName":"A"},"projectId":50003,"grade":"8","statusCode":"A","gradYear":2016,"buyer":false},
{"id":98765,"displayName":{"firstName":"Jane","lastName":"Doe","middleName":"Z"},"projectId":50003,"grade":"8","statusCode":"A","gradYear":2016,"buyer":true}
];
I want to bind my columns to the name properties that reside within the displayName object, but I am cannot get the column definition to recognize where the data resides. Here is an example of my firstName column definition:
{id: 'displayName.firstName', field: 'displayName.firstName', name: 'First Name',
width: 110, sortable: true, editor: TextCellEditor, formatter: SpaceFormatter,
cssClass: '', maxLength: 250, editable: true}
The view does not render the names although the data is there. Is it possible to bind a column to an object property that resides within another object? If so, what am I doing wrong?
Slickgrid doesn't support this capability by default, but you can workaround it by adding custom value extractor to your options object:
var options = {
dataItemColumnValueExtractor: function(item, columnDef) {
var names = columnDef.field.split('.'),
val = item[names[0]];
for (var i = 1; i < names.length; i++) {
if (val && typeof val == 'object' && names[i] in val) {
val = val[names[i]];
} else {
val = '';
}
}
return val;
}
}
var grid = new Slick.Grid($("#slickgrid"), data, columns, options);
The code is tested with slickgrid 2.0 and is working just fine. Unfortunately seems that slickgrid code is a bit inconsistent and editors don't take into account this option, so this solution is usable only if you will display the data without editing.
I know this is a bit old... but my work around is to do a pre-process on my items. Basically, flattening the model out:
var preProcessItems = function (items) {
var newItems = [];
for (var i = 0; i < items.length; i++) {
var item = items[i];
item['firstName'] = item['displayName']['firstName'];
newItems[i] = item;
}
return newItems;
};
/// when the value is updated on the flat structure, you can edit your deep value here
var fNameFormatter = function (row, cell, value, columnDef, dataContext) {
// datacontext.displayName.firstName = value;
return value ? value : "";
};
This problem seems to be more a of a data modeling issue though.