Call external Javascript function from react components - javascript

Im not sure if this has been asked before or anybody has encountered the same issue on reactjs. So the scenario is like this, I have an index.html file that includes some javascript. Now on my react component, I have a condition that will render only if the condition is true. This means that initially when my page loaded the component has not been rendered yet. When I toggle a button this is where that component gets rendered. That child component needs to call a javascript method that was included on my index.html. How should I do this?
Any help is greatly appreciated.

In index.html
<script type="text/javascript">
function test(){
alert('Function from index.html');
}
</script>
In your component
componentWillMount() {
window.test();
}
2022 Typescript edit:
Create a file global.d.ts like so (doc):
interface Window {
test: () => void;
}
✔

Try this solution to call global functions from React with TypeScript enabled:
Either in index.html or some_site.js
function pass_function(){
alert('42');
}
Then, from your react component:
window["pass_function"]();
And, of course, you can pass a parameter:
//react
window["passp"]("react ts");
//js
function passp(someval) {
alert(`passes parameter: ${someval}`);
}

So either you define the method on global scope (aka window).
And then you can use it from any methods, being React or not.
Or you can switch to module based paradigm and use require/import to get the module and use the function.
For bigger projects the latter is better as it's scales, while if you need a demo or POC you can certainly hook all to global scope and it will work.
More information about modules is at: http://exploringjs.com/es6/ch_modules.html

You can attached your method to the global window object and than use it like that in your component:
<button onClick={this.howItWorks} type="button" className='btn'>How it Works</button>
howItWorks = () => {
window.HowItWorksVideo();
}

for typescript users, try this:
declare global {
interface Window {
externalMethod: (params: any) => void;
}
}
then you would be able to call it like this in your react component
window.externalMethod(params)

Related

How to call a Javascript function from TypeScript in React [duplicate]

I have a react redux application with typescript.
So the scenario is like this, I have an index.cshtml file that includes some javascript.
<script type="text/javascript">
function test() {
alert('Function from index.html');
}
</script>
Now on my react component, on Main.tsx in componentWillMount() function I want to call test function.
componentWillMount() {
window.test();
}
but this is not working for me.
The message is test doesn't exist on type window
Any help is greatly appreciated.
You can extend the Window interface like this:
interface Window {
test(): void;
}
When you are doing this within a module, you need to ensure it is the global Window interface you are extending:
declare global {
interface Window {
test(): void;
}
}
This provides the type implementation to the compiler.
I suggest to use here some Utility class. As I understand you need some functions which you can use in other components. So, the best way to do it is to create Util class with statics methods. or some module like this:
export default {
test() {
console.log('foo');
}, ...
};
If you are sure that you have a global variable. You can type your self define file in typing folder.
interface Window {
test: () => void
}
if you use eslint, you should also set test to globals config option.

Use custom JavaScript code in a Vue.js app

I'm trying to insert JavaScript code in a Vue.js router app. I need to load data from the CMS the app is served from. In order to get the data from the CMS I have to use a JavaScript library from the CMS which is not made for Vue and is not exporting it's class/functions like modern JS. So I import the JS library from in the index.html by a script tag. This works as intended.
But now I have to use the class from this CMS JavaScript library.
Before writing this as a Vue-Router app I just have used Vue for templating purposes.
So I had some code packed in the window.onload event handler.
I have to create an instance for the CMS data access class.
But this leads to a build error (using vue-cli build). Since there
are no understandable error messages from the build process
I have to use trial and error. Even simple variable assignments like var a = 1 seem not to be allowed.
A console.log('something') works. But nothing else seemes to be allowed (except defining the onload-event handler)
I have added this code in a <script> Tag inside App.vue (which was created by vue-cli create)
window.onload = function() {
try {
// Instantiate class obj for CMS data access
cmsDataAccessObj = new CMSAccessData();
waitForPlayerData = true;
}
catch (e) {
console.error(e);
}
}
UPDATE
After testing the different solutions from the answers I got aware that using non-instance variables seems to cause the build errors.
This gives an error:
waitForPlayerData = true;
This works:
this.waitForPlayerData = true;
I wouldn't recommend using window.load to run your code. There are more native approaches to do this in Vue.js.
What you should do in the case you want to run it in the main component of the app before it's been loaded is to put the code inside the beforeCreate lifecycle hook of the main component.
...
beforeCreate () {
this.cmsDataLoader()
},
methods: {
cmsDataLoader () {
try {
// Instantiate class obj for CMS data access
cmsDataAccessObj = new CMSAccessData();
waitForPlayerData = true;
}
catch (e) {
console.error(e);
}
}
}
...
This will run the code everytime a component is created before the creation. You could also use the created lifecycle hook if you want to run it after the creation of the component.
Check the following link for more information about lifecycle hooks.
The best way to place JavaScript in Vue.js App is mounted function, it is called when the component is loaded:
export default {
name: "component_name",
mounted() {
let array = document.querySelectorAll('.list_item');
},
}
You don't need window.onload, you can just put whatever you want there. I'm not entirely certain when precisely in the lifecycle it renders and maybe someone can hop in and let us know but it for sure renders when page starts. (though it makes sense that it does before the lifecycle hooks even start and that it'll solve your needs)
Better & easier solution if you want to load it before Vue loads is to add it to the main.js file. You have full control there and you can load it before Vue initializes.
No need for window.onload there either, just put it before or import a JS file before you initialize Vue, because it's going to be initialized by order.

Call react component function from javascript

I have one question because I'm not sure if that possible. I have ReactJS project that included some javascript functions.
I found solution to call javascript function from react components with window object but is it possible to call function from reactcomponents in javascript script?
For example I have definied function in React component. Is it possible to call that function in javascript?
Thank you.
A function that is supposed to be used outside React application bundle should be exposed to global scope:
window.foo = () => { /* ... */ };
Then it can be accessed as such:
<script src="react-app-bundle.js"></script>
<script>
foo();
</script>
In case React application bundle is published as UMD module, it can export a function in entry point:
export const foo = () => { /* ... */ };
its namespace will be exposed to global scope when it's loaded via <script>:
<script src="react-app-bundle.js"></script>
<script>
ReactAppNamespace.foo();
</script>
This is the case for a lot of third-party React libraries, React itself exposes React global.
It's preferable to put all code that depends on React application internals to the application itself, so accessing globals is not needed.

Call external Javascript function from react typescript components

I have a react redux application with typescript.
So the scenario is like this, I have an index.cshtml file that includes some javascript.
<script type="text/javascript">
function test() {
alert('Function from index.html');
}
</script>
Now on my react component, on Main.tsx in componentWillMount() function I want to call test function.
componentWillMount() {
window.test();
}
but this is not working for me.
The message is test doesn't exist on type window
Any help is greatly appreciated.
You can extend the Window interface like this:
interface Window {
test(): void;
}
When you are doing this within a module, you need to ensure it is the global Window interface you are extending:
declare global {
interface Window {
test(): void;
}
}
This provides the type implementation to the compiler.
I suggest to use here some Utility class. As I understand you need some functions which you can use in other components. So, the best way to do it is to create Util class with statics methods. or some module like this:
export default {
test() {
console.log('foo');
}, ...
};
If you are sure that you have a global variable. You can type your self define file in typing folder.
interface Window {
test: () => void
}
if you use eslint, you should also set test to globals config option.

How to expose angular 2 methods publicly?

I am currently working on porting a Backbone project to an Angular 2 project (obviously with a lot of changes), and one of the project requirements requires certain methods to be accessible publicly.
A quick example:
Component
#component({...})
class MyTest {
private text:string = '';
public setText(text:string) {
this.text = text;
}
}
Obviously, I could have <button (click)="setText('hello world')>Click me!</button>, and I would want to do that as well. However, I'd like to be able to access it publicly.
Like this
<button onclick="angular.MyTest.setText('Hello from outside angular!')"></click>
Or this
// in the js console
angular.MyTest.setText('Hello from outside angular!');
Either way, I would like the method to be publicly exposed so it can be called from outside the angular 2 app.
This is something we've done in backbone, but I guess my Google foo isn't strong enough to find a good solution for this using angular.
We would prefer to only expose some methods and have a list of public apis, so if you have tips for doing that as well, it'd be an added bonus. (I have ideas, but others are welcomed.)
Just make the component register itself in a global map and you can access it from there.
Use either the constructor or ngOnInit() or any of the other lifecycle hooks to register the component and ngOnDestroy() to unregister it.
When you call Angular methods from outside Angular, Angular doesn't recognize model change. This is what Angulars NgZone is for.
To get a reference to Angular zone just inject it to the constructor
constructor(zone:NgZone) {
}
You can either make zone itself available in a global object as well or just execute the code inside the component within the zone.
For example
calledFromOutside(newValue:String) {
this.zone.run(() => {
this.value = newValue;
});
}
or use the global zone reference like
zone.run(() => { component.calledFromOutside(newValue); });
https://plnkr.co/edit/6gv2MbT4yzUhVUfv5u1b?p=preview
In the browser console you have to switch from <topframe> to plunkerPreviewTarget.... because Plunker executes the code in an iFrame. Then run
window.angularComponentRef.zone.run(() => {window.angularComponentRef.component.callFromOutside('1');})
or
window.angularComponentRef.zone.run(() => {window.angularComponentRef.componentFn('2');})
This is how i did it. My component is given below. Don't forget to import NgZone. It is the most important part here. It's NgZone that lets angular understand outside external context. Running functions via zone allows you to reenter Angular zone from a task that was executed outside of the Angular zone. We need it here since we are dealing with an outside call that's not in angular zone.
import { Component, Input , NgZone } from '#angular/core';
import { Router } from '#angular/router';
#Component({
selector: 'example',
templateUrl: './example.html',
})
export class ExampleComponent {
public constructor(private zone: NgZone, private router: Router) {
//exposing component to the outside here
//componentFn called from outside and it in return calls callExampleFunction()
window['angularComponentReference'] = {
zone: this.zone,
componentFn: (value) => this.callExampleFunction(value),
component: this,
};
}
public callExampleFunction(value: any): any {
console.log('this works perfect');
}
}
now lets call this from outside.in my case i wanted to reach here through the script tags of my index.html.my index.html is given below.
<script>
//my listener to outside clicks
ipc.on('send-click-to-AT', (evt, entitlement) =>
electronClick(entitlement));;
//function invoked upon the outside click event
function electronClick(entitlement){
//this is the important part.call the exposed function inside angular
//component
window.angularComponentReference.zone.run(() =
{window.angularComponentReference.componentFn(entitlement);});
}
</script>
if you just type the below in developer console and hit enter it will invoke the exposed method and 'this works perfect ' will be printed on console.
window.angularComponentReference.zone.run(() =>
{window.angularComponentReference.componentFn(1);});
entitlement is just some value that is passed here as a parameter.
I was checking the code, and I have faced that the Zone is not probably necessary.
It works well without the NgZone.
In component constructor do this:
constructor(....) {
window['fncIdentifierCompRef'] = {
component = this
};
}
And in the root script try this:
<script>
function theGlobalJavascriptFnc(value) {
try {
if (!window.fncIdentifierCompRef) {
alert('No window.fncIdentifierCompRef');
return;
}
if (!window.fncIdentifierCompRef.component) {
alert('No window.fncIdentifierCompRef.component');
return;
}
window.fncIdentifierCompRef.component.PublicCmpFunc(value);
} catch(ex) {alert('Error on Cmp.PublicCmpFunc Method Call')}
}
</script>
This works to me.
The problem is that Angular's components are transpiled into modules that aren't as easy to access as regular JavaScript code. The process of accessing a module's features depends on the module's format.
An Angular2 class can contain static members that can be defined without instantiating a new object. You might want to change your code to something like:
#component({...})
class MyTest {
private static text: string = '';
public static setText(text:string) {
this.text = text;
}
}
Super simple solution!! save component or function with an alias outside
declare var exposedFunction;
#Component({
templateUrl: 'app.html'
})
export class MyApp {
constructor(public service:MyService){
exposedFunction = service.myFunction;
}
at index.html add in head
<script>
var exposedFunction;
</script>
Inside exposed function do not use this. parameters if you need them you will have to use closures to get it to work
This is particularly useful in ionic to test device notifications on web instead of device

Categories

Resources