this.innerHTML in custom elements - web-component

I have a web component created with customElements and imported with
<link rel="import" href="component.html">
I have this tag <tag-name>test</tag-name>
In constructor I have console.log(this.innerHTML); but I don't see in console 'text' the console is empty.
(function (thisDoc) {
customElements.define('my-tag', class extends HTMLElement {
constructor() {
super();
var templ = thisDoc.getElementById('templId').content.cloneNode(true);
this.attachShadow({
mode: 'open'
}).appendChild(templ);
console.log(this.innerHTML);
}
});
})(document.currentScript.ownerDocument);

I was using Browsersync, I tried to serve with express and it works. I don't know why there are problems with Browsersync.

You can troubbleshoot your javascript by right-clicking on an element in your browser and selecting inspect element.
You will find a tab that says Debug where you can select the javascript file that has your code and in which you can set breakpoints, for example on the console.log(this.innerHtml) line of your code.
Reload your page or activate the script from the front end (UI) and when it stops at your breakpoint you can use the console tab to see if there are any errors in your code, and/or to inspect the values of your different variables.

Related

How should I include cdnjs libraries in custom javascript codes in Google tag manager?

I am new to Google analytics and Google Tag Manager and currently I am confused with using external JS libraries. Any help would be appreciated.
I need to use 'https://cdnjs.cloudflare.com/ajax/libs/fingerprintjs2/2.1.0/fingerprint2.min.js' in my custom javascript code in google tag manager. I have tried to include the script as a custom html or even custom template. The script is successfully added to the head and I see it in the inspection. But in my custom JS code , when I try to call and use library functions , it throws exception saying that the lib object is not defined.
I tried sequencing tags also , to make sure script loading tags are fired before my custom js code execution. But that did not fix the problem.
Any suggestion on how to include external JS libraries in your GTM custom JS code? I hope I explained the problem properly.
Thanks !
This example posted by jwest75674 should help. As you need to declare var = fingerprint in your script to allow Google Tag Manager to capture the data after the script has run
In short, you can copy the script below an add it as Custom HTML Tag in GTM (https://github.com/Valve/fingerprintjs2)
<script src="https://cdn.jsdelivr.net/npm/fingerprintjs2#2.1.0/dist/fingerprint2.min.js"></script>
<script type="text/javascript">
var fingerprint; // Variable to allow the Google Tag Manager to capture the data after this script has run.
if (window.requestIdleCallback) {
requestIdleCallback(function () {
Fingerprint2.get(function (components) {
console.log(components) // an array of components: {key: ..., value: ...}
})
})
} else {
setTimeout(function () {
Fingerprint2.get(function (components) {
console.log(components) // an array of components: {key: ..., value: ...}
})
}, 500)
}
</script>

Render a react component on a wordpress page

We currently have our website built with Wordpress and I have built a component in React that we want to conditionally render on the page.
I have the component built and bundled with Webpack for production but cannot figure out how to add it to our website and render the component on the page
edit I will also need to conditionally render the component (form submit, button click, etc.)
Has anyone successfully done this?
Since you've built and bundled your component already, you only need to do three things:
Add the bundled JavaScript (the Webpack output) as a script tag in whatever page you want the component to be on (preferably at the bottom of the <body>).
Example: <script src="wp-content/react/bundle.js"></script>
Add the root element that React will bind to to the same page.
Example: <div id="react-root"></div>
In your component file, render the component to the root element.
Example: ReactDOM.render(<Component />, document.getElementById('react-root'));
To dynamically show and hide the React component based on something that happens outside the component file, you need to create a way to connect the outside (the DOM) to the inside (React). The easiest way to do this is with a global variable attached to window.
In your React component, add the componentWillMount method that defines a global variable:
componentWillMount() {
window.showComponent = (option) => {
// "option" should be true or false
this.setState({ display: option });
}
}
Based on the value passed to setState above, you'll need to add the display property to your component's state:
constructor(props) {
super(props);
this.state = {
display: false
};
}
Now to make the component show or hide based on the value of this.state.display inside the render() method:
render() {
if (this.state.display) {
return (
...
)
} else {
return null;
}
}
All that's left to do is use showComponent(true) or showComponent(false) in your code that handles the form.
In your React project add the file to the global scope (window) like this:
window.myReactComponents = {
myFirstComponent: () => <MyFirstComponent/>
}
Once this is bundled reference the bundlejs file on your non-react page.
In your non react page in the global scope reference ReactDOM.render with the root element which it should use to render like this:
window.useComponent = {
renderMyFirstComponent : ReactDOM.render(
window.myReactComponents.myFirstComponent(),
document.getElementById('myReactElement')
)
};
That's it!
Live example
ReactDOM.render Documentation

Initializing react component from asp.net

Hopefully this is a slam-dunk for someone out there...my essential problem is this: I've built up a very nice set of react components which i can render in my asp.net 4.5 mvc 6 application using react.js, flux, gulp, and browserify.
as long as i have it structured so that the react components have all the data they need everything is perfect. My issue now is that I would like to have an MVC view include the react stuff, and inject run-time properties into the top-level component as it is created. Since I'm brpowserify-ing all of my react code into a bundle, i just include the one script tag in my view:
<script src="/js/modules/AuthContainer.jsx"></script>
But whereas I would normally use JSX syntax to instantiate my component with props like this:
...the view in ASP.NET never gets translated to pure JS, so that fails.
I've also tried:
ReactDOM.render
(
React.createElement(AuthContainer, { successPath: '/home' }),
document.getElementById('reactRoot')
);
...from inside a script block in my view but i get:
Uncaught ReferenceError: AuthContainer is not defined
But i'm sure i'm exposing 'AuthContainer' via the browserify-ed bundle, so i don't understand why it's unable to resolve that component.
I know there's a React.NET way to do this, but i can't get that server-side rendering to work with my components because I'm using jQuery to fetch data in componentDidMount and the server-side rendering is choking looking for $() jQuery stuff.
I'd love to get the server side rendering going but right now i just need it to do work, one way of the other. Can someone provide a simple code snippet or gist of how to instantiate a React component from inside a cshtml file with run-time props?
One easy solution is this, just put your server side properties with Javascript in a global:
index.cshtml
<script>
var __config__ = {
base: "#MyBackEdnVariable",
initialCount: "#Count",
user: {
id: #user.id,
name: #user.name,
}
};
</script>
<script src="/js/modules/AuthContainer.jsx"></script>
And with React use that global variable:
AuthContainer.js
class AuthContainer extends React.Component {
render() {
return (
<div>{this.props.user.name}</div>
);
}
}
AuthContainer.defaultProps = {
initialCount: __config__.initialCount,
user: __config__.user
};
For posterity:
ReactDOM.render
(
React.createElement
(
MyComponent,
{
prop1: #numericValue,
prop2: '#textValue',
}
),
document.getElementById('reactRoot')
);
the magic was the jsx-alternative syntax, which i was aware of couldn't get a handle on that day. This allows you to instantiate react using pure JS and therefor just embed inside a simple script tag in your cshtml.
hth.

jsdom does not fetch scripts on local file system

This is how i construct it:
var fs = require("fs");
var jsdom = require("jsdom");
var htmlSource = fs.readFileSync("./test.html", "utf8");
var doc = jsdom.jsdom(htmlSource, {
features: {
FetchExternalResources : ['script'],
ProcessExternalResources : ['script'],
MutationEvents : '2.0'
},
parsingMode: "auto",
created: function (error, window) {
console.log(window.b); // always undefined
}
});
jsdom.jQueryify(doc.defaultView, 'https://code.jquery.com/jquery-2.1.3.min.js', function() {
console.log( doc.defaultView.b ); // undefined with local jquery in html
});
the html:
<!DOCTYPE HTML>
<html>
<head></head>
<body>
<script src="./js/lib/vendor/jquery.js"></script>
<!-- <script src="http://code.jquery.com/jquery.js"></script> -->
<script type="text/javascript">
var a = $("body"); // script crashes here
var b = "b";
</script>
</body>
</html>
As soon as i replace the jquery path in the html with a http source it works. The local path is perfectly relative to the working dir of the shell / actual node script. To be honest i don't even know why i need jQueryify, but without it the window never has jQuery and even with it, it still needs the http source inside the html document.
You're not telling jsdom where the base of your website lies. It has no idea how to resolve the (relative) path you give it (and tries to resolve from the default about:blank, which just doesn't work). This also the reason why it works with an absolute (http) URL, it doesn't need to know where to resolve from since it's absolute.
You'll need to provide the url option in your initialization to give it the base url (which should look like file:///path/to/your/file).
jQuerify just inserts a script tag with the path you give it - when you get the reference in the html working, you don't need it.
I found out. I'll mark Sebmasters answer as accepted because it solved one of two problems. The other cause was that I didn't properly wait for the load event, thus the code beyond the external scripts wasn't parsed yet.
What i needed to do was after the jsdom() call add a load listener to doc.defaultView.
The reason it worked when using jQuerify was simply because it created enough of a timeout for the embedded script to load.
I had the same issue when full relative path of the jquery library to the jQueryify function. and I solved this problem by providing the full path instead.
const jsdom = require('node-jsdom')
const jqueryPath = __dirname + '/node_modules/jquery/dist/jquery.js'
window = jsdom.jsdom().parentWindow
jsdom.jQueryify(window, jqueryPath, function() {
window.$('body').append('<div class="testing">Hello World, It works')
console.log(window.$('.testing').text())
})

How to get patterns widgets to work in an iframe overlay

I have some "classic" tiles on a Plone 4.3.6 site, which contain a richtext field and two RelationChoice fields using plone.formwidget.contenttree widgets.
I have installed plone.app.widgets 1.8.0 (along with p.a.contenttypes), and I can't get the new TinyMCE and the new relateditems pattern widget to work properly. If I load the tile view URL directly (at the ##edit-tile/.... URL), the widgets actually show up and work properly. But in the iframe/overlay, they don't.
The prep-overlay looks like this:
jQuery('.tile-editable').each(function () {
jQuery(this).find('a.tile-edit-link, a.tile-delete-link').
prepOverlay({
subtype: 'iframe',
config: {
onLoad: function (e) {
jQuery('body').addClass('noscroll');
return true;
},
onClose: function() {
jQuery('body').removeClass('noscroll');
location.reload();
}
}
});
});
The iframe loads ++resource++plone.app.widgets.js in the header, and the fields are given the pat-relateditems and pat-tinymce classes as expected. But the init method inside the relateditems pattern is never called. I suppose the iframe DOM is not parsed for patterns, but I don't know where to look for the cause of this.
FWIW, there is an error in the console:
Uncaught Error: Mismatched anonymous define() module: function (){return eb}
http://requirejs.org/docs/errors.html#mismatch
in plone.app.widgets.js:166, but I don't know where that's coming from, or if it matters.
Are there any tricks to getting mockup widgets to work in an ifram overlay?
To reinitialise all patterns you can do:
var registry = require("pat-registry");
registry.scan(SELECTOR); // document or iframe or wherever you want to rescan all patterns.
IMHO you could do this on the onLoad method.

Resources