How to embed external js code into React component - javascript

I am working in a project, where I have to use a widget_api code provided by RIPE Stat, to integrate the graphical widget into a React component.
For example in HTML5, I would have done it like this, and it works fine.
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Widget</title>
</head>
<body>
<script src="https://stat.ripe.net/widgets/widget_api.js"></script>
<div class="statwdgtauto">
<script>
ripestat.init("rir-geo",{"resource":"80.12.67.0/24"},null,{"size":"500","disable":["controls"]})
</script>
</div>
</body>
</html>
While doing research I found this react-safe library which allows to do the same thing in React
Here is the code of my index file.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>MyWHOIS</title>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body class="bd-home">
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="./js/polyfill.js" defer ></script>
<script src="https://stat.ripe.net/widgets/widget_api.js" async></script>
</body>
</html>
And the component that I created for...
import React, { Component } from 'react';
import Safe from "react-safe";
export default class EmbedComponent extends Component {
constructor(props){
super();
/*
const widget_api = document.createElement("script");
widget_api.src = "https://stat.ripe.net/widgets/widget_api.js";
widget_api.async = true;
document.body.appendChild(widget_api);
*/
}
render() {
const params1 = {"family":4,"warnings":1,"delegated":1,"resource":"FR"};
const params2 ={"resource":"127.0.0.1/24"};
const control = {"size":"500","disable":["controls"]};
return (
<div>
<h4>Include Embed</h4>
<div className="statwdgtauto">
<Safe.script>
{`ripestat.init("rpki-by-country",${params1},null,${control})`}
</Safe.script>
<Safe.script>
{`ripestat.init("rir-geo",${params2},null,${control})`}
</Safe.script>
</div>
</div>
)
}
}
I have errors, when I include the file with the tag with async or defer, I have a cors error
A parser-blocking, cross site (i.e. different eTLD+1) script, , is invoked via document.write. The network request for this script MAY be blocked by the browser in this or a future page load due to poor network connectivity. If blocked in this page load, it will be confirmed in a subsequent console message. See for more details.
And without defer or async I have this problem of writing on the document
Failed to execute 'write' on 'Document': It isn't possible to write into a document from an asynchronously-loaded external script unless it is explicitly opened. widget_api.js:90

Define a new state isLoading
constructor(props) {
super(props);
this.state = {
isLoading: true,
};
}
componentDidMount() {
const widget_api = document.createElement("script");
widget_api.src = "https://stat.ripe.net/widgets/widget_api.js";
widget_api.async = true;
// Wait for the onload here
widget_api.script.onload = () => setState({isLoading: false})
document.body.appendChild(widget_api);
}
and on you render function do something during the isLoading phase (you can display a loader instead of your current implementation)

The issue here is that you are locked into an implementation detail of ripeStat which prevents use of it in some of the modrn frameworks, react for instance.
If you look at the ripeStat code, here for instance, https://stat.ripe.net/widgets/widget_api.js you see that it has calls to document.write.
document.write would not kick in, in a deferred situation and is expected.Check here https://developer.mozilla.org/en-US/docs/Web/API/Document/write#notes and you will find the same error that you are seeing.
Once the document has been read, parsed and closed, document.write calls will not be entertained.
I think this is a limitation of the ripeStat library. What they should use instead is
const script = document.createElement('script');
script.src = 'https://stat.ripe.net/widgets/widget_api.js';
document.head.appendChild(script);
which will ensure that it works across the board correctly.
Another option, which is probably a better one is for an npm package from ripeStat which will help the moderm frameworks.
The only way it will work correctly right now within your react application is that the script has to be present before the browser starts parsing your HTML and interpreting it.

Related

How to run scripts in index.html in react if you don't have index.html

I am still new to React.
I have React web App to which I need to add several scripts.
Although scripts have to be inside of body tag in index.html.
Like this :
<!DOCTYPE html>
<html lang="en">
<head>
<title>React example</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style media="only screen">
html,
body,
#root {
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div id="root">Loading React example…</div>
<script
src="https://unpkg.com/systemjs#0.19.39/dist/system.src.js"
>
</script>
<script src="systemjs.config.js"></script>
<script>
System.import('./index.jsx').catch(function(err) {
console.error(err);
});
</script>
</body>
</html>
But the problem is that my app doesn't have index.html it has only index.js.
I tried to add this script with document.write but I think it's a wrong way of doing it.
Besides that i have Semantic and Syntactic errors which I cannot understand they are also attached here
You can append the scripts in your react code with:
let script = document.createElement("script");
script.setAttribute("src", scriptUrl);
script.setAttribute("type", "text/javascript");
(this is for linked scripts, but embedded scripts can be done in a similar way)
Hi I used this in my react application
I inserted dynamic yandex metrica code
Возможно поможет кому то вставить код Яндекс метрики в SPA ReactJs App динамически, код счетчика я получаю с бекенда
export function addCustomScriptAndHtmlInHead(tagString: string ): void {
const range = document.createRange()
range.selectNode(document.getElementsByTagName('BODY')[0])
const documentFragment = range.createContextualFragment(tagString)
document.head.appendChild(documentFragment)
}

Am I able to use properties on the index.html file on the vuejs mount element?

<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong
>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
properly without JavaScript enabled. Please enable it to
continue.</strong
>
</noscript>
<div id="app" thisIsAProp="This is what I need"></div>
<!-- built files will be auto injected -->
</body>
</html>
So in my main.js file the app is mounted on #app. In my App.js file I need the properties on the <div id="app"> element. I tried using web-components which did work for a basic app but another requirement is I need to be able to overwrite the CSS variables within the parent web page, and when creating web components, vue creates them with a shadow-dom. Is there a better way to get the values from the vue mount element?
Data can be passed from the the page to entry point either with global variables:
<script>
window.myApp = {
foo: 'bar'
}
</script>
<div id="app"></div>
And accessed inside the app like window.myApp.foo.
Arbitrary string data (including JSON) can be passed through HTML attributes, data attributes commonly serve this purpose:
<div id="app" data-foo="bar"></div>
And accessed inside the app like document.querySelector('#app').dataset.foo.
Solved my problem
I was able to get the properties from the index.html mount into my App.vue file using
beforeMount() {
this.neededData = this.$parent.$el.getAttribute("thisIsAProp");
},

Stencil Component Method definition

I am facing a problem developing a stencil.js web component. I have this error:
(index):28 Uncaught TypeError: comp.hideDataPanel is not a function
at HTMLDocument. ((index):28)
I want to integrate my stencil component to a bigger browserify project
Before doing that I am trying the following index.html with the stencil server-dev
<!DOCTYPE html>
<html dir="ltr" lang="en">
<head>
<meta charset="utf-8">
<title>Advanced SearchBar</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0">
<meta name="theme-color" content="#16161d">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta http-equiv="x-ua-compatible" content="IE=Edge"/>
<script src="/build/app.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"> <!-- Added -->
<link rel="manifest" href="/manifest.json">
</head>
<body>
<advanced-searchbar target_url="http://localhost:1234/results" target_id="pdbCode"></advanced-searchbar>
<script>
document.addEventListener("DOMContentLoaded", function(event) {
let comp = document.getElementsByTagName('advanced-searchbar')[0];
comp.hideDataPanel(); // --> Does not work all the time
})
let comp = document.getElementsByTagName('advanced-searchbar')[0];
comp.addEventListener('clickedOnResult',function(e){
comp.hideDataPanel(); // --> Works Fine
})
</script>
</body>
</html>
Methods of my component appear to be unresolved at the DomContentLoaded event while, the same method is resolved at the asychronous user click event. Note that user can use .hideDataPanel() method thanks to #Method() inside typescript code (as shown here: https://stenciljs.com/docs/decorators)
For the purpose of future integration I would like to bind my stencil component method at the startup of my web application.
How do i do that ?
Shall i wait for a particular event in the page or component lifecycle for component method to be resolved ?
Thank you in advance
Maybe my understanding is wrong and I've never used the event, but according to mdn it sounds like the "DomContentLoaded" event is fired when the HTML DOM has been loaded. I guess that's too early for our webcomponents to be loaded, as they're coming from JS.
So you'd need to register on an event that fires when the whole page (including JS) has been loaded which I guess is window.load.
You could also add an #Event() within the stencil component you're trying to access after it has been loaded and .emit() that event within componentDidLoad(). Stencil events seem to propagate upwards in your dom-tree, so they'll eventually reach document.
So you can register and event listener on that event like:
document.addEventListener('myCustomStencilEvent', handlerFunction);

react.js chrome browser related issue

when I am typing react.js code that is given in bucky's react.js tutorial series it is not getting executed but when pasting it from bucky's github repo. it is getting executed.....Can any one help me out please...and the code is.
<html>
<head>
<title>
creating component
</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type="text/javascript" src="C:\Users\hatim\Desktop\react\React-Boilerplate-master\src\js\react.min.js"></script>
<script type="text/javascript" src="C:\Users\hatim\Desktop\react\React-Boilerplate-master\src\js\react-dom.min.js"></script><script type="text/javascript" src="C:\Users\hatim\Desktop\react\React-Boilerplate-master\src\js\browser.min.js"></script>
</head>
<body>
<div id="container_new"></div>
<script type="text/babel" >
var mycomponent=React.createClass({
render: function(){
return(<p>this is new component </p>);
}
});
ReactDOM.render(<mycomponent />,document.getElementById('container_new'));
</script>
</body>
</html>
I don't believe you can include the JavaScript files in the context of the location on your hard drive "c:\". I think you need to be running them using a web server (IIS, Node, etc.) and then include them using relative or absolute web paths (http://localhost/mytest/src/js/react-dom.min.js).

Webpack, React & Babel, not rendering DOM

I finally after hours made my Webpack, React & Babel build setup, but when I try to just run a simple render Hello World it doesn't output anything in the DOM.
Here is my code.
var React = require('react');
var ReactDOM = require('react-dom');
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('content')
);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
<script src="bundle.js"></script>
</head>
<body>
<div id="content"></div>
</body>
</html>
And when I watch my bundle.js I can see it imports all the React & ReactDOM I need to run the render.
The test I'm running is from: https://facebook.github.io/react/docs/getting-started.html.
Getting this console error: Uncaught Error: Invariant Violation: _registerComponent(...): Target container is not a DOM element.
Your bundle.js file is being loaded before the DOM has had time to load. This means that it won't be able to find your <div id="content"> when you have asked for it.
Try putting the script loader before the end of the body.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
</head>
<body>
<div id="content"></div>
<script src="bundle.js"></script>
</body>
</html>
When browsers find a <script> tag, they pause execution while they download the file. This means that your DOM has only partially rendered when your bundle.js script begins executing. So you would have essentially been passing undefined to the ReactDOM.render method.
If you have not had this issue in the past, perhaps you have been using the jQuery.ready event handler, which waits for the DOM to be loaded before executing.
bundle.js is executed when the content element isn't yet parsed an created. Just move your script element to the end of the markup.

Categories

Resources