How to convert inline babel script to JS - javascript

I am new to React JS and written some React JS code directly to HTML and it is working fine.
Now when I converted this inline code to JS using babel converter using Online Babel Converter and link the Converted JS to HTML, it is showng the blank the UI with no error or warning on browser console window.
I've written the inline babel script in <script type="text/babel> ... </script> tag
Note: I converted the inline code with default selected options in Online Babel Converter, Evaluate in Settings, stage-2 & react in Presets
Edit: Added some portion of code
<!DOCTYPE HTML>
<html>
<body>
<script type="text/babel>
class App extends React.Component {
createCircles = () => {
let circles = [];
for(let i = 1; i <= this.props.count; i++){
circles.push(<div className = "smallCircle" id={'circle'+i} key={i}><code className="circles" id={'id'+i}>{i}</code></div>);
}
return circles;
}
render(){
return (
<div id="circles">
<div className = "bigCircle" id="bigCircle">
<img id="bigCircleImage" src="http://localhost" />
</div>
<div className = "smallCircles">
{this.createCircles()}
</div>
</div>
);
}
}
function AppLoader(){
return (
<App />
);
}
ReactDOM.render(<AppLoader />, document.getElementById('root'));
</script>
<div id="root"></div>
</body>
</html>

Agreed with #JoeWarner answer to not to use extra AppLoader function if you are not returning more than one component.
Coming to the question, I saw that you written the script before the div tag of id root. After converting your script, import the script below the tag to see the changes

Related

NextJS Script tag not loading amplitude

I have following code to include amplitude js for tracking using Script tag. But, amplitude is not loading events.
import Document, { Html, Head, Main, NextScript } from 'next/document';
import Script from 'next/script';
<Html lang="en">
<Head>
<Script
async
key="amplitude"
src="/js/analytics/amplitude.js"
></Script>
</Head>
</Html>
amplitude.js has following code which includes amplitude using SDK way here
(function(e,t){var n=e.amplitude||{_q:[],_iq:{}};var r=t.createElement("script")
;r.type="text/javascript"
;r.integrity="sha384-MBHPie4YFudCVszzJY9HtVPk9Gw6aDksZxfvfxib8foDhGnE9A0OriRHh3kbhG3q"
;r.crossOrigin="anonymous";r.async=true
;r.src="https://cdn.amplitude.com/libs/amplitude-8.16.1-min.gz.js"
;r.onload=function(){if(!e.amplitude.runQueuedFunctions){console.log(
"[Amplitude] Error: could not load SDK")}};var s=t.getElementsByTagName("script"
)[0];s.parentNode.insertBefore(r,s);function i(e,t){e.prototype[t]=function(){
this._q.push([t].concat(Array.prototype.slice.call(arguments,0)));return this}}
var o=function(){this._q=[];return this};var a=["add","append","clearAll",
"prepend","set","setOnce","unset","preInsert","postInsert","remove"];for(
var c=0;c<a.length;c++){i(o,a[c])}n.Identify=o;var l=function(){this._q=[]
;return this};var u=["setProductId","setQuantity","setPrice","setRevenueType",
"setEventProperties"];for(var p=0;p<u.length;p++){i(l,u[p])}n.Revenue=l;var d=[
"init","logEvent","logRevenue","setUserId","setUserProperties","setOptOut",
"setVersionName","setDomain","setDeviceId","enableTracking",
"setGlobalUserProperties","identify","clearUserProperties","setGroup",
"logRevenueV2","regenerateDeviceId","groupIdentify","onInit","onNewSessionStart"
,"logEventWithTimestamp","logEventWithGroups","setSessionId","resetSessionId",
"getDeviceId","getUserId","setMinTimeBetweenSessionsMillis",
"setEventUploadThreshold","setUseDynamicConfig","setServerZone","setServerUrl",
"sendEvents","setLibrary","setTransport"];function v(t){function e(e){
t[e]=function(){t._q.push([e].concat(Array.prototype.slice.call(arguments,0)))}}
for(var n=0;n<d.length;n++){e(d[n])}}v(n);n.getInstance=function(e){e=(
!e||e.length===0?"$default_instance":e).toLowerCase();if(
!Object.prototype.hasOwnProperty.call(n._iq,e)){n._iq[e]={_q:[]};v(n._iq[e])}
return n._iq[e]};e.amplitude=n})(window,document);
amplitude.getInstance().init("YOUR_API_KEY_HERE")
Using normal script tag is working fine though.
You can use <Head> tag on any page - it will automatically set <Head> to it. Don't need to modify _document or App.
We expose a built-in component for appending elements to the head of the page: (link)
And about the script - I had the same problem. My solution (possible bad)
Inside your component (for script needs to be refreshed):
useEffect(() => {
const srcUrl = `/js/analytics/amplitude.js`;
const s = document.createElement('script');
const addScript = src => {
s.setAttribute('src', src);
s.setAttribute('async', 'async');
s.setAttribute('defer', 'defer');
s.setAttribute('id', 'specific_id')
document.body.append(s);
s.remove()
};
addScript(srcUrl)
},[]);
Or in App(for "static" scripts):
const App = ({ Component, pageProps }) => (
<>
<Script
src="/js/analytics/amplitude.js"
strategy="beforeInteractive"
/>
<Component {...pageProps} />
</>
);

Run JSX script on click of HTML button

Sorry, this is my first ever question, and I'm probably just dumb and don't understand something easy.
I have a webpage made in HTML and React there is a text box and button. I am trying to call a JSX function on click of the button. When you click the button, it is supposed to run some JSX code that will get something from the GitHub API and return it as HTML. That is why I am using JSX and not JavaScript. I found this code on another question and I modified it. I am new to JavaScript and JSX. When I put something in the textbox and click the button, the console logs: myFunction is not defined.
Is there any way to fix this?
I have a separate file called index.jsx that has all the code inside. Here it is:
/**
* See https://developer.github.com/v3/repos/branches/#get-branch
*
* Example Github api request:
* https://api.github.com/repos/ta-dachi/eatsleepcode.tech/branches/master
*/
class LatestCommitComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
author: "",
branch: "",
date: "",
sha: "",
link: ""
};
}
componentDidMount() {
// Replace this with your own repo
// https://api.github.com/repos/:owner/:repo/branches/master
fetch(
// This right below is what I am trying to replace from the text box
"https://api.github.com/repos/datkat21/datkat21.github.io/branches/master"
)
.then(response => {
response.json().then(json => {
console.log(json);
this.setState({
author: json.commit.author.login,
authorurl: json.commit.author.url,
avatar: json.commit.author.avatar_url,
branch: json.name,
date: json.commit.commit.author.date,
link: json._links.html,
authorpage: json.commit.author.html_url,
commit_url: json.commit.html_url,
commit_title: json.commit.commit.message,
});
});
})
.catch(error => {
console.log(error);
});
}
render(){
return (
<div>
// This part shows the response from the GitHub API as HTML shown in the browser
<div>{this.state.author}<br></br><a href={this.state.authorpage}><img src={this.state.avatar} alt="Loading..." class="img" /></a></div>
<div><a href={this.state.link}>Branch: {this.state.branch}</a></div><br></br>
<div>Message: {this.state.commit_title}</div>
<div>Date: {this.state.date}</div>
<div></div>
</div>
);
}
;}
ReactDOM.render(<LatestCommitComponent />, document.getElementById("root"));
Sorry if the code is too long.
I don't know how to call that file on click of the button. If anyone could help, that would be good!
Thanks.
Edit: Here is the HTML code:
<head>
<title>Begin</title>
<link type="text/css" rel="stylesheet" href="../../css/style.css" />
<script type="text/jsx" src="../render.jsx"></script>
<script type="text/jsx" src="index.jsx"></script>
<script type="text/javascript">
function myFunction() {
var GitUrl = document.getElementsByName("GitUrl")[0].value;
render(); // The function returns the product of p1 and p2
}
</script>
<script type="text/jsx" render() { render; return ( <div>
<div>{this.state.author}<br></br><a href={this.state.authorpage}><img src={this.state.avatar} alt="Loading..." class="img" /></a></div>
<div><a href={this.state.link}>Branch: {this.state.branch}</a></div><br></br>
<div>Message: {this.state.commit_title}</div>
<div>Date: {this.state.date}</div>
<div></div>
</div>
);
}
</script>
</head>
<body>
<form action="begin-create-done.html" method="get">
User/Repo URL:<br><br> <input type="text" name="GitUrl">
<br>
</form>
</body>
<button onclick="myFunction()">Get data</button> <!--button that should run script-->
</html>
Sorry if I'm just dumb and dont understand something. I'm trying to call the script when you click on the button as defined in the HTML code
while I don't see your button in your code, within your class you can create a function called fetchGithub (or something like that) then you add a property to your button that MIGHT look like this
<button onClick={fetchGithub}>Fetch Github</button>
Inside the fetchGithub function you can make a fetch call to the API and get your data. Then you can setState with the results and display it on your page.
edit: english

Insert a script tag inside template Vue

I'm creating a integration with a payment service.
The payment service provides me a form with a script tag inside, I want to insert that form with script tag inside my component template,
but vue doesn't allow the insertion of tag script within a template, how can I insert that form with script tag inside my template component?
the form with checkout of payment service:
<form action="http://localhost:8081/api/v1/payment/" method="POST">
<script
src="https://www.mercadopago.com.br/integrations/v1/web-tokenize-checkout.js"
data-public-key="KEY"
data-transaction-amount="14.90">
</script>
</form>
The expected result:
My component:
<template>
<div id="dashboard">
<form action="http://localhost:8081/api/v1/payment/" method="POST">
<script
src="https://www.mercadopago.com.br/integrations/v1/web-tokenize-checkout.js"
data-public-key="KEY"
data-transaction-amount="14.90">
</script>
</form>
</div>
</template>
<script>
import { mapState } from "vuex";
export default {
data() {
return {}
},
}
</script>
You can use an element reference and vanilla JS to add the relevant tag to the dom.
<form ref="myform">
...
</form>
mounted() {
let foo = document.createElement('script');
foo.setAttribute("src","https://www.mercadopago.com.br/integrations/v1/web-tokenize-checkout.js");
foo.setAttribute("data-transaction-amount", "14.90")
this.$refs.myform.appendChild(foo);
}
I know this is a bit old but I came across with this problem with MercadoPago and TommyF's answer really solved it. But in my case the data-transaction-amount needed to be updated dynamically depending on users choices... So if anyone facing this, my workaround was to put it inside updated(), set an id to script tag and verify if id exists. Existing, I remove by id and all .mercadopago-button. PS: I'm newbie on JS and Vue.
let existingScript = document.getElementById('mpScript');
let existingButtons = document.getElementsByClassName('mercadopago-button');
if(existingScript) {
existingScript.remove();
while(existingButtons.length > 0) {
existingButtons[0].parentNode.removeChild(existingButtons[0]);
}
}
let script = document.createElement('script');
script.setAttribute("src", "https://www.mercadopago.com.br/integrations/v1/web-tokenize-checkout.js");
script.setAttribute("data-transaction-amount", this.total);
script.setAttribute("data-public-key", 'KEY');
script.setAttribute("id", "mpScript");
this.$refs.mpCheckout.appendChild(script);

React: Script tag not working when inserted using dangerouslySetInnerHTML

I'm trying to set html sent from my server to show inside a div using dangerouslySetInnerHTML property in React. I also have script tag inside it and use functions defined in same inside that html. I have made example of error in JSFiddle here.
This is test code:
var x = '<html><scr'+'ipt>alert("this.is.sparta");function pClicked() {console.log("p is clicked");}</scr'+'ipt><body><p onClick="pClicked()">Hello</p></body></html>';
var Hello = React.createClass({
displayName: 'Hello',
render: function() {
return (<div dangerouslySetInnerHTML={{__html: x}} />);
}
});
I checked and the script tag is added to DOM, but cannot call the functions defined within that script tag. If this is not the correct way is there any other way by which I can inject the script tag's content.
I created a React component that works pretty much like dangerouslySetInnerHtml but additionally it executes all the js code that it finds on the html string, check it out, it might help you:
https://www.npmjs.com/package/dangerously-set-html-content
Here's a bit of a dirty way of getting it done ,
A bit of an explanation as to whats happening here , you extract the script contents via a regex , and only render html using react , then after the component is mounted the content in script tag is run on a global scope.
var x = '<html><scr'+'ipt>alert("this.is.sparta");function pClicked() {console.log("p is clicked");}</scr'+'ipt><body><p onClick="pClicked()">Hello</p></body></html>';
var extractscript=/<script>(.+)<\/script>/gi.exec(x);
x=x.replace(extractscript[0],"");
var Hello = React.createClass({
displayName: 'Hello',
componentDidMount: function() {
// this runs the contents in script tag on a window/global scope
window.eval(extractscript[1]);
},
render: function() {
return (<div dangerouslySetInnerHTML={{__html: x}} />);
}
});
ReactDOM.render(
React.createElement(Hello),
document.getElementById('container')
);
I don't think you need to use concatenation (+) here.
var x = '<html><scr'+'ipt>alert("this.is.sparta");function pClicked() {console.log("p is clicked");}</scr'+'ipt><body><p onClick="pClicked()">Hello</p></body></html>';
I think you can just do:
var x = '<html><script>alert("this.is.sparta");function pClicked() {console.log("p is clicked");}</script><body><p onClick="pClicked()">Hello</p></body></html>';
Since it's passed to dangerouslySetInnerHTML anyway.
But let's get back to the issue. You don't need to use regex to access the script tag's content. If you add id attribute, for example <script id="myId">...</script>, you can easily access the element.
Let's see an example of such implementation.
const x = `
<html>
<script id="myScript">
alert("this.is.sparta");
function pClicked() {console.log("p is clicked");}
</script>
<body>
<p onClick="pClicked()">Hello</p>
</body>
</html>
`;
const Hello = React.createClass({
displayName: 'Hello',
componentDidMount() {
const script = document.getElementById('myScript').innerHTML;
window.eval(script);
}
render() {
return <div dangerouslySetInnerHTML={{__html: x}} />;
}
});
If you have multiple scripts, you can add a data attribute [data-my-script] for example, and then access it using jQuery:
const x = `
<html>
<script data-my-script="">
alert("this.is.sparta");
function pClicked() {console.log("p is clicked");}
</script>
<script data-my-script="">
alert("another script");
</script>
<body>
<p onClick="pClicked()">Hello</p>
</body>
</html>
`;
const Hello = React.createClass({
constructor(props) {
super(props);
this.helloElement = null;
}
displayName: 'Hello',
componentDidMount() {
$(this.helloElement).find('[data-my-script]').each(function forEachScript() {
const script = $(this).text();
window.eval(script);
});
}
render() {
return (
<div
ref={helloElement => (this.helloElement = helloElement)}
dangerouslySetInnerHTML={{__html: x}}
/>
);
}
});
In any case, it's always good to avoid using eval, so another option is to get the text and append a new script tag with the original's script contents instead of calling eval. This answer suggests such approach
a little extension for Dasith's answer for future views...
I had a very similar issue but the in my case I got the HTML from the server side and it took a while (part of reporting solution where backend will render report to html)
so what I did was very similar only that I handled the script running in the componentWillMount() function:
import React from 'react';
import jsreport from 'jsreport-browser-client-dist'
import logo from './logo.svg';
import './App.css';
class App extends React.Component {
constructor() {
super()
this.state = {
report: "",
reportScript: ""
}
}
componentWillMount() {
jsreport.serverUrl = 'http://localhost:5488';
let reportRequest = {template: {shortid: 'HJH11D83ce'}}
// let temp = "this is temp"
jsreport.renderAsync(reportRequest)
.then(res => {
let htmlResponse = res.toString()
let extractedScript = /<script>[\s\S]*<\/script>/g.exec(htmlResponse)[0];
// console.log('html is: ',htmlResponse)
// console.log('script is: ',extractedScript)
this.setState({report: htmlResponse})
this.setState({reportScript: extractedScript})
})
}
render() {
let report = this.state.report
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo"/>
<h2>Welcome to React</h2>
</div>
<div id="reportPlaceholder">
<div dangerouslySetInnerHTML={{__html: report}}/>
</div>
</div>
);
}
componentDidUpdate() {
// this runs the contents in script tag on a window/global scope
let scriptToRun = this.state.reportScript
if (scriptToRun !== undefined) {
//remove <script> and </script> tags since eval expects only code without html tags
let scriptLines = scriptToRun.split("\n")
scriptLines.pop()
scriptLines.shift()
let cleanScript = scriptLines.join("\n")
console.log('running script ',cleanScript)
window.eval(cleanScript)
}
}
}
export default App;
hope this is helpful...
Just use some known XSS tricks. We just had a case where we had to inject a script and couldn't wait for the release so here goes our loader:
<img src onerror="var script = document.createElement('script');script.src = 'http:';document.body.appendChild(script);"/>

Can I use jsx without React to inline HTML in script?

Can I use inline HTML in a script as below by using a library like jsx:
<script src="jsx-transform.js"></script>
<script type="text/jsx">
define('component', function () {
return (<div>test html code</div>);
});
</script>
I was able to write JSX files and inject them into an HTML page using a 'fake' React file.
no-react.js
/**
* Include this script in your HTML to use JSX compiled code without React.
*/
const React = {
createElement: function (tag, attrs, children) {
var element = document.createElement(tag);
for (let name in attrs) {
if (name && attrs.hasOwnProperty(name)) {
let value = attrs[name];
if (value === true) {
element.setAttribute(name, name);
} else if (value !== false && value != null) {
element.setAttribute(name, value.toString());
}
}
}
for (let i = 2; i < arguments.length; i++) {
let child = arguments[i];
element.appendChild(
child.nodeType == null ?
document.createTextNode(child.toString()) : child);
}
return element;
}
};
Then compile your jsx.
test.jsx
const title = "Hello World";
document.getElementById('app').appendChild(
<div>
<h1>{title}</h1>
<h2>This is a template written in TSX, then compiled to JSX by tsc (the Typescript compiler), and finally
injected into a web page using a script</h2>
</div>
);
Resulting compiled 'test.js'
var title = "Hello World";
document.querySelector('#app').appendChild(React.createElement("div", null,
React.createElement("h1", null, title),
React.createElement("h2", null, "This is a template written in TSX, then compiled to JSX by tsc (the Typescript compiler), and finally" + " " + "injected into a web page")));
And finally, the HTML page that includes both scripts.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>no-react</title>
<script src="no-react.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
<script src="test.js"></script>
React renders JSX html syntax to JS using functions such as React.createElement (among others for Fragments and so on). But that all boils down to the #babel/plugin-transform-react-jsx plugin which does the transpiling of this:
return(<div id="hello">Hello World</div>)
into this...
return React.createElement('div', {id: 'hello'}, 'Hello World');
However you can replace React.createElement with you're own function to do this. You can read more on that here: https://babeljs.io/docs/en/next/babel-plugin-transform-react-jsx.html
You should also look at libraries which do exactly this such as nervjs, jsx-render and deku. All of these use a JSX html syntax without react. Some (such as jsx-render) are only focused on converting JSX to the final JS, which might be what you're looking for.
The author of that package wrote an article on it here: https://itnext.io/lessons-learned-using-jsx-without-react-bbddb6c28561
Also Typescript can do this if you use that...but I've no first hand experience with it.
To sum up
You can do it without React, but not without Babel or Typescript.
JSX is not a string-based templating language; it compiles to actual JavaScript function calls. For example,
<div attr1="something" attr2="other">
Here are some <span>children</span>
</div>
transpiles to
React.createElement("div", {attr1: "something", attr2: "other"},
"Here are some ", React.createElement("span", null, "children")
)
I was looking for something like this myself.
A way to write Components and JSX like for simple projects.
Didn't find one that I liked so I've built this:
https://github.com/SagiMedina/Aviya#aviya
Have a look, maybe it will answer your problem as well.
You will need something to transform the JSX into JS function calls. React uses Babel to do this -- you would probably be best off with that too.
There's a library by the creators of Preact that essentially does what you're after called vhtml. The tagline is "Render JSX/Hyperscript to HTML strings, without VDOM".
Here is a copy of the Readme at time of writing:
Usage
// import the library:
import h from 'vhtml';
// tell babel to transpile JSX to h() calls:
/** #jsx h */
// now render JSX to an HTML string!
let items = ['one', 'two', 'three'];
document.body.innerHTML = (
<div class="foo">
<h1>Hi!</h1>
<p>Here is a list of {items.length} items:</p>
<ul>
{ items.map( item => (
<li>{ item }</li>
)) }
</ul>
</div>
);
New: "Sortof" Components!
vhtml intentionally does not transform JSX to a Virtual DOM, instead serializing it directly to HTML. However, it's still possible to make use of basic Pure Functional Components as a sort of "template partial".
When vhtml is given a Function as the JSX tag name, it will invoke that function and pass it { children, ...props }. This is the same signature as a Pure Functional Component in react/preact, except children is an Array of already-serialized HTML strings.
This actually means it's possible to build compositional template modifiers with these simple Components, or even higher-order components.
Here's a more complex version of the previous example that uses a component to encapsulate iteration items:
let items = ['one', 'two'];
const Item = ({ item, index, children }) => (
<li id={index}>
<h4>{item}</h4>
{children}
</li>
);
console.log(
<div class="foo">
<h1>Hi!</h1>
<ul>
{ items.map( (item, index) => (
<Item {...{ item, index }}>
This is item {item}!
</Item>
)) }
</ul>
</div>
);
The above outputs the following HTML:
<div class="foo">
<h1>Hi!</h1>
<ul>
<li id="0">
<h4>one</h4>This is item one!
</li>
<li id="1">
<h4>two</h4>This is item two!
</li>
</ul>
</div>
It looks like the dom-chef package can do this. From the readme:
No API, JSX gets auto transformed into actual DOM elements.
// babel.config.js
const plugins = [
[
'#babel/plugin-transform-react-jsx',
{
pragma: 'h',
pragmaFrag: 'DocumentFragment',
}
]
];
// ...
const {h} = require('dom-chef');
const handleClick = e => {
// <a> was clicked
};
const el = (
<div class="header">
<a href="#" class="link" onClick={handleClick}>Download</a>
</div>
);
document.body.appendChild(el);
You can have a look at documentation: in-browser JSX transform,
and also see Babel documentation
You can achieve what you want, but it is discouraged in production...
Jsx parse the return (<div>test html code</div>); to something like this return React.createElement('div', {...});
then if you don't using react.js, then browser will not know what React is and trigger an error.

Categories

Resources