Can sql queries vary by coulmns? - javascript

I'm trying to allow users to add routes to points on a leaflet map, using sql queries to a database of points. Because I want each point to have more than one route that passes through it, I added additional columns: "route2", "routenumber2" till "route5", "routenumber5" to the original "route" and "routenumber".
The following code does work, but I figured it's repetitive to write it out five times, each time only with a different set of columns.
if (e.target && e.target.id == "submitrest") {
const enteredRoute = document.getElementById("input_Route").value; // from user form input
const enteredNumber = document.getElementById("input_routenumber").value;
const enteredNickname = document.getElementById("input_nick").value;
const enteredID = document.getElementById("input_cartodb_id").value;
cartoData.eachLayer(function (layer) {
// SQL to put layer in -- Building the SQL query
let sql =
"UPDATE stops " +
"SET area = '" + enteredRoute + "', " +
"route_number = '" + enteredNumber + "', " +
"nickname = '" + enteredNickname + "' " +
"WHERE cartodb_id = " + enteredID + ";"
console.log(sql);
if (enteredRoute && enteredNickname && enteredNumber && enteredID) {
fetch(url1, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: "q=" + encodeURI(sql)
})
.then(function (response) {
return response.json();
})
.then(function (data) {
console.log("Data saved:", data);
})
What I am asking is if, like how document.getElementById allows the user to input different data each time and send the data using the same code, there is a less repetitive way to make an sql query function that allows me to put the data into "route3" and "routenumber3" if "route2" and "routenumber2" are already full, and so on.
What I would like is a row in CartoDB to have five sets/columns routes and routenumbers that a user can input data to, preferably with less duplicated code.
So far I've tried using Javascript class constructors and the Factory Method. Can I get these to allow the the columns specified in the sql query to be variable? Thank you

Related

Firebase function - http get parameters with acentuation

I have a firebase function doing a http GET. There are 3 parameters and all works ok but if one of the parameters contains acentuation the Firebase console don't show any error but the the GET is not executed. In this case, the problem is with Parameter03.
var url = 'http://myapi.azurewebsites.net/api/values?Parameter01=' + nameParam + '&Parameter02=' + emailParam + '&Parameter03=' + serviceParam ;
http.get(url, (resp) => {
res.setEncoding('utf8');
}).on("error", (err) => {
console.log("Error : " + err.message);
});
Any help please ?
Whenever you build a URL, you should properly escape all the query string components so that they contain only valid characters. That's what encodeURIComponent() is for. So do encode all your query string values like this instead:
var url = 'http://myapi.azurewebsites.net/api/values' +
'?Parameter01=' + encodeURIComponent(nameParam) +
'&Parameter02=' + encodeURIComponent(emailParam) +
'&Parameter03=' + encodeURIComponent(serviceParam);
There are other cleaner ways to build a URL with query string components, but this should work fine.

Unable to CREATE SQLite tables using JavaScript in for loop

I have a cross platform app developed using AngularJS, JS, Phonegap/Cordova, Monaca and Onsen UI.
I have implemented a SQLite Database in the app to store various data to ensure that the app can be used offline. I have done a few simple tests and this is all working as intended.
I now try to create all the tables I will need in the app (28 in total) in my apps first views onDeviceReady() function. For this I create an array of objects that I will pass one by one to the SQLite CREATE statement as below.
Setting up the table values
// Form values
var formValues = [{
tablename: "table_1",
id: "id_1",
desc: "desc_1",
dataType: "TEXT"
}, {
tablename: "table_2",
id: "id_2",
desc: "desc_2",
dataType: "TEXT"
}, {
...
...
...
...
}, {
tablename: "table_28",
id: "id_28",
desc: "desc_28",
dataType: "TEXT"
}];
Creating the tables
function onDeviceReady() {
for (var i = 0; i < formValues.length; i++) {
var createFormValues = 'CREATE TABLE IF NOT EXISTS ' + formValues[i].tablename + ' (' + formValues[i].id + ' INTEGER, ' + formValues[i].desc + ' ' + formValues[i].dataType + ')';
alert("SQL: " + createFormValues +
"\n\nForm: " + formValues +
"\nName: " + formValues[i].tablename +
"\nID: " + formValues[i].id +
"\nDesc: " + formValues[i].desc +
"\nType: " + formValues[i].dataType);
db.transaction(function (tx) { tx.executeSql(createFormValues); });
}
};
When I run the above code, the alert shows that all the information including the SQL statement is OK. However, when I query each table following the for() loop, it says no tables are created EXCEPT the last table.
I then try the following which DOES create all the tables but is obviously less efficient and manageable.
Calling a function
createFormTables("table_1", "id_1", "desc_1", "TEXT");
createFormTables("table_2", "id_2", "desc_2", "TEXT");
createFormTables("...", "...", "...", "...");
createFormTables("table_28", "id_28", "desc_28", "TEXT");
Executing the function
createFormTables: function (tableName, id, description, dataType) {
var sql = 'CREATE TABLE IF NOT EXISTS ' + tableName + ' (' + id + ' INTEGER, ' + description + ' ' + dataType + ')';
alert("Create Form Field SQL: " + sql);
db.transaction(function (tx) { tx.executeSql(sql); });
},
I know that the SQLite statements are executed asynchronously but I dont understand why that would create the tables in the second example and not the first? How do I create the tables using the first example? I can set a $timeout to execute each INSERT statement but this seems unnecessary and will cause delays.
I would use the JavaScript "Object" aproach to avoid conflict when calling function 'createFormTables' with something like:
var QuerySet = function(){
//OPTIONAL: I use JQuery Deferred to catch when an async event has finished
this.defRes = new $.Deferred();
this.defResProm = this.defRes.promise();
};
QuerySet.prototype.createFormTables= function(inputData){
//do your stuff and manage when this.defRes is resolved and results it sends back (if a result is needed)
this.sqlToExecute = "// YOUR SQL QUERY";
var self=this;
$.when(
(new SqlResult(this.sqlToExecute)).execSqlCustomDeferred(), //read below for SqlResult() explanations
self
).done(function(sqlRes,self){
self.defRes.resolve();
});
return this.defResProm;
};
Then in the code:
creatFromTables[i] = (new QuerySet()).createFormTables(inputData);
createFromTables[i].defRes.done(function(res){//do stuff with the result});
Don't need to use $.Deferred() but I think it could be useful if you want to know when all the tables have been created.
And here is sqlResult that is used to call the transaction on the DB itself:
var SqlResult = function(sqlToExecute,bracketValues){
//console.log("SqlResult("+sqlToExecute+','+bracketValues+') starts');
this.sqlToExecute = sqlToExecute;
this.bracketValues =bracketValues;
};
SqlResult.prototype.execSqlCustomDeferred = function(){
var execSqlCustomDeferredRes = $.Deferred();
var execSqlCustomDeferredResProm = execSqlCustomDeferredRes.promise();
//console.log("SqlResult.execSqlCustomDeferred sqlToExecute is: "+this.sqlToExecute);
var sqlToExecuteForTx = this.sqlToExecute;
var bracketValuesForTx = this.bracketValues;
DbManagement.db.transaction(function(tx){
console.log("SqlResult.execSqlCustomDeferred in TX sqlToExecute is: "+sqlToExecuteForTx);
if(bracketValuesForTx!=null){
console.log("SqlResult.execSqlCustomDeferred bracket value is: "+ArrayManagement.arrayToString(bracketValuesForTx));
}
tx.executeSql(sqlToExecuteForTx,bracketValuesForTx,success,error);
function success(tx,rs){
//console.log('before execSqlCustomDeferredRes resolve ' + execSqlCustomDeferredRes.state());
execSqlCustomDeferredRes.resolve(rs);
//console.log('before execSqlCustomDeferredRes resolve after ' + execSqlCustomDeferredRes.state());
}
function error(tx,error){
console.log('execSqlCustomDeferred error ' + error.message);
execSqlCustomDeferredRes.reject(error);
}
});
return execSqlCustomDeferredResProm;
};

Override cached image in ajax response

I have an ajax response that is returning images that are cached. I can bust this cache with a random number generator, but having an issue applying it correctly to the returned URI.
The cached image has a URI coming from the response represented by "obj.entity.entries[property].uri" that looks like this:
http://xx.domain.com/api/v2/img/5550fdfe60b27c50d1def72d?location=SQUARE
The newly uploaded image needs to have the random number applied to it, so that it is appended to the end of the URI, right before the ?, like so:
http://xx.domain.com/api/v2/img/5550fdfe60b27c50d1def72d+6?location=SQUARE, where +6 is the randomly generated number.
I believe the best approach is to use a regex to look for the end of the URI before the ? and apply the var storing the random number, then reapply this new URI to the response. I have the following worked out, but not sure how to apply the regex correctly:
$('.image-search').on('click', function () {
var root = "http://localhost:7777/proxy/staging/rest/v1/cms/story/id/";
var encodeID = $("#imageid").val();
var bearerToken = localStorage.getItem('Authorization');
var imageCacheBust = Math.floor((Math.random() * 10) + 1);
//IF TESTING ON LOCALHOST
if (document.domain == 'localhost') {
url = root + encodeID + "/images";
} else {
//IF IN PRODUCTION
url = "/cropper/admin/cropv2/rest/v1/cms/story/id/" + encodeID + "/images";
//GRAB REFERRER URL FOR VIMOND ASSET
//SET VALUE SUCCEEDING ASSETS AS ASSET ID
var regexp = /assets\/(\d+)/;
var assetid = regexp.exec(window.document.referrer);
$("#imageid").val(assetid[1]);
};
$.ajax({
url: url,
method: 'GET',
headers: {
"Authorization": bearerToken
},
}).then(function (response) {
var obj = response;
var regexp = "REGEX HERE";
var imageURI = regexp.exec(obj.entity.entries[property].uri);
$("#imageid").css("border-color", "#ccc");
$(".search-results").empty();
for (var property in obj.entity.entries) {
if (obj.entity.entries.hasOwnProperty(property)) {
$(".search-results").append($("<li><a href='" + imageURI + "' target='_blank'><div class='thumbnail'><img width='30' height='30' src='" + imageURI + "' target='_blank'/></img><div class='caption'><p>" + obj.entity.entries[property].orientation + "</p></div></a></li>"));
}
}
}).fail(function (data) {
$(".search-results").empty();
$(".search-results").append("<p class='alert alert-danger'>Invalid ID</p>");
$("#imageid").css("border-color", "red");
});
});
You don't need to add your random digits to the file path part of the URL, just append to the URL parameters instead, that is enough to prevent caching.
For example use:
img/5550fdfe60b27c50d1def72d?location=SQUARE&6
Where the 6 is your randomly generated value.
Also, be aware that a randomly generated number might not be the best choice here, since it might be undesirably duplicated. Consider using a hash or timestamp instead of a purely random number.
The solution ended up being fairly simple:
I set var imageCacheBust = Math.random(); and then used it in the returned URI like so: var imageURI = obj.entity.entries[property].uri + "?" + imageCacheBust;

How to disable certain HTTP methods (e.g. POST) for PersistedModel in LoopBack framework

When you create model in LoopBack framework, you can inherit from PersistedModel class. This way all the HTTP methods are generated. I am wondering how can I disable certain HTTP methods?
One option is to override functions from PersistedModel with empty logic, but want method to disappear from Swagger API explorer.
I did below in model.js files like below. This makes table readonly.
module.exports = function(model) {
var methodNames = ['create', 'upsert', 'deleteById','updateAll',
'updateAttributes','createChangeStream','replace','replaceById',
'upsertWithWhere','replaceOrCreate'
];
methodNames.forEach(function(methodName) {
disableMethods(model,methodName)
});
}
function disableMethods(model,methodName)
{
if(methodName!='updateAttributes')
model.disableRemoteMethod(methodName, true);
else
model.disableRemoteMethod(methodName, false);
}
The only thing which requires additional care is disabling of custom model methods (like User.login). You need to call disableRemoteMethod before explorer middleware: https://github.com/strongloop/loopback/issues/686
An update on Santhosh Hirekerur answer to make it hide everything on LB3, stop using the deprecated Model.disableRemoteMethod method and also a more intelligent way to hide updateAttributes and any other future methods that may work the same.
I check to see if the method is on the prototype and if it is, prefix the name with prototype. before we disableRemoteMethodByName:
module.exports = function (model) {
var methodNames = [
'create',
'upsert',
'deleteById',
'updateAll',
'updateAttributes',
'patchAttributes',
'createChangeStream',
'findOne',
'find',
'findById',
'count',
'exists',
'replace',
'replaceById',
'upsertWithWhere',
'replaceOrCreate'
];
methodNames.forEach(function (methodName) {
if (!!model.prototype[methodName]) {
model.disableRemoteMethodByName('prototype.' + methodName);
} else {
model.disableRemoteMethodByName(methodName);
}
});
}
I put the above code in server/middleware/disable-methods.js and call it from a model like so:
var disableMethods = require('../../server/middleware/disable-methods');
module.exports = function (Model) {
disableMethods(Model);
}
Found answer in documentation.
For example this disables PersistedModel.deleteById:
var isStatic = true;
MyModel.disableRemoteMethod('deleteById', isStatic);
So it looks like you it's not possible to disable all DELETE actions at the same time. For example method PersistedModel.deleteAll remains accessible in given example.
Developer must disable each relevant method from PersistedModel class explicitly.
Relevant docs are here
Sections:
Hiding methods and REST endpoints
Hiding endpoints for related models
In case of loopback 3
I had the same problem.
My first solution was to manually update the "public":true items in server/model-configuration.json but it was overridden anytime I used the Swagger tool to refresh the LoopBack API (with slc loopback:swagger myswaggerfilename command from the project root).
I finally wrote a Grunt task as a reliable workaround.
Run it just after a slc loopback:swagger generation or just before running the API live.
you just have to specify the names of the paths I want to expose in the javascript array list_of_REST_path_to_EXPOSE
and make sure you are happy with the backup folder for the original /server/model-config.json file.
I wanted to share it with you in case:
https://github.com/FranckVE/grunt-task-unexpose-rest-path-loopback-swagger
Basically:
module.exports = function (grunt) {
grunt.registerTask('unexpose_rest_path_for_swagger_models_v1', function (key, value) {
try {
// Change the list below depending on your API project :
// list of the REST paths to leave Exposed
var list_of_REST_path_to_EXPOSE =
[
"swagger_example-api_v1",
"write_here_the_paths_you_want_to_leave_exposed"
];
// Location of a bakup folder for modified model-config.json (change this according to your specific needs):
var backup_folder = "grunt-play-field/backups-model-config/";
var src_folder = "server/";
var dest_folder = "server/";
var src_file_extension = ".json";
var src_file_root_name = "model-config";
var src_filename = src_file_root_name + src_file_extension;
var dest_filename = src_file_root_name + src_file_extension;
var src = src_folder + src_filename;
var dest = dest_folder + dest_filename;
var free_backup_file = "";
if (!grunt.file.exists(src)) {
grunt.log.error("file " + src + " not found");
throw grunt.util.error("Source file 'model-config.json' does NOT exists in folder '" + src_folder + "'");
}
// timestamp for the backup file of model-config.json
var dateFormat = require('dateformat');
var now = new Date();
var ts = dateFormat(now, "yyyy-mm-dd_hh-MM-ss");
// backup model-config.json
var root_file_backup = src_file_root_name + "_bkp" + "_";
var root_backup = backup_folder + root_file_backup;
free_backup_file = root_backup + ts + src_file_extension;
if (!grunt.file.exists(root_file_backup + "*.*", backup_folder)) {
//var original_file = grunt.file.read(src);
grunt.file.write(free_backup_file, "// backup of " + src + " as of " + ts + "\n");
//grunt.file.write(free_backup_file, original_file);
grunt.log.write("Creating BACKUP"['green'] + " of '" + src + "' " + "to file : "['green'] + free_backup_file + " ").ok();
} else {
grunt.log.write("NO BACKUP created"['red'] + " of '" + src + "' " + "because file : " + free_backup_file + " ALREADY EXISTS ! "['red']).error();
throw grunt.util.error("Destination backup file already exists");
}
// load model-config.json
var project = grunt.file.readJSON(src);//get file as json object
// make modifications in model-config.json
for (var rest_path in project) {
if (rest_path.charAt(0) === "_") {
grunt.log.write("SKIPPING"['blue'] + " the JSON item '" + rest_path + "' belonging to the " + "SYSTEM"['blue'] + ". ").ok();
continue; // skip first level items that are system-related
}
if (list_of_REST_path_to_EXPOSE.indexOf(rest_path) > -1) { //
project[rest_path]["public"] = true;
grunt.log.write("KEEPING"['green'] + " the REST path '" + rest_path + "' " + "EXPOSED"['green'] + ". ").ok();
} else {
project[rest_path]["public"] = false;
grunt.log.writeln("HIDING"['yellow'] + " REST path '" + rest_path + "' : it will " + "NOT"['yellow'] + " be exposed.");
}
}
}
I wanted to hide the PATCH method, but when I was trying to hide it also I got to hide the PUT method , I was using this line :
Equipment.disableRemoteMethod('updateAttributes', false);
but later I found a way to only hide the PATCH method, this line works perfect for me.
Equipment.sharedClass.find('updateAttributes', false).http = [{verb: 'put', path: '/'}];
The above line overrides the original http that updateAttributes method had.
[{verb: 'put', path: '/'}, {verb: 'patch', path: '/'}]

jquery while loop running too fast - how to add a wait

I have jquery code that loops based on a counter, and inserts a record to a database and then opens a series of 4 reports for each new record it inserts.
The loop runs based on the number that is supplied by the user in the form dropdown called dropdownSection. For each Section; 1,2, or 3 the same number of records need to be inserted by ajax.
When the loop runs in the browser I get an error that I cannot track down. When I set a breakpoint in FireBug and step through the code it works fine. This leads me to think my loop might be running too fast?
Here is my code for the loop:
function InsertSheeter()
{
var textDate = $('#textDate').val()
var Workorder = $('#textWorkorder').val()
var Material = $('#dropdownMaterial').val()
var Shift = $('#dropdownShift').val()
var Sheeter = $('#dropdownSheeter').val()
var FoilNum1 = $('#textFoilNum1').val()
var FoilNum2 = $('#textFoilNum2').val()
var FoilNum3 = $('#textFoilNum3').val()
var Printline = $('#dropdownPrintline').val()
var Section = $('#dropdownSection').val()
var Comments = $('#textComments').val()
var Employee = $('#dropdownEmployees').val()
var a = 0
while (a < Section)
{
switch (a)
{
case 0:
blockSection = "1"
break;
case 1:
blockSection = "2"
break;
case 2:
blockSection = "3"
break;
}
var str = "{pDate:'" + textDate + "', pSheeter:'" + Sheeter + "', pShift:'"
+ Shift + "', pEmployee:'" + Employee + "', pWorkorder:'"
+ Workorder + "', pBlockSection:'" + blockSection + "', pComments:'"
+ Comments + "', pFoilNum1:'" + FoilNum1 + "', pFoilNum2:'"
+ FoilNum2 + "', pFoilNum3:'" + FoilNum3 + "', pPrintline:'"
+ Printline + "', pMaterial:'" + Material + "'}"
$.ajax(
{
type: "POST",
//contentType: "application/text; charset=utf-8",
url: "insertsheeter",
data: str,
dataType: "html",
success: function (data) {
OpenReports(Workorder, data);
},
error: function (xhr, errorType, exception)
{
var errorMessage = exception || xhr.statusText;
alert(errorMessage);
}
});
a++;
}
}
Do I need to put a delay in my loop to allow the other stuff to happen before continuing the loop?
Thx
In your case, I suspect you need the loop to wait for one AJAX insertion and set of reports to complete before starting the next one. You can do this with a recursive function instead of your while loop:
function myFunc() {
$.ajax({
/* ...options... */,
success: function(data) {
OpenReports(Workorder, data);
if (some_Boolean_test) {
myFunc();
};
}
});
}
myFunc();
Adding a fixed delay isn't going to be a consistent solution--that is if timing is even your problem. You should try setting async: false as Dave suggested. If that fixes your issue then timing might be part of your problem. The problem with fixed time delays is that they work under current conditions, but if for some reason the "slow" part takes even longer, your delay might not be enough--that's an antipattern.
As an aside, the one thing that sticks out to me is that you made a string that looks like a JSON object for your HTTP-POST data instead of just making a JSON object--was there a particular reason you did so? I would have done this:
var postData = {
pDate: textDate,
pSheeter: Sheeter,
pShift: Shift,
pEmployee: Employee,
pWorkorder: Workorder,
pBlockSection: blockSection,
pComments: Comments,
pFoilNum1: FoilNum1,
pFoilNum2: FoilNum2,
pFoilNum3: FoilNum3,
pPrintline: Printline,
pMaterial: Material
}
and then set data: postData in the $.ajax() call. Maybe your server code expects such an odd string though?
Hope this helps.
AJAX calls are by default Asynchronous, it looks like you might be looking for some synchronous behaviour here.
You can make an AJAX synchronous by setting
async: false

Categories

Resources