Calling a TS Function from Script - javascript

I'm Using a external JS from an external enterprise. Is mandatory use this script online and not import it.
one of the complexity is that they've his own html tag to call a functions that are inside from a script tag. I've created this script from typescript side to control some variables, but i need to call a function to have a value needed in the end of the flux.
So, in short, I need call a TypeScript Function from this script tag created.
here some code:
let script = document.createElement('script');
script.type = `text/javascript`;
script.text = `
var success = function (data) {
let transactions= ${JSON.stringify(this.transactions)};
let internalId = this.getInternalId('Hello there!'); -----> The TS Function that I want to call
};`;
document.getElementsByTagName('body')[0].appendChild(script);
getInternalId(value:string):void {
console.log('a');
}
greetings!
UPDATE
I tried to abstract the function in the HTML tag like this:
[attr.data-order-id]="success"
and in the ts file like this:
success = (data:any ) => {
debugger;
alert(JSON.stringify(this.transactions;));
};
But I lost every reference of the proyect and somehow it function is executed from other file:
The function is executed from another file. On the left tab is the ts file where function is declarated.

Related

React, how to add external script and make its functions available?

I wonder how I would add an external script to an React application and make its functions available. Let's take this script https://www.cssscript.com/confetti-falling-animation/
In a "not-react-application" I would add it like this in my DOM
<script src="confetti.js"></script>
and then call it's functions like this
startConfetti();
or
stopConfetti();
However, this does not work in React. I know that I can add a <script /> tag like this:
useEffect(() => {
const script = document.createElement('script');
script.src = './confetti.js';
script.async = true;
document.body.appendChild(script);
return () => {
document.body.removeChild(script);
}
}, []);
But this does not make the functions startConfetti() or stopConfetti() available. They are undefined.
How would I add the script and its functionalities in a React App?
Add the script in index.html's head tag, like so (with the correct path to the JavaScript file):
<script src="confetti.js"></script>
Then in your React component, you could get it with the help of window object, this way:
const startConfetti = window.startConfetti;
startConfetti();

Load ordering of dynamically added script tags

I have a typescript application that dynamically adds script tags that point to JS files. Due to some restrictions I cant have these script tags statically defined in a html file, so I add them dynamically through typescript like this:
for (let src of jsFiles) {
let sTag = document.createElement('script');
sTag.type = 'text/javascript';
sTag.src = src;
sTag.defer = true;
document.body.appendChild(script);
}
Now, I am noticing that, when I add script tags dynamically, their doesn't seem to be a guarantee in the order in which they are loaded. Unfortunately, the jsFiles array has scripts that are dependent on each other. So, the 2nd script in the array can only be loaded after the first one is fully loaded. The second script references a function that is defined in the first one. Is there a way I can specify the order in which scripts are ordered and executed when adding them dynamically (similar to how ordering is done when you statically define script tags in a html file)?
P.S. I would like to avoid using the onload callback to solve this issue since I noticed a performance degradation with my application. My second script file is very large and I am assuming that caused the degradation.
I can mention some alternatives to overcome that requirement:
Use a library to inject dependencies (AMD or CommonJS modules)
Just use modules. ES2015: import/export, or CommonJS: require().
Create the script tag programmatically and set the callback onload in order to react when the script has been loaded asynchronously. The attribute async = true is set by default.
If you are allowed to modify the scripts to inject, then add a line at the end of scripts with an object or array that keeps track of the scripts already loaded.
You can fetch the scripts as text (XMLHttpRequest), then, build a string with the scripts in the required order and, finally, execute the text-script via eval()
And the less recommended option but frequently used, set a setInterval to check if the script was already executed.
I recommend going for the first option. But for academic purposes, I'm going to illustrate the second option:
Create the script tag programmatically and set the callback onload in order to react when the script has been loaded asynchronously.
I want to recommend a reading about script loaders: Deep dive into the murky waters of script loading, half hour worth spending!
The following example is a small module to manage scripts injection, and this is the basic idea behind it:
let _scriptsToLoad = [
'path/to/script1.js',
'path/to/script2.js',
'path/to/script3.js'
];
function createScriptElement() {
// gets the first script in the list
let script = _scriptsToLoad.shift();
// all scripts were loaded
if (!script) return;
let js = document.createElement('script');
js.type = 'text/javascript';
js.src = script;
js.onload = onScriptLoaded;
let s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(js, s);
}
function onScriptLoaded(event) {
// loads the next script
createScriptElement();
};
In this plunker you can test the injection of scripts asynchronously in a specific order:
https://plnkr.co/edit/b9O19f
The main idea was to create an API that allows you interact with the scripts to inject, by exposing the following methods:
addScript: receive an URL or a list of URLs for each script to be loaded.
load: Run the task to load scripts in the specified order.
reset: Clear the array of scripts, or cancels the load of scripts.
afterLoad: Callback executed after every script has been loaded.
onComplete: Callback executed after all scripts have been loaded.
I like Fluent Interface or method chaining technique, so I built the module that way:
scriptsLoader
.reset()
.addScript("script1.js")
.addScript(["script2.js", "script3.js"])
.afterLoad((src) => console.warn("> loaded from jsuLoader:", src))
.onComplete(() => console.info("* ALL SCRIPTS LOADED *"))
.load();
In the code above, we load first the "script1.js" file, and execute the afterLoad() callback, next, do the same with "script2.js" and "script3.js" and after all scripts has been loaded, the onComplete() callback is executed.
I would like to avoid using the onload callback to solve this issue since I noticed a performance degradation with my application.
If you want the files ordered ... you need to wait for onload on each file. No way around it.
Here is a utility function I wrote once:
/**
* Utility : Resolves when a script has been loaded
*/
function include(url: string) {
return new Promise<{ script: HTMLScriptElement }>((resolve, reject) => {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
script.onload = function() {
resolve({ script });
};
document.getElementsByTagName('head')[0].appendChild(script);
});
}
For anyone who is using jQuery I have improved #adeneo script so it will load all scripts in the specified order. It doesn't do chain loading, so it's very fast, but if you want even faster, change the 50 ms wait time.
$.getMultiScripts = function(arr, path) {
function executeInOrder(scr, code, resolve) {
// if its the first script that should be executed
if (scr == arr[0]) {
arr.shift();
eval(code);
resolve();
console.log('executed', scr);
} else {
// waiting
setTimeout(function(){
executeInOrder(scr, code, resolve);
}, 50);
}
}
var _arr = $.map(arr, function(scr) {
return new Promise((resolve) => {
jQuery.ajax({
type: "GET",
url: (path || '') + scr,
dataType: "text",
success: function(code) {
console.log('loaded ', scr);
executeInOrder(scr, code, resolve);
},
cache: true
});
});
});
_arr.push($.Deferred(function( deferred ){
$( deferred.resolve );
}));
return $.when.apply($, _arr);
}
How to use:
var script_arr = [
'myscript1.js',
'myscript2.js',
'myscript3.js'
];
$.getMultiScripts(script_arr, '/mypath/').done(function() {
// all scripts loaded
});

Required code cannot access main code

so I was trying to bring my code to readable form but stumbled upon a kinda annoying problem.
So I wanted to outsource a class into an file, "require" it and than write the callback function in the main file for the readability. But the function in the outsourced file is not able to access the callback function. Here is the simplified problem:
file_a.js
function test_a(){
return "this is A"
}
var test_b = require('./lib/file_b.js').test_b
console.log(test_b())
file_b.js
function test_b(){
return test_a()
}
exports.test_b = test_b
I hope someone could tell me how to manage this problem :)
EDIT: This code is for a firefox addon !
test_a function has to be globally defined:
test_a = function(){
return "this is A"
}
var test_b = require('./lib/file_b.js').test_b
console.log(test_b())
Also, you have to return something in your test_b function:
function test_b(){
return test_a()
}
exports.test_b = test_b
Then you will have such output:
this is A
You can load both js files independently in the same HTML file.
Then, whichever code that you have that is referencing other files loaded on the page should be in a window.onload call (or using jQuery $(document).ready), so that it only runs when the two files are available on the page.

Assign a value to a variable in a function in one file from another file

I have a function like this:
function oneFunction()
{
var onevaribale = $('#onevalue').val();
var twovariable = $('#twovalue').val();
//Do something with both variables
//continue using **onevariable** not noticing the typo as **onevaribale**
}
Now because of the typo, the entire function fails and the location of where the code is run is on an intranet. Luckily, the code has an external js file and I want to assign something like:
var onevariable = onevaribale
How do I go about extending oneFunction to make this change from the external js file?

Javascript: usage of require in Appcelerator Titanium

I am quite new to javascript and I am struggling with a simple problem. I have to split up codes into separate files. As an example I have a file called Database.js. In that file I have the following lines:
function Database(){
//someStuff
this.fetchAll = function(){
//some stuff
return something;
}
}
Now I want to use the Database.js code in the file app.js. So I write the following code in app.js:
var Database = require('Database');
var myDB = new Database();
var result = myDB.fetchAll();
However, I get the error Script Error = '[object Database]' is not a constructor (evaluating 'new Database()') at app.js (line 3).
What is my mistake?
Before you moving to the development, you need to understand thoroughly about CommonJS Modules in Titanium. Then it will be more simple for you. Also refer the require function
Let's come to your error. [ERROR] [object Database]' is not a constructor (evaluating 'new Database()') at app.js (line 3) means that the module you created is not constructor. Your constructor function might not return any value. Read simple usage of CommonJS module. I'm sure it will resolve your issue.
There is an alternative way, you can include your Database.js file in your app.js. You does not need to return anything and no need to use require function. You just need to use the include method. Just write Ti.include('Database.js'); inside your app.js and you can access all the global variables and functions inside the Database.js file
This question is old but it has not been answered yet. So i will just provide the answer for anyone who is visiting here.
You have to export you function as global. To do so you would declare it as below
exports.fetchAll = function Database(){
//some stuff
return something;
};
You can also declare the function so that it can be used globally as well as locally within the file
var fetchAll = function Database(){
//some stuff
return something;
};
exports.fetchAll = fetchAll;
Then assuming the file name is Database and it is in same folder as app.js, you can use it as below
var Database = require('Database');
var result = Database.fetchAll();
edit: This answer is javascript general and it's not oriented towards Appacelerator Titanium.
There is no such include or require in javascript. You can on the other hand do one of the following
Include a script tag before your script to include Database.js
<script type="text/javascript" src="Database.js" >
OR
Add it dynamically
function loadScript(url, callback)
{
// adding the script tag to the head as suggested before
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
// then bind the event to the callback function
// there are several events for cross browser compatibility
script.onreadystatechange = callback;
script.onload = callback;
// fire the loading
head.appendChild(script);
}
The problem seemed to be the usage of the variable name 'Database'. Maybe there is somewhere a name collusion.
I am sorry that I did not know that the usage of require is not a basic concept of js.
Just a quick guess here. If you use CommonJS then you have to tell what should be available outside of the module. The way you lay out that you have made the Database "object" you would need to add:
module.exports = Database;
somewhere in your module. I always put them at the end - but not sure that is a requirement.
You can also make individual functions available outside of a module by specifying:
exports.getMyDatabase = getMyDatabase;
Where "getMyDatabase" is a function you have specified in the module. I use this way to "hide" certain implementation details of some functions from the outside and just make available the functions I want the developer to be able to call ;-)
/John
I think this is the right usage of require js:
require(["Database"], function() {
var myDB = new Database();
var result = myDB.fetchAll();
});
http://requirejs.org/docs/jquery.html

Categories