I need to implement 4 scripts, the last one has one function that I always get undefined, I have implemented it on a website without React, but at react I'm having a lot of problems.
componentDidMount () {
this.mountLeadpointScript();
}
mountLeadpointScript() {
const disclosureScript = document.createElement('script');
disclosureScript.id = 'disclosureSr';
disclosureScript.type = 'text/javascript';
disclosureScript.async = true;
document.body.appendChild(disclosureScript);
const srScript = document.createElement('script');
srScript.id = 'srScript';
srScript.type = 'text/javascript';
srScript.async = true;
document.body.appendChild(srScript);
const dataVerifyScript = document.createElement('script');
dataVerifyScript.src = '"//www.dataverify123.com/js/sr-min.js';
dataVerifyScript.async = true;
document.body.appendChild(dataVerifyScript);
dataVerifyScript.onload = () => {
window.leadpoint_dataLayer = [{ 'a': '00000', 'i': '11111' }];
window.LeadpointSecureRights.startSrTokenProcess('www.dataverify123.com');
}
}
Not displaying the real values of a & i.
Always getting undefined, i have tried withouth window, using this, putting it on the html of the app, nothing works.
Thanks in advance.
I'll attach a picture of how it should be implemented enter image description here
The solution from #Salah worked, I was trying to display a disclaimer from that script and it wasn't working due that the div wasn't being rendered when the script was executing, at the end, I ended up using a set timeout so the component will be rendered and then the script is going to execute correctly.
Otherwise, if there is a solution where I can avoid using it on the HTML would be great.
well, to solve that, you may have to paste those scripts in the index.html file, if you are using create-react-app, you will find it in: public/index.html.
Hope that helps
Related
I've been working with Liferay 7 for a while and needed to create a feedback form with prefilled values. I created a feedback form and a page, where it's shown and where I could add Javascript.
The user clicks on a link ("Did you find this helpful? Yes/No") and it takes you to the feedback page with the page and answer as URL parameters.
URL: {feedback-page-url/} ?pageUrl=/services&answer=Yes
Now here's where the problems began. Liferay updates it's values very confusingly and while generic document.getElementsByName(...) etc. seemed to work at first, they updated back when clicking the page. The difficult thing is to update the right values in right elements, so they won't be overrun by Liferay.
I provided an answer to my question below. Feel free to ask me anything, I'll try to help :)
Full code block in the end!
So I found out a solution to this problem. Liferay creates an instance (_com_liferay...) and uses it's values to be up to date, so we need to get a hold of it and update it's values. You can do it manually by inspecting and finding your instance, but I have an automatic code that should get it for you.
The id we are searching for is for DDMFormPortlet and the String we get this way is close to perfect. The String that document.querySelector() finds begins with p_p_id_com..., so we can use .substring to remove the unnecessary part and then add +"form" in the end to make it complete. If you find a better way to find this, please share it :)
// _com_liferay_dynamic_data_mapping_form_web_portlet_DDMFormPortlet_INSTANCE_randomkey_form
const idFinder = function() {
const idString = document.querySelector('[id*="DDMFormPortlet"]').id;
return(idString.substring(6) + "form");
}
Now that we have the correct String text, we'll find the element, that corresponds to it:
const formFieldArray = window[idFinder()];
Now if you try it just by itself, it most likely won't find anything, because it's loads slowly. I put all of this into try-catch with setTimeout() to make sure everything works as intended. Now all we need to do is collect the information from our URL and set it to the correct places.
const params = new URLSearchParams(location.search);
const formAutoFiller = function (params) {
try {
const formFieldArray = window[idFinder()];
// make sure you have the numbers according to your form!
formFieldArray.pages[0].rows[0].columns[0].fields[0].value=params.get('pageUrl');
formFieldArray.pages[0].rows[1].columns[0].fields[0].value=params.get('answer');
// ...
}
}
And finally, as the changed values update to the form after clicking an input field, we'll move the selection focus to one of the input fields after the other code is ran:
document.getElementsByClassName("ddm-field-text")[1].focus();
A bit cleanup for myself and we're done! Full Javascript here:
const params = new URLSearchParams(location.search);
const idFinder = function() {
const idString = document.querySelector('[id*="DDMFormPortlet"]').id;
return(idString.substring(6) + "form");
}
const formAutoFiller = function (params) {
try {
const formFieldRows = window[idFinder()].pages[0].rows;
formFieldRows[0].columns[0].fields[0].value=params.get('pageUrl');
formFieldRows[1].columns[0].fields[0].value=params.get('answer');
document.getElementsByClassName("ddm-field-text")[1].focus();
} catch (e) {
setTimeout(formAutoFiller, 500, params);
}
}
formAutoFiller(params);
For the project I'm working on I've made a React app that's based around displaying information whenever a country is clicked. I'm using an SVG world map from simplemaps.com (https://simplemaps.com/custom/world) which comes with javascript hooks to handle user clicks, e.g.
<script type="text/javascript">
simplemaps_worldmap.hooks.click_state = function(id){
alert(simplemaps_worldmap_mapdata.state_specific[id].name);
}
</script>
In order to display the map you must also include
<script src="./scripts/mapdata.js"></script>
<script src="./scripts/worldmap.js"></script>
and
<div id="map"></div>
Rendering the div component is handled by a React component I made, but this meant that the map stopped being displayed when I clicked onto a different page and clicked back. To solve this I started dynamically loading the scripts as part of the React component like so:
import React, {useEffect} from 'react';
function Map() {
useEffect(() => {
const mapScript = document.createElement('script');
const worldScript = document.createElement('script');
const clickScript = document.createElement('script');
mapScript.type = 'text/javascript';
mapScript.src = '../scripts/mapdata.js';
worldScript.type = 'text/javascript';
worldScript.src = '../scripts/worldmap.js';
clickScript.type = "text/javascript";
clickScript.innerHTML = `simplemaps_worldmap.hooks.click_state = function(id){
alert(simplemaps_worldmap_mapdata.state_specific[id].name);
}`;
document.head.appendChild(mapScript);
document.head.appendChild(worldScript);
document.body.appendChild(clickScript);
return () => {
document.head.removeChild(mapScript);
document.head.removeChild(worldScript);
document.body.removeChild(clickScript);
}
}, []);
return (
<div id="map">
</div>
)
}
export default Map;
Initially it worked, but after I added the clickScript lines:
const clickScript = document.createElement('script');
clickScript.type = "text/javascript";
clickScript.innerHTML = `simplemaps_worldmap.hooks.click_state = function(id){
alert(simplemaps_worldmap_mapdata.state_specific[id].name);
};`
document.body.appendChild(clickScript);
return () => {
document.body.removeChild(clickScript);
}
I started getting the error: ReferenceError: simplemaps_worldmap is not defined.
It works as intended when loaded in the HTML page like so:
<script src="./scripts/mapdata.js"></script>
<script src="./scripts/worldmap.js"></script>
<script type="text/javascript">
simplemaps_worldmap.hooks.click_state = function(id){
alert(simplemaps_worldmap_mapdata.state_specific[id].name);
}
</script>
However when it's being dynamically loaded it seems to break it. I have tried loading them in both the head and the body and it doesn't seem to make a difference.
To sum up the problem: the scripts work fine when done in HTML but when loaded in javascript the clickScript can't seem to find mapData.js to reference it, even though worldData.js can find mapData.js. I've tried making clickScript external, but that doesn't seem to fix the problem.
Apologies if this is an obvious fix but any help would be appreciated.
Edit: My index.html, My map.js
The SimpleMaps script, after page load, looks for the id="map" element and renders a map into it. When you re-render the component, the map gets deleted, (because you're rendering an empty div). So really, what you want to do is force SimpleMaps to reinitialise the map. Reloading the scripts is unnecessary since they are already there.
I am unable to create a working version because I don't have a license for SimpleMaps, but this is how I might approach it, basing this on what I read in the docs about manual loading.
In mapdata.js
main_settings.auto_load='no';
In the React component:
import React, {useEffect} from 'react';
function Map() {
useEffect(() => {
simplemaps_worldmap.load();
}, []);
return (
<div id="map"></div>
)
}
export default Map;
I am working on a React js project where I should dynamically add third party scripts (widgets) to the web app.
Widgets include any kind of third party platforms: Twitter, Instagram, Youplay, Youtube etc.
The current code that I have looks like this:
appendThirdPartyScript(externalScript) {
// Create an element outside the document to parse the string with
const head = document.createElement("head");
// Parse the string
head.innerHTML = externalScript;
// Copy those nodes to the real `head`, duplicating script elements so
// they get processed
let node = head.firstChild;
while (node) {
const next = node.nextSibling;
if (node.tagName === "SCRIPT") {
// Just appending this element wouldn't run it, we have to make a fresh copy
const newNode = document.createElement("script");
if (node.src) {
newNode.src = node.src;
}
while (node.firstChild) {
// Note we have to clone these nodes
newNode.appendChild(node.firstChild.cloneNode(true));
node.removeChild(node.firstChild);
}
node = newNode;
}
document.head.appendChild(node);
node = next;
}
}
So basically the scripts urls comes from the backend/api and that is a list of scripts smth like ['http://twitter-widget.js', 'http://instagram-widget.js']
So since I have an array of scripts as string I use a for loop to go thru each of element and call appendThirdPartyScript('somescript')
data.externalScripts.map(script => {
this.appendThirdPartyScript("" + script);
});
This solution worked for almost all cases until I came to this case:
['http://embed.tt.se/v10/tt-widget.js', 'new tt.TTWidget({WhereToAddWidget: 'tt-quiz-XMuxmuWHc',type: 'quiz',ID: 'xxx',clientID: 'xxx',});']
So basically the error I get is:
tt is not a function
I am assuming that the first script hasn't completed loading (in this case http://embed.tt.se/v10/tt-widget.js) and the next one is trying to call something that does not exists.
When I try to hard code http://embed.tt.se/v10/tt-widget.js within head tag in index.html directly than it works!
So this approach of dynamically adding third party widgets is not reliable. Anyone can let me know if my current code needs to be changed or any suggestion would be pretty much appreciated!
This seems to work but probably not best solution:
const delayTime = 500;
externalScriptArray.forEach((script, index) => {
setTimeout(() => {
this.appendNewTagElementToDom(script);
}, delayTime*index);
});
i'm putting together a personal website as a portfolio and i'm having trouble getting a photo gallery to work. I found a free Javascript gallery (http://ettrics.com/lab/demo/material-photo-gallery/) that I decided to implement. When putting the page together locally, the javascript runs no problem, however when I upload the page to the site (which already has plenty of other javascript running) I get the following error when scrolling on the page, or when trying to 'fullscreen' one of the images by clicking on it:
TypeError: this._fullImgs is undefined
I tried to isolate the issue and found that a line of code was executing differently on the server, than locally, the excerpt is below:
Gallery.prototype._loadFullImgsDone = function() {
var imgLoad = imagesLoaded(this._fullBox);
imgLoad.on('done', function(instance) {
var imgArr = instance.images;
this._fullImgs = [];
this._fullImgDimensions = [];
this._fullImgsTransforms = [];
for (var i = 0, ii = imgArr.length; i < ii; i++) {
var rect = imgArr[i].img.getBoundingClientRect();
this._fullImgs.push(imgArr[i].img);
this._positionFullImgs.call(this, imgArr[i].img, i);
this._fullImgDimensions.push(rect);
}
this._fullImgsLoaded = true;
}.bind(this));
};
I have found that the images are being found from their source location, however
imgLoad.on('done', function(instance) {
...
executes differently. The site is located at http://http://samueller.tech/photo-best.html id anybody would like to see for themselves the error I am getting.
Thanks in advance, i'm at a complete loss of how to fix this.
I'm seeing (on that site) the resizeHandler is getting called before the images are loaded
Gallery.prototype._handleScroll = debounce(function() {
this._resetFullImg.call(this);
}, 25);
Gallery.prototype._handleResize = function() {
this._resetFullImg.call(this);
};
Then this._resetFullImg fails because there are no images loaded yet which is why this._fullImgs is empty. The code seems to have another variable called _fullImgsLoaded and probably the _resetFullImg method should do nothing if images haven't been loaded.
You could try adding that like this:
// in material-photo-gallery.js line 1379
Gallery.prototype._resetFullImg = function() {
if (!this._fullImagesLoaded) {
return
}
this._fullImgsTransforms = [];
for (var i = 0, ii = this._fullImgs.length; i < ii; i++) {
...
I don't know how this will affect the reset of the gallery code, but it might work. It makes some sense that on your production system, the page load time (with extra JS and stuff) is such that these events might get called before things are ready which is something you don't see locally.
good luck.
I have a very unique situation.
We use a Cisco Web VPN (don't know the exact name) here at work.
If I try to use the web pages I've developed, the javascript is broken.
I have tracked it down to this:
When using the Cisco Web VPN it will actually rewrite some of the HTML/JavaScript code.
For instance, at the very beginning of the source it has stuck the following:
<script id='CSCO_GHOST' src="/+CSCOL+/cte.js"></script>
This is directly after the <html> begin tag (and not inside the <head> tags).
Inside of that source, cte.js, there is an error. That error is causing jQuery to not function properly. cte.js is part of Cisco's product and is totally out of my control.
I know how to capture errors with the windows.onerror but that is not working for this situation. The error is occurring before my scripts are loaded into the page.
Any ideas on how to suppress this error or work around such a thing?
I had my <script> tags in the <head> and then moved them to the bottom of the <body> and in neither place does it make a difference.
UPDATE:
After a bit more looking, it is something in jQuery. I commented out the <script> tag for jQuery and the error did not happen. Uncommented, the error came back.
This is what I had to do to fix the problem. I created a JS file in my web project with the following code:
if ( typeof SegmentHtml != "undefined" ) {
SegmentHtmlParam.prototype['filter'] = function() {
var name = null;
var value = null;
for (var i = 1; i < this._tokens.length; i++) {
var token = this._tokens[i];
if (token.type === ATTR_NAME) {
name = csco_g_buffer.substring(token.first_index, token.last_index).toUpperCase();
} else if (token.type === ATTR_VALUE) {
value = csco_g_buffer.substring(token.first_index, token.last_index);
};
};
var need_processing = false;
if (ParserClsidName) {
var tmp = ParserClsidName[this._clsid];
if (tmp) {
var proc = tmp[name];
need_processing = typeof proc != 'undefined';
};
};
/**
* ERROR ON NEXT LINE: name is null
*/
if (name!=null && name.toLowerCase() == "csco_proto") {
this._parent['csco_proto'] = value;
};
if (need_processing) { this._parent[name] = value; };
};
};
This is the FIRST javascript file I include in my HTML file.
<script type="text/javascript" src="js/jQueryCiscoKludge.js"></script>
I am running into this issue as well. It is really messed up for Cisco to just rewrite JS code like that, assuming it'll work for every single code on the web. There are some serious irreversible consequence like scope loss that will screw everything up. Who in their right mind would do that in the name of "security"? And what is preventing us from overriding the JS code they have injected?