I'm using UiPath Orchestrator. This runs as expected. But I now additionally want to reduce the authentication to a single call (instead of always do an auth when requesting an odata). So my idea was to write the object to a file and on the odata request read that object and re-use it.
The following orchestrator object comes from the constructor of new Orchestrator. This object is ready to be used and has the following structure (via console.log(orchestrator)):
In my tool I need the object functions of odata. So this works:
console.log(orchestrator['v2']['odata']);
I now want to save that object as file to be able to re-use it, so I did:
fs.writeFileSync('./data.json', orchestrator, 'utf-8')
But sadly I get the error:
Converting circular structure to JSON
That is intended as the node package is using a circulare structure. So my idea was to use the circular-json package to fix that issue:
const {parse, stringify} = require('circular-json');
...
var savetofile = stringify(orchestrator);
...
var readfromfile = parse(savetofile);
...
console.log(readfromfile['v2']['odata']);
But sadly than readfromfile['v2']['odata'] is not available anymore. The reason is that stringify(orchestrator) is already minifying too heavy:
So how I achieve that I am able to read the Orchestrator object from the file and being able to use the functions again? Or is it more useful to use a memory tool in my case?
The issue was not located in the Orchestrator object itself. So there is no need to do a single authentication.
My problem was that I put the res.send outside of the callback. So it never waited for the actual finish of the REST api call.
This was the base code where it just took the static result of the first request, it never updated the results:
app.get('/jobs', function (req, res) {
...
var orchestrator = require('./authenticate');
var results = {};
var apiQuery= {};
orchestrator.get('/odata/Jobs', apiQuery, function (err, data) {
for (row in data) {
results[i] =
{
'id' : row.id,
...
};
}
});
return res.send({results});
});
The solution is to moving the res.send({results}); into the orchestrator.get, then it properly overwrites the results as it waits correctly for the callback:
app.get('/jobs', function (req, res) {
...
var orchestrator = require('./authenticate');
var results = {};
var apiQuery= {};
orchestrator.get('/odata/Jobs', apiQuery, function (err, data) {
for (row in data) {
results[i] =
{
'id' : row.id,
...
};
}
return res.send({results});
});
});
I am developing a web application using Angular 8. I just want to access the exif data of an input image outside the getData method by assigning the obtained data to a global variable. If i tried to access the global variable after executing function it is showing undefined.
here is the function for extracting the exif data:
photodata: any; // global variable
getPhotodata(file) {
EXIF.getData(file, function() {
const data = EXIF.getAllTags(this);
console.log(data); // working
console.log(data.Make); // working
console.log(data.Model); // working
console.log(data.DateTimeOriginal); // working
this.photodata = data;
console.log(this.photodata) // working
});
}
console.log(this.photodata) // here it is showing undefined
i have tried to return the data. But it also does not worked
getPhotodata(file) {
EXIF.getData(file, function() {
const data = EXIF.getAllTags(this);
console.log(data); // working
console.log(data.Make); // working
console.log(data.Model); // working
console.log(data.DateTimeOriginal); // working
return data;
});
}
console.log(getPhotodata(file)) // undefined
I'm aware you probably solved this by now, but in case async programming got you curious, you might enjoy my library exifr. I've written it because exif-js is effectively dead now (not maintained for over 2 years), it's pretty ineffective. Exifr is built around promises and async/await syntax, so you can do this:
async function getExif() {
let output = await exifr.parse(file)
console.log(data.Make)
console.log(data.Model)
}
You can also try out the library's playground and experiment with images and their output, or check out the repository and docs.
I am trying to create a library for a project, its like this:
module.exports = Diary;
function Diary() {
someFunction = function( message ) {
console.log(message)
}
function D() {
return new D._Section;
}
D.about = {
version: 1.0
};
D.toString = function () {
return "Diary "+ D.about.version;
};
var Section = function () {
this.Pages = []
}
D._Section = Section;
//to extend the library for plugins usage
D.fn = sectionproto = Section.prototype = D.prototype;
sectionproto.addPage = function (data) {
this.Pages.push(data)
conole.log(this.Pages)
};
return D;
};
main purpose for this is to use same library for server side and client side operations, so we can have same code base.
this issue is that when i use this in node app
var Diary = require('./diary.js');
var myDiary = new Diary();
console.log(myDiary.addPage('some text on page'))
and run it, it throws an error
TypeError: myDiary.addPage is not a function
i am not not sure what to do here to make this work for node js, as our client app is very huge and making changes to it would require some effort if we have to go in some other pattern.
First Question is:
1. is this approach right or we need to look in to something else
2. if this can work on node js app then how with minimum changes to library
The main problem is that you're exporting your overall Diary function, but then using it as though you'd received its return value (the D function) instead.
The way you're exporting it, you'd use it like this:
var Diary = require('./diary.js')();
// Note -------------------------^^
var myDiary = new Diary();
But beware that that means every import will create its own D function and associated things.
Alternately, export the result of calling Diary, but then the Diary function has no purpose.
Other issues are:
You're falling prey to The Horror of Implicit Globals* by not declaring someFunction or sectionproto. Be sure to declare your variables.
The structure is over-complicated without any obvious reason it needs to be so complicated.
* (disclosure: that's a post on my anemic little blog)
Problem: I'm trying to get some data from a server to populate a cytoscape graph. When i access the scope from javascript its undefined.
Despite their being quite a few posts with this / similar issue. I'm having trouble finding an explanation about how to get round the problem of accessing the scope from a javascript file, once the data is ready (if that is the problem im having).
I read that http.get methods are asynchronous? so they don't block anything after from executing. I guess this is what is causing an undefined error when i'm accessing the scope because the data hasn't returned yet? I've found some info on this but can't figure out what to use to get round the problem. I can access the data in the usual way in HTML with the angular curly braces and it works. It also works when i just return some data from the controller.
If anyone can point me in the right direction i'd really appreciate it.
This is javascript file im trying to run which grabs the scope and adds nodes to a cytoscape graph.
<script type="text/javascript">
window.onload = function() {
nodes = angular.element(document.querySelector('[ng-controller="DataController"]')).scope().nodes;
alert(nodes);
cy.add(nodes);
}
</script>
2. which calls a factory method from the controller.
dataFactory.getNodes().then(function(data)
{
$scope.nodes = data;
});
3. http.get from the factory
_service.getNodes = function()
{
return $http.get(urlBase + "/nodes");
};
4. node.js returns some 'nodes' to add to the cytoscape graph
router.get('/api/data/nodes', function(req, res) {
console.log('sending some data');
var data = [
...
];
res.status(200).json(data);
});
I've seen "promises" mentioned so i guess i'll be heading in that direction next...
Thanks
You are trying to alert the value of nodes when the DOM is loaded (window.onload) and the data from the service is not yet returned.
Your controller is already uses a promise, and the data is binded to the scope when the promise is resolved.
.then(function(data){
...
});
If you specifically want to access the data from an external js script, you can simply call the function from the controller:
script
<script type="text/javascript">
function alertNodes() {
nodes = angular.element(document.querySelector('[ng-controller="DataController"]')).scope().nodes;
alert(nodes);
cy.add(nodes);
}
</script>
controller
dataFactory.getNodes().then(function(data){
//$scope.nodes = data;
alertNodes()
});
I want to make an ajax call that will return a json object. One of this JSON object's properties will be the string of a function to be executed in the client. I realise this can easily be solved by using eval, but seeing the many disadvantages of eval, I'd rather avoid it. My question is:
Can I in some way return from the server some js code and execute it without resorting to eval?
As requested, here's some example code:
Server (Node.js):
var testFunc = function() {
alert('h1');
};
app.get('/testPack', function(req, res) {
var template = jade.render('h1 hi');
res.send({
template : template,
entity : testFunc.toString(),
data : {
id: "OMG I love this"
}
});
});
Client:
$(document).ready(function() {
$.ajax({
url: '/testPack',
success: function(data) {
$('body').append($(data.template))
alert(data.data.id);
var entity = eval(data.entity);
entity();
}
})
})
Of course, the returned function called entity wouldn't do such a silly thing, it would expose an API of the returned widget.
Just to clarify, I'd like to avoid having to make a separate call for the javascript itself. I'd rather bundle it with the template and data to render.
Easiest way to do that, is not to call a server through an ajax, but instead to create a new script tag on the page with the url pointing to a RESTful web-service that would output pure JavaScript (not JSON). That way your output will be evaluated by the browser directly without the use of eval.
To expand a little on my answer:
To get around the problems of running script in the global context you could do some tricks. For example, when you are adding script tag to the head, you can bind onload event (or rather fake onload event, since IE doesn't support onload on the script tag) to it, and if your response from the server will be always wrapped in the the function with a known name, you could apply that function from within your object. Example code below (this is just an example though):
function test ()
{
this.init = function ()
{
var script = document.createElement("script");
script.type = "text/javascript";
script.language = "javascript";
script.src = "test.js";
var me = this;
window.callMe = function () { me.scriptReady(me); };
var head = document.getElementsByTagName("head")[0];
head.appendChild(script);
};
this.scriptReady = function (object)
{
serverResponse.call(object);
};
this.name = "From inside the object";
this.init();
}
var t=new test();
The server response should look something like this:
function serverResponse()
{
alert(this.name);
}
window.callMe();
In this case, everything inside serverResponse() will use your object as "this". Now if you modify your server response in this way:
function serverResponse()
{
this.serverJSONString = { "testVar1": "1", "testVar2": 2 };
function Test()
{
alert("From the server");
}
Test();
}
window.callMe();
You can have multiple things being returned from the server and with just one response. If you don't like just setting variables, then create a function in your main object to handle JSON string that you can supply by calling this function from your response.
As you can see, it's all doable, it really doesn't look pretty, but then again, what you are trying to do is not pretty to begin with.
P.S. Just inserting a string inside tag will not work for IE, it will not allow you to do that. If you don't have to support IE, then you could get away with just inserting server response inside a newly created script tag and be done with it.
P.P.S. Please don't use this code as is, cause I didn't spend too much time writting it. It's ugly as hell, but was just ment as an example:-)
No, you can't do this by definition, because JavaScript functions are not valid JSON. See the spec here:
http://www.json.org/
If you're returning a string, then that's what it is: just a string. You can't evaluate it without eval. You can call whatever else you're returning whatever you want, but please don't call it JSON.
Here's an example of how I think this could work.
The json object represents what is returned from the server. The c and d properties contain function names as strings. If those functions are properties of some other object which exists in your page, then you should be able to call them using the object["property"] accessor.
See it working on jsFiddle: http://jsfiddle.net/WUY4n/1/
// This function is a child of the window object
window.winScopedFunction = function() {
alert("ROCK THE WIN");
}
// This function is a child of another object
var myObject = {
myFunction : function() {
alert("ROCK ON");
}
};
// pretend that this json object was the result of an ajax call.
var jsonResultFromServer= {
a : 1,
b : 2,
c : "myFunction",
d : "winScopedFunction"
};
// you can call the local functions like so
myObject[jsonResultFromServer.c]();
window[jsonResultFromServer.d]();
Yes, there's a way, but it has the exact same disadvantages as eval.
You can use the Function constructor to create a new function, and then call it. For example:
new Function(code)();
http://code.google.com/p/json-sans-eval/ is a fast JSON parser that does not use eval, and JSON.parse is becoming increasing widely available in new browsers. Both are excellent alternatives to eval for parsing JSON.
You can use the trick that Google does with Google Charts.
<html>
<head>
<script>
function onWorkDone(data) {
console.log(data);
}
</script>
<script src="callback.js"></script>
</head>
</html>
Then your callback.js is:
function doWork(callback) {
callback({result: 'foo'});
}
doWork(onWorkDone);
Basically, your script will call onWorkDone when the doWork completed. You can see a working example here:
http://jsfiddle.net/ea9Gc/
Do you have some example cases? Some things I can think of is you that you can just have a regular function inside your js file, and your server will return some parameters for your function to execute. You can even specify what function to use! (Isn't that amazing?)
// your js file
var some_namespace = {
some_function : function(a, b){
// stuff
}
}
// your server output
{
some_other_data: "123",
execute: {
func: "some_namespace.some_function",
params: [1, 2]
}
}
// your ajax callback
function(r){
window[r.execute.func].apply(this, r.execute.params);
}
The reasons of not using eval
Well, you already said it yourself. Don't use eval. But you have a wrong picture regarding why.
It is not that eval is evil. You are getting the reason wrong. Performance considerations aside, using eval this way allows a sloppy programmer to execute code passed from server on the client. Notice the "passed from server" part.
Why never execute code passed from server
Why don't you want to execute code passed from the server (incidentally that's what you're planning to do)?
When a browser executes a script on a web page, as long as the web site is valid -- i.e. really yours, and not a malware site pretending to be yours trying to trick your users -- you can be reasonably sure that every bit of code the browser is running is written by yourself.
Hacker's heaven -- script injection attacks
Now, if you are passing data from the server to your web application, and that data contains executable functions, you're asking for trouble. In the long, twisted journey of that data going from your server to your client's browser, it goes through the wild west called the Internet, perhaps through multiple layers of proxies and filters and converters, most of which you do not control.
Now, if a hacker is hiding somewhere in the middle, takes your data from the server, modify the code to those functions to something really bad, and sends it away to your client, then your client browser takes the data and executes the code. Voila! Bad things happen. The worse is: you (at the server side) will never know that your clients are hacked.
This is called a "script injection attack" and is a serious sercurity risk.
Therefore, the rule is: Never execute functions returned from a server.
Only pass data from server
If you only accept data from a server, the most that can happen whan a hacker tempers with it is that your client will see strange data coming back, and hopefully your scripts will filter them out or handle them as incorrect data. Your client's browser will not be running any arbitrary code written by the hacker with glee.
In your client-side script, of course you're sticking to the Golden Rule: Do not trust ANY data coming through the Internet. Therefore you'd already be type-check and validating the JSON data before using it, and disallowing anything that looks suspicious.
Don't do it -- pass functions from server and execute on client
So, to make a long story short: DON'T DO IT.
Think of another way to specify pluggable functionalities on the browser -- there are multiple methods.
I've had this same question, and I fixed it this way:
File: functions.js.php?f=1,3
$functions=array(
'showMessage' => 'function(msg){ alert(msg); }',
'confirmAction' => 'function(action){
return confirm("Are you sure you want to "+action+"?");
}',
'getName' => 'function getName(){
return prompt("What is your name?");
}'
);
$queried = explode($_REQUEST['f']);
echo 'var FuncUtils = {'; // begin javascript object
$counter=1;
foreach($functions as $name=>$function){
if(in_array($counter, $queried))
echo '"'.$name.'":,'.$function.',';
$counter++;
}
echo '"dummy":null };'; // end javascript object
File: data5.json
{
"action" : ['confirmAction','exit']
}
File: test.js
$(document).ready(function(){
$.getScript('functions.js.php?f=1,3');
});
function onBeforeExit(){
$.getJSON('data5.json', function(data) {
var func = data.action.shift();
FuncUtils[func].apply(null, data.action);
});
}