Jsdom load javascript code but doesn't run correctly - javascript

What is wrong with this code? It displays the says: hello bar from the out.js console.log but does not run the rest of the script doesn't add the link inside <div id="link"></div>
If I put the script directly in the code it works, but not in a .js file
teste2.js
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
const dom = new JSDOM(`
<!DOCTYPE html>
<html lang="en">
<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">
<title>Document</title>
</head>
<body>
<div id="link"></div>
<p>Hello world</p>
<script src="http://localhost/2022/jsdom/out.js"></script>
</body>
</html>`, { resources: "usable", runScripts: "dangerously"});
const document = dom.window.document;
console.log(document.getElementsByTagName('html')[0].innerHTML);
out.js
let T = document.getElementById('link');
T.innerHTML = 'LINK';
console.log('bar says: hello');

JSDOM loads sub-resources asynchronously, so your Node.js code is accessing the DOM before the <script> code has executed.
This is also why the log of document.getElementsByTagName('html')[0].innerHTML appears before the log of 'bar says: hello'.
You can handle this by explicitly waiting for the load event:
const document = dom.window.document;
document.addEventListener('load', () => {
console.log(document.getElementsByTagName('html')[0].innerHTML);
});
You'll need more complex logic if the script itself does anything asynchronously. Firing a custom event that you can listen for is a good approach.

Related

How to import js file from url and initialize a class in React?

I want to embed PitchPrint app on a React website. They have a vanilla html/js integration tutorial here. I added script tags with links to jQuery and their app file in my index.html file, as they require and then created a separate jsx file that suposed to return a button witch opens the app. The problem is, when I try to build, it throws an error 'PitchPrintClient' is not defined witch suposed to come from their files.
My index.html file:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://pitchprint.io/rsc/js/client.js"></script>
<title>App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
My jsx file:
import React from 'react';
const AppButton = () => {
let _launchButton = document.getElementById('launch_btn');
let _previewDiv = document.getElementById('pp_preview_div');
let _loaderDiv = document.getElementById('pp_loader_div');
_launchButton.setAttribute('disabled', 'disabled');
var ppclient = new PitchPrintClient({
apiKey: 'f80b84b4eb5cc81a140cb90f52e824f6', //Kinldy provide your own APIKey
designId: '3d8f3899904ef2392795c681091600d0', //Change this to your designId
custom: true
});
//Function to run once the app is validated (ready to be used)
var appValidated = () => {
_launchButton.removeAttribute('disabled'); //Enable the Launch button
_launchButton.onclick = () => ppclient.showApp(); //Attach event listener to the button when clicked to show the app
_loaderDiv.style.display = 'none'; //Hide the loader
};
//Function to run once the user has saved their project
var projectSaved = (_val) => {
let _data = _val.data; //You can console.log the _data varaible to see all that's passed down
if (_data && _data.previews && _data.previews.length) {
_previewDiv.innerHTML = _data.previews.reduce((_str, _prev) => `${_str}<img src="${_prev}">`, ''); //Show the preview images
}
};
ppclient.on('app-validated', appValidated);
ppclient.on('project-saved', projectSaved);
return <div>
<div id="pp_loader_div"><img src="https://pitchprint.io/rsc/images/loaders/spinner_new.svg" /></div>
<button id="launch_btn" >Launch Designer</button>
<div id="pp_preview_div"></div>
</div>;
};
export default AppButton;
PS: I know getElementById does not realy work with react, I'll deal with that later, for now I just want to initialize this app.
that's because the component is not mounted yet.
you need to call document.getElementById once the component is mounted, and in order to access dom elements inside the component you need to call it inside useEffect hook
useEffect(() => {
let _launchButton = document.getElementById("launch_btn");
let _previewDiv = document.getElementById("pp_preview_div");
let _loaderDiv = document.getElementById("pp_loader_div");
_launchButton.setAttribute("disabled", "disabled");
var ppclient = new PitchPrintClient({
apiKey: "f80b84b4eb5cc81a140cb90f52e824f6", //Kinldy provide your own APIKey
designId: "3d8f3899904ef2392795c681091600d0", //Change this to your designId
custom: true,
});
//Function to run once the app is validated (ready to be used)
var appValidated = () => {
_launchButton.removeAttribute("disabled"); //Enable the Launch button
_launchButton.onclick = () => ppclient.showApp(); //Attach event listener to the button when clicked to show the app
_loaderDiv.style.display = "none"; //Hide the loader
};
//Function to run once the user has saved their project
var projectSaved = (_val) => {
let _data = _val.data; //You can console.log the _data varaible to see all that's passed down
if (_data && _data.previews && _data.previews.length) {
_previewDiv.innerHTML = _data.previews.reduce(
(_str, _prev) => `${_str}<img src="${_prev}">`,
""
); //Show the preview images
}
};
ppclient.on("app-validated", appValidated);
ppclient.on("project-saved", projectSaved);
}, []);
Read more about React hooks and their constraints.
https://reactjs.org/docs/hooks-intro.html
also make sure to access global variables using window.PitchPrintClient
also, make sure your app is mounted once the dom is ready. by moving your script tags to the end of the body tag or using jquery on ready callback.
PS: The answer is not considering the best practices of writing react components, but I encourage you to use refs and minimize accessing to dom as much as you could.

How do I connect an audio worklet to a web page?

I'm trying to connect a web page to an audio worklet (following this demos but I got stuck.
Can somebody help?
Here's the code I've got so far.
Those files are all in the same folder, but they don't log anything.
INDEX.HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="mobile-web-app-capable" content="yes">
</head>
<body>
<script src="./index.js"></script>
</body>
</html>
INDEX.JS
const demoCode = async () => {
const audioContext = new AudioContext()
await audioContext.audioWorklet.addModule('test-processor.js')
const testNode = new AudioWorkletNode(audioContext, 'test-processor')
testNode.connect(audioContext.destination)
}
TEST-PROCESSOR.JS
class TestProcessor extends AudioWorkletProcessor {
constructor () {
super()
console.log(currentFrame)
console.log(currentTime)
}
process (inputs, outputs, parameters) {
return true
}
}
console.log(sampleRate)
const usefulVariable = 42
console.log(usefulVariable)
registerProcessor('test-processor', TestProcessor)
It looks like you're not invoking your demoCode() function anywhere. If you want to be compliant with the autoplay policy in todays browsers that needs to happen in response to a user gesture.
First you need to add a button to your HTML.
<button id="start" type="button">start</button>
Then you can attach an event listener for that button within your index.js file.
document.getElementById('start').addEventListener('click', demoCode);

Passing onclick event into template literals without global function

I've been working on adding onclick event in template literals with plain javascript (without jquery only javascript). As you can see the result html knows that onclick event on each div has function which will alert as I click but when I click, it didn't respond. It seems like suppose to work but somehow it is not working.
I got lots of help from Stackoverflow but most of the anwser was using global function. but I don't personally want to use global function since sometimes it cause some trouble.
so how can I actually pass the function into onclick event by using template literals?
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="ul"></div>
</body>
<script src="/index.js"></script>
</html>
index.js
function test() {
const list = [
{ number: 1, check: () => alert("1") },
{ number: 2, check: () => alert("2") },
{ number: 3, check: () => alert("3") },
];
const $list = list.reduce((acc, item) =>
acc + `<div onclick='${item.check}'>${item.number}</div>`,""
);
const $ul = document.querySelector("#ul");
$ul.innerHTML = $list;
}
test();
result
Instead of building the DOM via HTML strings, create actual DOM elements.
const $ul = document.querySelector("#ul");
for (const item of list) {
const element = document.createElement('div');
element.textContent = item.number;
element.onclick = item.check;
$ul.appendChild(element);
}

Forcing AngularJS directive to link outside digest cycle

This refers to an Angular 1 application.
If the DOM is modified outside the context of my angular application, I know I can use angular.element(document.body).scope().$apply() to force the whole app to re-render, including the newly injected content.
However my directives never seem to link.
So in the example below, the markup <message></message> should render Hello World, but when it is injected manually, then digest applied, the link method never appears to run.
https://jsbin.com/wecevogubu/edit?html,js,console,output
javascript
var app = angular.module('app', [])
app.directive('message', function() {
return {
template: 'Hello, World!',
link: function() {
console.log('message link')
}
}
})
document.getElementById('button').addEventListener('click', function() {
document.getElementById('content').innerHTML = '<message>default content</message>'
var scope = window.angular.element(document.body).scope()
scope.$apply()
})
html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
</head>
<body ng-app="app">
inside app:
<message></message>
outside app:
<button id="button">Print another message</button>
<div id="content"></div>
</body>
</html>
According to the docs, you can do this with angular.injector
angular.injector allows you to inject and compile some markup after the application has been bootstrapped
So the code for your example could be:
document.getElementById('button').addEventListener('click', function() {
var $directive = $('<message>default message</message>');
$('#content').append($directive);
angular.element(document.body).injector().invoke(function($compile) {
var scope = angular.element($directive).scope();
$compile($directive)(scope);
});
})
Hope this is what you are looking for!

Uncaught SyntaxError: Unexpected token )

I have an html file using which I am rendering a react component.
Here is my html file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="../../../elements/css/elements.css"/>
<link rel="shortcut icon" href="http://example.com/myicon.ico"/>
</head>
<body>
<h1>Text Modal Demo</h1>
<p>Styled using the Elements SDK.</p>
<br/>
<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-dom.js"></script>
<script src="https://cdn.polyfill.io/v2/polyfill.js?features=CustomEvent,Intl.~locale.en,Intl.~locale.fr"></script>
<script type="text/javascript" src="../../jsfiles/textModal/dist.text-modal.js"></script>
<script type="text/javascript" src="../../jsfiles/textModal/text-modal.js"></script>
</body>
</html>
And here is my text-modal.js file
function init() {
// Demo eventing API
document.body.dispatchEvent(new CustomEvent('o.InitTextModal', {
detail: { elementId: 'app', contentTemplateLarge: true, footerVisible: true, successBtnCallback: () => { console.log('¡¡success button pressed!!') }}
}
));
}
window.onload = init;
When I try to load the html file, I see this error in my console
Uncaught SyntaxError: Unexpected token ) at Line 5 text-modal.js
which is this line - detail: { elementId: 'app', contentTemplateLarge: true, footerVisible: true, successBtnCallback: () => { console.log('¡¡success button pressed!!') }}
This issue is seen only on IE 11 and Android device. Works fine for iOS
IE11 doesn't support arrow functions. You need to rewrite your javascript:
Before:
() => { console.log('¡¡success button pressed!!') }
After:
function() { console.log('¡¡success button pressed!!') }
Looks like arrow syntax is not supported on IE 11 or some older versions of Android browser.
I haven't tried this much but as far as the error looks this thingy here seems it is not supported better use the same old way of creating functions to make sure it is compatible anywhere
successBtnCallback: () => { // Anything else }
hope that helps

Categories

Resources