Embed Typeform in React app - reactjs

How can I embed a Typeform form in my React app?
The embed code that Typeform provide doesn't compile in JSX.
This is a sample of the embed code:
<div class="typeform-widget" data-url="https://sample.typeform.com/to/32423" style="width: 100%; height: 500px;"></div> <script> (function() { var qs,js,q,s,d=document, gi=d.getElementById, ce=d.createElement, gt=d.getElementsByTagName, id="typef_orm", b="https://embed.typeform.com/"; if(!gi.call(d,id)) { js=ce.call(d,"script"); js.id=id; js.src=b+"embed.js"; q=gt.call(d,"script")[0]; q.parentNode.insertBefore(js,q) } })() </script> <div style="font-family: Sans-Serif;font-size: 12px;color: #999;opacity: 0.5; padding-top: 5px;"> powered by Typeform </div>

You can use a React wrapper component I created: https://github.com/alexgarces/react-typeform-embed
It uses the official Typeform Embed SDK under the hood. Basically you have to pass your form url, but it also supports other SDK options.
import React from 'react';
import { ReactTypeformEmbed } from 'react-typeform-embed';
class App extends React.Component {
render() {
return <ReactTypeformEmbed url="https://demo.typeform.com/to/njdbt5" />;
}
}

You can view Typeform documentation for embedding with JavaScript here.
And their official npm module here.
Use React refs to trigger initialisation similarly to how you would initialise a jQuery plugin for instance.
import React from 'react';
import * as typeformEmbed from '#typeform/embed'
class Form extends React.Component {
constructor(props) {
super(props);
this.el = null;
}
componentDidMount() {
if (this.el) {
typeformEmbed.makeWidget(this.el, "https://sample.typeform.com/to/32423", {
hideFooter: true,
hideHeaders: true,
opacity: 0
});
}
}
render() {
return (
<div ref={(el) => this.el = el} style={{width: '100%', height: '300px'}} />
)
}
}
export default Form;

Inspired by Elise Chant's solution and using function based components, hooks and Typescript, this is what I come up with for my project. I did not want to install another thin wrapper on top of the official SDK.
import * as typeformEmbed from '#typeform/embed';
import React, { useEffect, useRef } from 'react';
interface EmbeddedTypeformProps {
link: string;
hideFooter?: boolean;
hideHeaders?: boolean;
opacity?: number;
}
export const EmbeddedTypeform: React.FunctionComponent<EmbeddedTypeformProps> = ({
link,
hideFooter = true,
hideHeaders = true,
opacity = 90,
}) => {
const elementRef = useRef(null);
useEffect(() => {
typeformEmbed.makeWidget(elementRef.current, link, {
hideFooter,
hideHeaders,
opacity,
});
}, [link]);
return (
<div
ref={elementRef}
style={{ width: '100%', height: '100%', flex: '1 1 auto' }}
/>
);
};

If you are using Typescript with react and you got this error just make sure that noImplicitAny set to false in tsconfig file :
"noImplicitAny": false,

Related

Openlayers Popup in React | How to?

Is there anyway to get popup overlay of OpenLayers working in react? I have no ideia how to get this working..
I've included a regular react openlayer overlay that stays over Viena on the map and a second overlay that pops up where ever a user clicks.
First install openlayers with npm i ol
Then create a class MapExample.js:
import React, { Component } from "react";
import ReactDOM from 'react-dom';
import Map from "ol/Map.js";
import View from "ol/View.js";
import Overlay from "ol/Overlay.js";
import LayerTile from "ol/layer/Tile.js";
import SourceOSM from "ol/source/OSM.js";
import * as proj from 'ol/proj';
import './MapExample.css';
const posViena = proj.fromLonLat([16.3725, 48.208889]);
export default class MapExample extends Component {
constructor(props) {
super(props);
this.state = { center: posViena, zoom: 3 };
this.map = new Map({
target: null, // set this in componentDidMount
layers: [
new LayerTile({
source: new SourceOSM()
})
],
view: new View({
center: this.state.center,
zoom: this.state.zoom
})
});
}
componentDidMount() {
this.map.setTarget("map");
// Listen to map changes
this.map.on("moveend", () => {
let center = this.map.getView().getCenter();
let zoom = this.map.getView().getZoom();
this.setState({ center, zoom });
});
// Basic overlay
const overlay = new Overlay({
position: posViena,
element: ReactDOM.findDOMNode(this).querySelector('#overlay'),
positioning: 'center-center',
stopEvent: false
});
this.map.addOverlay(overlay);
// Popup showing the position the user clicked
this.popup = new Overlay({
element: ReactDOM.findDOMNode(this).querySelector('#popup')
});
// Listener to add Popup overlay showing the position the user clicked
this.map.on('click', evt => {
this.popup.setPosition(evt.coordinate);
this.map.addOverlay(this.popup);
})
}
componentWillUnmount() {
this.map.setTarget(null);
}
render() {
return (
<div>
<div id="map" style={{ width: "100%", height: "360px" }}/>
<div className="blue-circle" id="overlay" title="overlay"/>
<div className="blue-circle" id="popup" title="Welcome to OpenLayers"/>
</div>
);
}
}
With a MapExample.css file like this:
.blue-circle {
width: 30px;
height: 30px;
border: 1px solid #088;
border-radius: 15px;
background-color: #0FF;
opacity: 0.5;
z-index: 9999; /* Watch out for this!!! */
}
Finally have your App.js like this:
import React from 'react';
import './App.css';
import MapExample from "./MapExample";
function App() {
return (
<div className="App">
<MapExample />
</div>
);
}
export default App;

React and SVG. Works for JSX, fails when used in Style

Here's my component. When I use the SVG from within JSX, it renders OK:
import React from "react";
import Radium from 'radium';
import LogoSvg from '../../images/my_logo.svg';
class HeaderBar extends React.Component {
render () {
return (
<div>
<LogoSvg />
</div>
);
}
}
export default Radium(HeaderBar);
however, when I change to this, nothing is rendered. It's as if the backgroundImage isn't even taken in. Changing the backgroundImage to a simple background: 'red' works well. What am I doing wrong here?
import React from "react";
import Radium from 'radium';
import LogoSvg from '../../images/my_logo.svg';
class HeaderBar extends React.Component {
render () {
const style = {
backgroundImage: `url(data:image/svg+xml;utf8,${LogoSvg})`,
width: '500px',
height: '500px'
};
return (
<div style={style}>
</div>
);
}
}
export default Radium(HeaderBar);
I use webpack 4 with:
test: /\.svg$/,
use: [
{
loader: "babel-loader"
},
{
loader: "react-svg-loader",
options: {
jsx: true // true outputs JSX tags
}
}
]
I believe it's because react-svg-loader will return a React component which renders an inline svg. You simply want the inline svg if you're using a data image. Maybe try svg-inline-loader instead.
I believe it can't find the path to your svg image because of the data:image/svg+xml;utf8, in front of it. It will work if you change it to:
const style = {
backgroundImage: `url(${LogoSvg})`,
width: '500px',
height: '500px'
};
or inline:
<div style={{backgroundImage: `url(${LogoSvg})`}>

How to integrate react DnD with react fullcalendar?

I have the following simple demo for a drag and drop component using React DnD plugin.
Card.js (DropSource)
import React, { Component } from 'react';
import { DragSource } from 'react-dnd';
const ItemTypes = {
CARD: 'card'
};
const cardSource = {
beginDrag(props) {
return { };
}
}
function collect(connect, monitor) {
return {
connectDragSource : connect.dragSource(),
connectDragPreview: connect.dragPreview(),
isDragging : monitor.isDragging()
}
}
class Card extends Component {
render() {
const { connectDragSource , isDragging } = this.props;
return connectDragSource(
<div style={{
opacity : isDragging ? 0.5 : 1,
height: '50px',
width: '50px',
backgroundColor: 'orange',
}}>
♞
</div>
);
}
}
export default DragSource(ItemTypes.CARD, cardSource , collect)(Card);
Box.js (Droptarget)
import React, { Component } from 'react';
import { DropTarget } from 'react-dnd';
const boxTarget = {
canDrop(props) {
},
drop(props) {
}
};
function collect(connect, monitor) {
return {
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(),
canDrop: monitor.canDrop()
};
}
const ItemTypes = {
CARD: 'card'
};
class Box extends Component {
render() {
const { connectDropTarget, isOver, canDrop } = this.props;
return connectDropTarget(
<div style={{
position: 'relative',
width: '200px',
height: '200px',
background: canDrop ? '#ff0000' : '#eee'
}}>
{ this.props.children }
</div>
);
}
}
export default DropTarget(ItemTypes.CARD, boxTarget, collect)(Box);
simpleDrag.js
import React, { Component } from 'react';
import { DragDropContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import CARD from './card';
import BOX from './box';
class simpleDrag extends Component {
render() {
return(
<div>
<BOX />
<CARD/>
</div>
);
}
}
export default DragDropContext(HTML5Backend)(simpleDrag);
And then ofcourse i use the simpleDrag element in my app.js to render and i have a working DnD example , now my question is how can i use DnD along site fullcalender.js ? I.E. say i want to make each day cell in the full calender a dropable target how do i do that ?
Fullcalender.js
React DnD
The above code can be found in my github repo HERE.
You can integrate fullcalendar and react-dnd using the ThirdPartyDraggable interface provided by fullcalendar (docs).
However, it is important to notice that fullcalendar reacts to mouse events to implement its drag and drop. react-dnd provides the a html5-backend, but they don't play together nicely as the HTML5 Drag and Drop API disables mouse events in favour of drag events.
You should thus use an alternative backend that uses those mouse events. E.g. this one.
I implemented a sandbox with an example implementation.
for the record, hooks (which React is about in functional components) cannot be used in class-based components (https://reactjs.org/warnings/invalid-hook-call-warning.html).
You might want to consider rewriting your Card and Box as RFCs instead of RCCs.

React createElement type is invalid

I am having trouble trying to publish a node module, material-ui-next-datepicker
It is working locally but not when installed as a node module
import * as React from 'react'
import * as ReactDOM from 'react-dom'
import {MuiThemeProvider, createMuiTheme, withStyles, StyledComponentProps, Theme} from 'material-ui/styles'
import DateFormatInput from 'material-ui-next-datepicker'
const theme = createMuiTheme()
const styles = (theme:Theme):Record<string, React.CSSProperties> => ({
container: {
width: '100vw',
height: '100vh',
display: 'flex',
justifyContent: 'center',
alignItems: 'center'
}
})
#(withStyles as any)(styles)
class DemoPage extends React.Component<DemoPageProps, DemoPageState> {
constructor(props) {
super(props)
this.state = {
date: undefined
}
}
onChange = (date:Date) => {
console.log(date)
this.setState({date})
}
render() {
const {classes} = this.props
const {date} = this.state
return (
<div className={classes.container}>
<DateFormatInput name='date-input' value={date} onChange={this.onChange} label='Date'/>
</div>
)
}
}
interface DemoPageProps extends React.Props<{}>, StyledComponentProps {
}
interface DemoPageState {
date: Date
}
ReactDOM.render(
<MuiThemeProvider theme={theme}>
<DemoPage/>
</MuiThemeProvider>
, document.getElementById('root'))
Here's the error in the browser
When I do print out DateFormatInput, it looks fine...definitely not undefined
I am not too familiar with dependencies and how to differentiate between peer, ambient or bundled. So, I do need some help in making this node module work
Finally able to solve this issue simply by adding .npmignore
I removed all my demo files like:
demo/
src/
index.html
tsconfig.json
webpack.config.js
Then it starts working fine by importing...

Updating a div size based on props in react

I'm trying to implement a side nav bar like how it is shown on this website
https://adminlte.io/themes/AdminLTE/index2.html
Now I'm trying to basically emulate the expanded nav bar and mini navbar toggle. However, I'm having trouble updating the size of the navbar in react.
Here is my nav bar component
import React, { Component } from 'react';
class SideNavBar extends Component {
render() {
let sideBarStyle = {
'height': '100%',
'backgroundColor': 'lightblue',
'width': "80px",
'position': 'absolute',
'top': '0',
'left': '0'
}
setTimeout(() => {
sideBarStyle["width"] = "300px";
}, 1000)
return (
<div style={sideBarStyle}>
sidenavbar
</div>
);
}
}
export default SideNavBar;
I put a set timeout there just because I wanted to quickly test if it was possible to expand the div's width from a click event.
But I get the following error
TypeError: Cannot assign to read only property 'width' of object '#<Object>'
How do I go about updating an element's size based on click events?
Can you try below.
import React, { Component } from 'react';
class SideNavBar extends Component {
constructor(props){
super(props);
this.state = {
width : 80
}
}
componentDidMount(){
setTimeout(() => {
this.setState({
width: 300
})
}, 1000);
}
render() {
let sideBarStyle = {
'height': '100%',
'backgroundColor': 'lightblue',
'width': this.state.width,
'position': 'absolute',
'top': '0',
'left': '0'
}
return (
<div style={sideBarStyle}>
sidenavbar
</div>
);
}
}
export default SideNavBar;
One more thing you no need to specify px explicitly in React. Just no is enough. React will take care of px.

Resources