I would like to place markers on a leaflet map but from a database,
I would like to save on mongodb the lat and long and show 'em like markers on my map, is that possible?
Create a request for example with JQuery Ajax:
$.ajax({url: "/your_data_provider.php", success: function(result){
//result = JSON.parse(result); // If your result is not a json Object.
// It depends on what your data looks like
//Example 1: Lat and Lng has a own field in the db
result.forEach(function(data){
var lat = data.lat;
var lng = data.lng;
var marker = L.marker([lat, lng]).addTo(map);
});
//Example 2: you have one geojson-data string field "geo" in db
// Before inserting in db create a featuregroup `var fg = L.featureGroup();`
// and add all markers to the group `marker.addto(fg);`.
// Then you can call `var datageo = fg.toGeoJSON();` and add this datageo to the db in the field "geo"
result.forEach(function(data){
var geo = data.geo;
L.geoJSON(geo).addTo(map);
});
//https://leafletjs.com/examples/geojson/
},
error: function(xhr){
alert("An error occured: " + xhr.status + " " + xhr.statusText);
}});
});
Also you need a data provider. You can create a REST-Api www.url.com/data/postions/ or calling directly for example a php file.
php file:
// I have never used MongoDB, you have to code your own request. I copied it.
<?php
header('Content-type:application/json;charset=utf-8');
try {
$mng = new MongoDB\Driver\Manager("mongodb://localhost:27017");
$listdatabases = new MongoDB\Driver\Command(["listDatabases" => 1]);
$res = $mng->executeCommand("admin", $listdatabases);
$databases = current($res->toArray());
$result = new array();
$x = 0;
foreach ($databases->databases as $el) {
$result[$x]['id'] = $el->id;
//Example 1:
$result[$x]['lat'] = $el->lat;
$result[$x]['lng'] = $el->lng;
//Example 2:
$result[$x]['geo'] = $el->geo;
$x++;
}
echo json_encode($result);
} catch (MongoDB\Driver\Exception\Exception $e) {
$error = new array();
$error['exception'] = $e->getMessage();
$error['line'] = $e->getLine();
echo json_encode($error);
}
?>
Related
My scenario is to add a section in a page and perform an action on it.But as there are elements with the same xpath already, webdriver is clicking on first element and the script is failing.So, I want to fetch the existing number of elements having the same xpath and then increase the count by 1 so as to click on the newly added section. Please find the below code and correct me where it is going wrong.(Or) Suggest me any other approach.
Also, please let me know will line no. 9 works if getting the number of elements issue is resolved. Thanks!
Method :
this.getElementCount=async function(locator) {
try {
console.info('Verifying count for element ' + locator);
let noOfElements = await element.all(locator).count();
await console.info('There are ' + noOfElements + 'elements in UI');
return noOfElements;
} catch(err) {
throw err;
}
}
Calling method :
var compLocator = element(by.xpath("//div[#title='Test']"));
this.clickOnComp=async function(){
var elementsCount=getElementCount(compLocator);
console.info("No. of elements : "+elementsCount);
if(elementsCount>1){
var currentEle=elementsCount+1;
var currentCompLocator=compLocator[currentEle]; // line no.9
console.info("comp locator :" +currentCompLocator);
await clickElement(currentCompLocator);
console.info("Clicked : "+currentCompLocator);
}
else{
await clickElement(compLocator);
}
}
Output :
Verifying count for element [object Object]
No. of elements : [object Promise]
(node:13915) UnhandledPromiseRejectionWarning: TypeError: Invalid locator
Start with resolving promise with await
var compLocator = element(by.xpath("//div[#title='Test']"));
this.clickOnComp=async function(){
var elementsCount=await getElementCount(compLocator); // <-----------------
console.info("No. of elements : "+elementsCount);
if(elementsCount>1){
var currentEle=elementsCount+1;
var currentCompLocator=compLocator[currentEle]; // line no.9
console.info("comp locator :" +currentCompLocator);
await clickElement(currentCompLocator);
console.info("Clicked : "+currentCompLocator);
}
else{
await clickElement(compLocator);
}
}
There are two issues in your code:
getElementCount() expects a locator argument by you give a element
(Line 9) compLocator is an element not an xpath or an element array, you can't use compLocator[currentEle]
var compXPath = "//div[#title='Test']"
var compLocator = by.xpath(compXPath);
this.clickOnComp=async function(){
var elementsCount = await getElementCount(compLocator);
console.info("No. of elements : "+elementsCount);
if(elementsCount > 1){
var currentEle = elementsCount+1;
var currentCompXPath = compXPath + "/["+ currentEle +"]" // line no.9
console.info("current Comp xpath :" +currentCompXPath);
var currentCompLocator = by.xpath(currentCompXPath)
await clickElement(currentCompLocator);
console.info("Clicked : "+currentCompLocator);
}
else{
await clickElement(compLocator);
}
}
I use the node module "query-overpass" for a query to get farmshops from openstreetmaps. I would like to convert all polygons to points inside this script. I use turf.js to get the centroids of theese polygons, but I am not able to change the objects in a permanent way. This is my code so far:
const query_overpass = require("query-overpass");
const turf = require ("turf");
const fs = require("fs")
let test
let filename = "data/test.js"
let bbox = "48.91821286473131,8.309097290039062,49.0610446187357,8.520584106445312";
console.log('starting query for ' +filename)
console.log('bbox: ' +bbox)
let query = `
[out:json][timeout:250];
// gather results
(
// query part for: “vending=milk”
node["vending"="milk"](${bbox});
way["vending"="milk"](${bbox});
relation["vending"="milk"](${bbox});
// query part for: “shop=farm”
node["shop"="farm"](${bbox});
way["shop"="farm"](${bbox});
relation["shop"="farm"](${bbox});
// query part for: “vending=food”
node["vending"="food"](${bbox});
way["vending"="food"](${bbox});
relation["vending"="food"](${bbox});
);
// print results
out body;
>;
out skel qt;
`;
// query overpass, write result to file
query_overpass(query, (error, data) => {
data = JSON.stringify(data , null, 1)
console.log(data)
test = JSON.parse(data)
//create centroids for every polyon and save them as a point
for (var i = 0; i < test.features.length; i++) {
console.log("Log: " +test.features[i].geometry.type)
console.log("Log: " +test.features[i].properties.name)
if (test.features[i].geometry.type === "Polygon"){
console.log("polygon detected")
var centroid = turf.centroid(test.features[i]);
var lon = centroid.geometry.coordinates[0];
var lat = centroid.geometry.coordinates[1];
console.log(" lon: " +lon +" lat: " +lat)
test.features[i].geometry.type = 'Point'
//delete Polygon structure and insert centroids as new points here
console.log("polygon deleted and changed to point")
}
}
console.log(test)
fs.writeFile(filename, `var file = ${test};` , ["utf-8"], (error, data) => {if (error) {console.log(error)}})
}, {flatProperties: true}
)
It seems like I can change things inside of the for loop, but they do not appear when the data is saved later. It is basically a question of how to edit json objects properly, but I can't figure out why this doesnt work here at all.
So there are basically two questions:
Why cant I override geometry.type in the example above?
How can I delete the old polygon and add a new point to a feature?
Thanks for any help.
That's quite complicated... Why don't you let Overpass API do this job and use out center; instead of out body;>;out skel qt; to return the center points of all nodes, ways and relations. You can use overpass-turbo.eu to try this out first.
I'm new in CRM development. I know a basic thing like "best practice for crm 2011"
I wanna understand now how to work with lookup fields. And I think I chose the easiest way for my self.
I have an costum entity "contract" it has 5 more field, 2 of these are lookups.
First lookup (agl_contractId) - it is a link by it self
Second lookup (agl_ClientId) - link to Client.
What do I need?
When I choose fill First lookup (agl_contractId), script should find in this contract a Client and copy-past it to current form.
I've done script but it isn't work... (((
function GetAccountFromContract()
{
XrmServiceToolkit.Rest.Retrieve(Xrm.Page.getAttribute("agl_osnovnoy_dogovorid").getValue(),
'agl_osnovnoy_dogovoridSet',
null,null,
function (result) {
var Id = Xrm.Page.getAttribute("agl_osnovnoy_dogovorid").getValue();
if (result.Id != null) {
var LookupData = new Array();
var LookupItem = new Object();
var lookuptextvalue = lookupvalue[0].name;
var lookupid = lookupvalue[0].id;
var lokupType = lookupvalue[0].entityType;
alert(lookupvalue);
alert(lookupData);
Xrm.Page.getAttribute("agl_accountid").setValue(lookupData);
}
},
function (error) {
equal(true, false, error.message);
},
false
);
}
If I understand you well: When you select Contract in agl_osnovnoy_dogovorid field, you want to pull Client property from that Contract and put it in agl_accountid field?
If that is right:
First, get Id of selected Contract (from agl_osnovnoy_dogovorid field)
var selectedContract = new Array();
selectedContract = Xrm.Page.getAttribute("agl_osnovnoy_dogovorid").getValue();
{
var guidSelectedContract = selectedContract[0].id;
//var name = selectedContract[0].name;
//var entType = selectedContract[0].entityType;
}
Second, retrieve Client from agl_osnovnoy_dogovorid. Your oData query will be like:
http://crmserver/org/XRMServices/2011/OrganizationData.svc/ContractSet(guid'" + guidSelectedContract + "')/CustomerId
(In example I'm using CustomerId field. For your case enter Schema Name of Client field).
Now, execute query and put result into agl_accountid field:
$.getJSON(
Xrm.Page.context.getServerUrl() + "/XRMServices/2011/OrganizationData.svc/ContractSet(guid'" + guidSelectedContract + "')/CustomerId",
function(data){
if(data.d.CustomerId != null && data.d.CustomerId.Id != null && data.d.CustomerId.Id != "undefined")
{
//set agl_accountid field
Xrm.Page.getAttribute("agl_accountid").setValue([{id:data.d.CustomerId.Id, name:data.d.CustomerId.Name, typename:data.d.CustomerId.LogicalName}]);
}
});
Your using REST to retrieve data but also using FetchXml example to setup the agl_accoutid lookup.
Also some of the conditions are not clear … anyway … I’ve incorporated the change to your original post.
function GetAccountFromContract()
{
var aodLookupValue = Xrm.Page.getAttribute("agl_osnovnoy_dogovorid").getValue();
if (!aodLookupValue) return;
XrmServiceToolkit.Rest.Retrieve( aodLookupValue[0].id ,
'agl_osnovnoy_dogovoridSet', null,null,
function (result) {
var customer = result.d["your attribute name"];
if (customer) {
var LookupData = new Array();
var LookupItem = new Object();
var lookuptextvalue = customer.Name;
var lookupid = customer.Id;
var lokupType = customer.LogicalName;
alert(lookupvalue);
alert(lookupData);
Xrm.Page.getAttribute("agl_accountid").setValue(lookupData);
}
},
function (error) {
equal(true, false, error.message);
}, false );
}
I want to be able to pass multiple data sets to my view. Here is how I am currently doing it in my controller:
transactions: function (req, res) {
var queryexpenses = 'select * from expense order by name';
Expense.query(queryexpenses, function (err, expense) {
this.expenses = expense;
});
if (req.param('filter')) {
var where = 'where fk_expense = ' + req.param('expensefilter');
where += ' and datePosted > "' + req.param('yearfilter') + '-01-01" ';
where += ' and datePosted < "' + req.param('yearfilter') + '-12-31" ';
} else {
var where = 'where fk_expense IS NULL';
}
var query = 'select * from accounting ' + where + ' order by description';
Accounting.query(query, function (err, trans) {
this.transactions = trans;
});
var total = 0;
_.each(this.transactions, function (element, index, list) {
// format dates
element.datePosted = dateFormat(element.datePosted, 'dd/mm/yyyy');
var tmp0 = element.amount
var tmp1 = tmp0.replace(/ /g, '');
var tmp2 = parseFloat(tmp1);
total += tmp2;
});
this.total = total.toFixed(2);
return res.view();
}
This is the only way I am able to accomplish what Im trying to do but there are problems which I believe are caused by me putting the query objects in the "this" scope. The first problem is the page will crash after server restart on first reload. The second problem is everything seems to happen one step behind. What I mean is if I issue commands on the UI (eg submit a form) nothing will happen unless I take the same action twice.
So how do I pass multiple sets of data to my views without scoping them in "this"?
res.view({
corndogs: [{name: 'Hank the Corndog'}, {name: 'Lenny the Corndog'}]
});
Here is the relevant docs page: http://sailsjs.org/#!documentation/views
Also, it looks like you're not taking full advantage of Waterline for making SQL queries.
I am trying to build a GeoJSON object from a SQL query to some GIS point data in a postgis postgresql database. A snippet of my node.js app.js is below.
As it stands I understand building the type and features, but don't know how to attach a properties array to each GeoJSON record (in the below, it all renders at the end, separate from (not collated with) the features).
THE QUESTION: What do I need to do so that the properties attach (collate) for each record in the loop that builds the GeoJSON So that it looks more like this http://www.geojson.org/geojson-spec.html#examples?
`function GrabData(bounds, res){
pg.connect(conn, function(err, client){
var moisql = 'SELECT ttl, (ST_AsGeoJSON(the_geom)) as locale from cpag;'
client.query(moisql, function(err, result){
var featureCollection = new FeatureCollection();
for(i=0; i<result.rows.length; i++){
featureCollection.features[i] = JSON.parse(result.rows[i].locale);
featureCollection.properties[i] = JSON.parse(result.rows[i].ttl); //this is wrong
}
res.send(featureCollection);
});
});
}
function FeatureCollection(){
this.type = 'FeatureCollection';
this.features = new Array();
this.properties = new Object; //this is wrong
}
`
This should do the job:
...
for(i=0; i<result.rows.length; i++){
var feature = new Feature();
feature.geometry = JSON.parse(result.rows[i].locale);
feature.properties = {"TTL", result.rows[i].ttl};
featureCollection.features.push(feature);
}
...
Using:
function FeatureCollection(){
this.type = 'FeatureCollection';
this.features = new Array();
}
function Feature(){
this.type = 'Feature';
this.geometry = new Object;
this.properties = new Object;
}
I recently wrote a little helper module for this purpose. It's very straightforward to use -
var postgeo = require("postgeo");
postgeo.connect("postgres://user#host:port/database");
postgeo.query("SELECT id, name ST_AsGeoJSON(geom) AS geometry FROM table", "geojson", function(data) {
console.log(data);
});
You can find the repo here - https://github.com/jczaplew/postgeo