Inserting the iframe into react component - iframe

I have a small problem. After requesting a data from a service I got an iframe code in response.
<iframe src="https://www.example.com/show?data..." width="540" height="450"></iframe>
I would like to pass this in as a props to my modal component and display it but when I simply {this.props.iframe} it in the render function it is obviously displaying it as a string.
What is the best way to display it as html in react or using JSX?

If you don't want to use dangerouslySetInnerHTML then you can use the below mentioned solution
var Iframe = React.createClass({
render: function() {
return(
<div>
<iframe src={this.props.src} height={this.props.height} width={this.props.width}/>
</div>
)
}
});
ReactDOM.render(
<Iframe src="http://plnkr.co/" height="500" width="500"/>,
document.getElementById('example')
);
here live demo is available Demo

You can use property dangerouslySetInnerHTML, like this
const Component = React.createClass({
iframe: function () {
return {
__html: this.props.iframe
}
},
render: function() {
return (
<div>
<div dangerouslySetInnerHTML={ this.iframe() } />
</div>
);
}
});
const iframe = '<iframe src="https://www.example.com/show?data..." width="540" height="450"></iframe>';
ReactDOM.render(
<Component iframe={iframe} />,
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container"></div>
also, you can copy all attributes from the string(based on the question, you get iframe as a string from a server) which contains <iframe> tag and pass it to new <iframe> tag, like that
/**
* getAttrs
* returns all attributes from TAG string
* #return Object
*/
const getAttrs = (iframeTag) => {
var doc = document.createElement('div');
doc.innerHTML = iframeTag;
const iframe = doc.getElementsByTagName('iframe')[0];
return [].slice
.call(iframe.attributes)
.reduce((attrs, element) => {
attrs[element.name] = element.value;
return attrs;
}, {});
}
const Component = React.createClass({
render: function() {
return (
<div>
<iframe {...getAttrs(this.props.iframe) } />
</div>
);
}
});
const iframe = '<iframe src="https://www.example.com/show?data..." width="540" height="450"></iframe>';
ReactDOM.render(
<Component iframe={iframe} />,
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container"><div>

With ES6 you can now do it like this
Example Codepen URl to load
const iframe = '<iframe height="265" style="width: 100%;" scrolling="no" title="fx." src="//codepen.io/ycw/embed/JqwbQw/?height=265&theme-id=0&default-tab=js,result" frameborder="no" allowtransparency="true" allowfullscreen="true">See the Pen fx. by ycw(#ycw) on CodePen.</iframe>';
A function component to load Iframe
function Iframe(props) {
return (<div dangerouslySetInnerHTML={ {__html: props.iframe?props.iframe:""}} />);
}
Usage:
import React from "react";
import ReactDOM from "react-dom";
function App() {
return (
<div className="App">
<h1>Iframe Demo</h1>
<Iframe iframe={iframe} />,
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Edit on CodeSandbox:
https://codesandbox.io/s/react-iframe-demo-g3vst

Related

vue3 update image src dynamically

I'm trying to update an image dynamically but it is not updated.
According to the doc I have a template:
<template>
<section class="relative">
<div class="">
<img ref="heroImg" class="" src='../images/hero-bg-01.jpg' width="1440" height="577" />
</div>
</section>
</template>
Now I would like to update the src of my img and I do:
import { ref, onMounted } from "vue";
export default {
name: 'HeroTestimonials',
props:["source", "dataV"],
setup(){
const heroImg = ref(null);
onMounted(() => {
const imgUrl = new URL('../images/hero-bg-02.jpg', import.meta.url).href;
heroImg.src = imgUrl;
console.log(heroImg);
})
return {heroImg}
},
}
Into the console I have the message:
{
"_rawValue": null,
"_shallow": false,
"__v_isRef": true,
"_value": null,
"src": "http://localhost:3001/src/images/hero-bg-02.jpg" }
No errors but the image is not updated yet.
What's wrong?
Thanks for any suggestion!
[EDIT] - I've added the line return {heroImg} which was missing.
If you want to make the src attribute dynamic, you must use a v-bind in front of the attribute, for exemple v-bind:src="yourVariableHere" or use the shorthand :src. (you can see more here : https://v3.vuejs.org/api/directives.html#v-bind)
In your exemple you should do something like that :
<img class="" :src='imgUrl' width="1440" height="577" />
Then, in your script section :
<script>
import { onMounted, ref } from 'vue';
export default {
name: 'App',
setup() {
const imgUrl = ref('../images/hero-bg-01.jpg')
onMounted(() => {
imgUrl.value = '../images/hero-bg-02.jpg';
})
return {
imgUrl
}
}
}
</script>
However I'm not sure about doing that in the onMounted hook because the image would get replaced instantly

Typescript: Clicking 'X' doesn't successfully close my popup banner

I've created a popup banner with the following code (sorry if the format is off)
//this is in folder Banner.tsx
import React, {useCallback} from "react";
type Properties = {
close: () => void;
text: string;
const Banner: React.FC<Properties> = ({close, text}) => {
const onClick = useCallback(() => {
close();},
[close, text]);
return (
<div className = "BannerBox">
<div className = "banner">
<span className = "popup"> {onClick}{close}[x]
</span>
{text}
</div>
</div>
);
};
export default Banner;
//this is App.tsx
import Banner from "./Components/Banner";
function App(): JSX.Element {
const [isOpen, setIsOpen]=useState(false);
const toggleBanner = () => {
SetIsOpen(!isOpen);
};
return (
<div>
<input type = "button"
value = "popup"
onClick={toggleBanner}/>
<p>hi</p>
{isOpen && <Banner text = {"hello"} close={function (): void { throw new Error("Function not implemented.");
} }/>}
</div>
export default App;
//this is my Banner.css file (let me know if you need the full code but this is some of it)
.BannerBox{
position: fixed;
background: blue;
width:50%;
}
.banner{
position: relative;
width: 100%;
}
.popup{
content: 'x';
position: fixed;
background: green;
}
the code compiles just fine, I'm not getting any errors but the problem is that when the banner pop-ups, I can't close it by clicking 'X' i have to refresh the page in order to close the banner and I'm not sure how to fix that. Any help is appreciated!
The close function needs to be passed to the onClick callback for the span which is acting as the button. These are added as "attributes" for the jsx element. See below onClick={onClick} where your onClick callback function is passed by reference (notice no invoking parentheses within the curly braces)
In the return of Banner.tsx
<span className="popup" onClick={onClick}>
[x]
</span>
close is passed into your Banner component, so this needs to be implemented in your App component. I ensured it always closes by explicitly setting isOpen to false (instead of calling toggle)
in the return of App.tsx
{isOpen && <Banner text={"hello"} close={() => setIsOpen(false)} />}
so in total
Banner.tsx
import React, { useCallback } from "react";
import "./Banner.css";
type Properties = {
close: () => void;
text: string;
};
const Banner: React.FC<Properties> = ({ close, text }) => {
const onClick = useCallback(() => {
close();
}, [close]);
return (
<div className="BannerBox">
<div className="banner">
<span className="popup" onClick={onClick}>
[x]
</span>
{text}
</div>
</div>
);
};
export default Banner;
and App.tsx
import React, { useState } from "react";
import Banner from "./Components/Banner";
function App(): JSX.Element {
const [isOpen, setIsOpen] = useState(false);
const toggleBanner = () => {
setIsOpen(!isOpen);
};
return (
<div>
<input type="button" value="popup" onClick={toggleBanner} />
<p>hi</p>
{isOpen && <Banner text={"hello"} close={() => setIsOpen(false)} />}
</div>
);
}
export default App;
See codesandbox here
Let's assume that close() will actually close the popup banner since you did't show the implementation of it.
This line causes the issue
<span className = "popup">{onClick}{close}[x]</span>
You are supposed to pass a function to the onClick listener. Something like:
<span className = "popup" onClick={close}>[x]</span>

window.gtag not triggers GA call after initial load

The code below contains how google stuff is imported into app. It works fine and call GA as you seen in pic below. but its not working when routing to subsequent pages.
As in the image below, it calls analytics api only hard refresh the page...
_app.js:
const ymkApp = ({ Component, pageProps }) => {
const router = useRouter()
const handleRouteChange = (url) => {
console.log(url)
if (typeof window !== 'undefined') {
window.gtag('config', 'TRACKID', {
page_path: 'https://preprod.yemek.com/tarif/kiraz-receli',
})
}
}
useEffect(() => {
router.events.on('routeChangeComplete', handleRouteChange)
return () => {
router.events.off('routeChangeComplete', handleRouteChange)
}
}, [router.events])
return <Component {...pageProps} />
}
_document.js:
import getConfig from 'next/config';
import Document, { Head, Html, Main, NextScript } from 'next/document';
const { publicRuntimeConfig } = getConfig()
export default class MyDocument extends Document {
render() {
return (
<Html lang="tr">
<Head>
{/* Google Tag Manager Start */}
<link
rel="dns-prefetch preconnect"
href="https://www.google-analytics.com"
/>
<link
rel="dns-prefetch preconnect"
href="https://www.googletagmanager.com"
/>
<script
async="async"
src="https://www.googletagservices.com/tag/js/gpt.js"
/>
<script
type="text/javascript"
dangerouslySetInnerHTML={{
__html: `
var googletag = googletag || {};
googletag.cmd = googletag.cmd || [];
`,
}}
/>
<script
dangerouslySetInnerHTML={{
__html: `(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer', 'TRACKID');`,
}}
/>
<noscript
dangerouslySetInnerHTML={{
__html: `<iframe src="https://www.googletagmanager.com/ns.html?id=${publicRuntimeConfig.gtm}" height="0" width="0" style="display:none;visibility:hidden"></iframe>`,
}}
/>
{/* Google Tag Manager End */}
</Head>
<body>
<Main />
I have checked, it calls window.gtag each roue change, but doesnt trigger call GA. What might be missing here?

Dynamic component imported stuck in loading phase : next js

I am new to next js. In my project I need to display youtube videos. I have an api which provides me the video ids to show with its meta details. I wanted to create dynamic pages for each videos. I am using react-player as player.
Here is my code
[videoId].tsx
import Head from 'next/head';
import { useRouter } from 'next/router'
import Layout from '../../components/layout';
import { IVideoItem } from '../../models/videos.model';
import VideoContainer from '../../components/videos-page/video-container';
import { getVideosPaths, getVideosPageTitle, getVideosPageDescription, getVideosData } from '../../services/videos-page.services';
export default function VideoPage({videoInfo} :IVideosPageProp) {
const router = useRouter()
if (router.isFallback) {
return <div>Loading...</div>
}
return(
<>
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta charSet="utf-8" />
<title>{getVideosPageTitle(videoInfo)}</title>
<meta name="description" content={getVideosPageDescription(videoInfo)} />
<meta property="og:title" content={getVideosPageTitle(videoInfo)} key="ogtitle" />
<meta property="og:description" content={getVideosPageDescription(videoInfo)} key="ogdesc" />
</Head>
<VideoContainer data={videoInfo} />
</>
)
}
export async function getStaticPaths() {
const paths = await getVideosPaths()
//console.log('paths: ',paths);
return {
paths,
fallback: false
}
}
export async function getStaticProps({ params }:IVideosPageStaticProp) {
const {videoId} = params;
const videoInfo = await getVideosData(videoId)
return {
props: {
videoInfo
}
}
}
interface IVideosPageProp {
videoInfo: IVideoItem
}
interface IVideosPageStaticPropParams {
videoId: string
}
interface IVideosPageStaticProp {
params: IVideosPageStaticPropParams
}
video-container.tsx
import { Row, Col } from 'react-bootstrap'
import { IVideoItem } from '../../models/videos.model';
import styles from './videos-container.module.scss';
import VideoTag from '../home/videos-block/video-tag';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { faEye, faThumbsUp, faThumbsDown } from '#fortawesome/free-solid-svg-icons';
import moment from 'moment';
import dynamic from 'next/dynamic';
const ReactPlayer = dynamic(
() => import('react-player'),
{ loading: () => <p>...</p>, ssr: false }
)
export default function VideoContainer({data} :IVideosPageProp){
const videoInfo:IVideoItem = data;
const videoTag = [{"tagName": "Foo", "tagId": 1}]
const fallBackElement = () => {
return <img src={videoInfo.default_thumbnail_url} width="100%"/>
}
return (
<div className={styles['videos-container']}>
<ReactPlayer
url={`https://youtu.be/${data.video_id}`}
controls
width = "100%"
light={true}
playing={true}
fallback={fallBackElement()}
config={{
youtube: {
playerVars: { showinfo: 1 }
}
}}
/>
<div className={styles['videos-body']}>
<div className={styles['tag-list-container']}>
{videoTag.map((tag, index) =>{
return <VideoTag videoTag={tag} key={index}/>
})}
</div>
<div className={styles['video-title']}>
{videoInfo.title}
</div>
<Row className={styles['video-numbers']}>
<Col md={2} xs={2}><FontAwesomeIcon icon={faEye} className={styles['views-icon']} />{videoInfo.views_count}</Col>
<Col md={2} xs={4}>{moment(new Date(videoInfo.published_at)).format('Do MMMM YYYY')}</Col>
<Col md={4} xs={2}></Col>
<Col md={2} xs={2}><FontAwesomeIcon icon={faThumbsUp} className={styles['views-icon']} />{videoInfo.like_count}</Col>
<Col md={2} xs={2}><FontAwesomeIcon icon={faThumbsDown} className={styles['views-icon']} />{videoInfo.dislike_count}</Col>
</Row>
<div className={styles['video-description']}>
{videoInfo.description}
</div>
</div>
</div>
)
}
interface IVideosPageProp {
data:IVideoItem
}
When I run yarn dev the page is loading properly and the video player is rendering and working as expected. But when I run next buld and after that next start, the page is loading, but player is not loading. Insted it shows the "Loading..." message on the page, I refreshed several times, no luck. Not able to understand the issue. Can any one help?
Update 1:
The page is rendering with video title, video description etc. But the dynamically imported video player is not rendered. At the place of video player, it shows 'Loading...'.
Not sure if you can dynamically load from the node_module, like this:
const ReactPlayer = dynamic(
() => import('react-player'),
{ loading: () => <p>...</p>, ssr: false }
)
But you should be able to do this by creating a react-player component first, then dynamic import it like this:
// create a component named Player.js
import ReactPlayer from 'react-player';
const Player = props => (<ReactPlayer {...props}/>)
export default Player;
// then dynamic import it:
const Player = dynamic(
() => import('../components/Player'),
{ ssr: false }
)
// Then use <Player> with the same props

Meteor flow-router Reference Error "class" is not defined

I am using Meteor 1.2.1 and am running into an issue with FlowRouter. I have a '/' route declared in routes.jsx and it renders my Walls component in the MainLayout.
I added a second route '/brews' and a Brews component and and I get this error when I go to localhost:3000/brews:
Exception from Tracker recompute function:
debug.js:41 ReferenceError: Brews is not defined
at FlowRouter.route.action [as _action] (router.jsx:9)
at Route.callAction (route.js:51)
at router.js:447
at Object.Tracker.nonreactive (tracker.js:589)
at router.js:431
at Tracker.Computation._compute (tracker.js:323)
at Tracker.Computation._recompute (tracker.js:342)
at Object.Tracker._runFlush (tracker.js:481)
at Object.Tracker.flush (tracker.js:441)
at Router._invalidateTracker (router.js:489)
Here is the code:
**router.jsx***
FlowRouter.route('/', {
action() {
ReactLayout.render(MainLayout, { content: <Wall /> });
}
});
FlowRouter.route('/brews', {
action() {
ReactLayout.render(MainLayout, { content: <Brews />});
}
});
***wall.jsx*** *** This Renders fine ***
Wall = React.createClass({
render() {
return (
<div className="footer">
<h1>Welcome to the Wall!</h1>
</div>
)
}
});
***brews.jsx***
Brews = React.createClass({
render() {
return (
<div className="footer">
<h1>Welcome to the Wall!</h1>
</div>
)
}
});
***main.jsx***
MainLayout = React.createClass({
render() {
return (
<div>
<Header />
<div className="container">
{this.props.content}
</div>
<Footer />
</div>
)
}
});
***main.html***
<head>
<title>Example React App</title>
</head>
<body>
<div id="react-root"></div>
</body>

Resources