In localhost these videos work as expected using OnMouseHover and OnMouseOut, however when I deploy the site, the videos don't show up and I get an error saying : "Uncaught (in promise) DOMException: The element has no supported sources." The videos are uploaded to my github but I suspect that isn't the issue. Can anyone guide me as to how to fix this?
Here's my code:
interface ICanvasProps {
canvas: {
name: string;
src: any;
}
}
export function Canvas(props: ICanvasProps) {
const { canvas } = props
return (
{
canvas.map((canva) => {
return (
<div key={canva.name} className='card'>
<video
preload={'auto'}
autoPlay
loop
onLoad={()=>{"I am loaded"}}
//#ts-ignore
onMouseOver = { (event) => event.target.play() }
//#ts-ignore
onMouseOut = { (event) => event.target.pause() }
style={{
width: '100%',
borderRadius:"10px"
}}
src={canva.src}></video>
</div>
)
})
}
</div>
)
}
I tried looking for issues using event.target and suspect it could be because the browser cannot load the videos before displaying them but I am unsure how to load the videos since I'm mapping through an array of sources. `
Related
The issue with this is that apparently, Google V3 Recaptcha does not update the captchaCode, so it is required to manually reload the page each time to force this behavior. Are there any options I can programmatically force the Google V3 Recaptcha update? Here is the code, which unfortunately does not work. Possible functionality that might affect it:
Firebase auth presence
<div id="recaptcha-container" /> defined in HTML layout. Does it mean I have 2 Recaptchas on a website?
const submitSupportTicket = (e: any) => {
e.preventDefault();
recaptchaRef.current?.execute();
};
const onReCAPTCHAChange = async (captchaCode: any) => {
if (!captchaCode || !authUser) {
return;
}
try {
// Do something
} catch (error) {} finally {
recaptchaRef.current?.reset();
}
};
<ReCAPTCHA
size="invisible"
ref={ recaptchaRef }
sitekey={ process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY || '' }
onChange={ onReCAPTCHAChange }
/>
I'm looking to play an audio file using custom controls to trigger the .play() method on a custom button. To be clear, I'm not trying to have the audio auto-play. Everything works perfectly in Chrome, but in Safari I get the error:
Unhandled Promise Rejection: NotAllowedError: The request is not
allowed by the user agent or the platform in the current context,
possibly because the user denied permission.
The project is built using React and React Router, so I'm wondering if it's possibly fixable in my useEffect() hook. I've tried enabling controls on the audio element and using CSS to remove them from the DOM, but no luck.
import React, { useState, useRef, useEffect } from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import { gsap } from "gsap";
function RadioPlayerNav(props) {
const audioEl = useRef(null);
const [isPlaying, setIsPlaying] = useState(false);
const playingTitle = document.querySelector(".radio-player-nav .title p");
const toPX = (value) => {
return (parseFloat(value) / 100) * (/vh/gi.test(value) ? window.innerHeight : window.innerWidth);
};
const radioPlayerGSAP = gsap.to(".radio-player-nav .title p", {
x: toPX("-5vw"),
duration: 4,
ease: "none",
yoyo: true,
repeat: -1,
delay: 1,
repeatDelay: 1,
paused: true,
});
useEffect(() => {
if (isPlaying) {
audioEl.current.play();
radioPlayerGSAP.play();
// radioPlayerGSAP.reversed(4, false);
} else {
audioEl.current.pause();
}
}, [isPlaying]);
return (
<div className="radio-player-nav">
<div className="radio-player-controls">
<audio src="src/current-radio-mix.mp3" ref={audioEl} preload="auto"></audio>
<i
className={isPlaying ? "fas fa-pause cursor-hover" : "fas fa-play cursor-hover"}
onClick={() => {
setIsPlaying(!isPlaying);
}}
></i>
<div className="title">
<p>MIXED FEELINGS M0001</p>
</div>
<a href="src/current-radio-mix.mp3" download="Mixed Feelings M0001">
<i className="fas fa-download cursor-hover"></i>
</a>
</div>
</div>
);
}
export default RadioPlayerNav;
You can find the full github repo for the project here: https://github.com/nallstott/mixed-feelings/tree/master
Turns out, safari requires you to use useLayoutEffect instead of useEffect to accomplish this. I'm leaving the post up since I didn't see anything previously that gave the answer, along with the article that solved it for me in case anyone else has this issue with <audio> on safari.
https://lukecod.es/2020/08/27/ios-cant-play-youtube-via-react-useeffect/
I also play audio in my app, and it cycles through them. I was able to get around this by placing my audio files in a map, and use a separate function to call the audio to play.
import hold_female from '../../assets/audio/Female/hold_female.mp3';
import exhale_female from '../../assets/audio/Female/exhale_female.mp3';
import inhale_female from '../../assets/audio/Female/inhale_female.mp3';
import hold_male from '../../assets/audio/Male/hold_male.mp3';
import exhale_male from '../../assets/audio/Male/exhale_male.mp3';
import inhale_male from '../../assets/audio/Male/inhale_male.mp3';
//Props here...
createAudio('Exhale_female', exhale_female); //These place the audio into a map under the name provided.
createAudio('Inhale_female', inhale_female);
createAudio('Hold_female', hold_female);
createAudio('Exhale_male', exhale_male);
createAudio('Inhale_male', inhale_male);
createAudio('Hold_male', hold_male);
const BreatheTest: FC<BreathingProps> = ({ gender }) => {
const [stageText, setStageText] = useState<string>('Inhale');
const [index, setIndex] = useState<number>(0);
const [milliseconds, setMilliseconds] = useState<number>(0); //Set to 0 so the audio plays right away and there is no delay.
const captions = ['Inhale', 'Hold', 'Exhale', 'Hold'];
const playAudioFiles = () => {
playAudio(`${stageText}_${gender}`);
};
useEffect(() => {
const timeout = setTimeout(() => {
stopAll(); //stop all the previous audio files if they are running.
setStageText(captions[index]);
setIndex(index === 3 ? 0 : index + 1);
setMilliseconds(isSafari ? 4500 : 4350);//Sets the timeout to the time of the audio files.
playAudioFiles(); //Plays the audio files as the useEffect runs
}, milliseconds);
return () => clearTimeout(timeout);
}, [index]);
//... render method and everything else.
}
My app is for controlling breathing, and this is how I have gotten past the error you are seeing. From what I have read, iOS just requires some kind of trigger to start any media, audio or video. Putting the play function into a series of play functions kind of satisfies Safari.
It may not work for you, or how your code works, but if this is where we can discuss how we got around iOS's audio control, this is another way.
I am trying to get the chart URI by using the Data URI method. I've seen a bunch of examples using Apexchart Js to get pdf like this CodePen from ApexChart, when trying to reproduce it on react I got TypeError: Cannot read property 'type' of undefined
Here is my component did mount look like this:
componentDidMount() {
console.log(this.state.loading);
if (this.state.loading === false) {
const {options} = this.state;
const node = ReactDOM.findDOMNode(this);
if (node instanceof HTMLElement) {
var chart = new ApexCharts(node.querySelector('.charty'), options);
chart.render().then(() => {
setTimeout(function() {
chart.dataURI().then(uri => {
console.log(uri);
});
}, 4000);
});
}
} else {
return;
}
}
Type is defined as well in my state and in the render like so :
<div className='rfe'>
<div className='rfea'>
From {this.state.AxisMonth[0]} to{' '}
{this.state.AxisMonth[this.state.AxisMonth.length - 1]}
</div>
<Chart
className='charty'
type='area'
options={this.state.options}
series={this.state.series}
width='1000'
height='380'
/>
</div>
</div>
here is the error I got
Really need help with this.
You can use the exec function to call any method of ApexCharts from a React component.
getDataUri() {
ApexCharts.exec("basic-bar", "dataURI").then(({ imgURI, blob }) => {
console.log(imgURI);
});
}
Here's a full codesandbox example
I a trying to convert the code in the ML5 image classification example(Link) to my React component, which is as follows:
class App extends Component {
video = document.getElementById('video');
state = {
result :null
}
loop = (classifier) => {
classifier.predict()
.then(results => {
this.setState({result: results[0].className});
this.loop(classifier) // Call again to create a loop
})
}
componentDidMount(){
ml5.imageClassifier('MobileNet', this.video)
.then(classifier => this.loop(classifier))
}
render() {
navigator.mediaDevices.getUserMedia({ video: true })
.then((stream) => {
this.video.srcObject = stream;
this.video.play();
})
return (
<div className="App">
<video id="video" width="640" height="480" autoplay></video>
</div>
);
}
}
export default App;
However this does not work. The error message says that Unhandled Rejection (TypeError): Cannot set property 'srcObject' of null.
I can imagine video = document.getElementById('video'); is probably not able to grab the element by id. So I tried
class App extends Component {
video_element = <video id="video" width="640" height="480" autoplay></video>;
...
render() {
...
return (
<div className="App">
{video_element}
</div>
);
}
}
Which did not work either. I'm confused of what will be the correct method to implement this?
Any help appreciated, thanks!
I am answering again with an highlight on a slightly different problem rather then the ref one.
There is a huge problem that is causing the awful blinking and constantly failing promise due to an exception... and it is the get of the user media in the render method!
Consider this, every time you set the state, the component is re-rendered. You have a loop that constantly update the state of the component, and that promise keeps failing.
You need to get the user media when the component gets mounted:
componentDidMount() {
navigator.mediaDevices.getUserMedia({ video: true }).then(stream => {
if (this.video.current) {
this.video.current.srcObject = stream;
this.video.current.play();
}
ml5.imageClassifier("MobileNet", this.video.current)
.then(classifier => this.loop(classifier));
});
}
Your render method is then a lot shorter:
render() {
return (
<div className="App">
<video ref={this.video} id="video" width="640" height="480" autoPlay />
</div>
)
}
In the moment App is instantiated the video element doesn't exist yet, but the document.getElementById runs, returning undefined or null. That's why you get:
Cannot set property 'srcObject' of null
Because here:
this.video.srcObject = stream
this.video is null.
This is not the proper way of doing this. You should prepare a reference of the dom element, assign it as a prop and then access the element from there. Something like:
class App extends Component {
video = React.createRef()
...
render() {
navigator.mediaDevices.getUserMedia({ video: true })
.then((stream) => {
if ( this.video.current ) {
this.video.current.srcObject = stream;
this.video.current.play();
}
})
return (
...
<video ref={ this.video }
id="video"
width="640"
height="480"
autoplay
/>
Am a little bit stuck with Meteor, Flowrouter and React when it comes to display single items. Have been trying several solutions but don't know how to transfer the ID to my React class and can't really find any information. A push in the right direction to help understand how to do this correctly would be very appreciated
My route looks like this
FlowRouter.route('/video/:_id', {
name: "video",
action(pathParams, queryParams) {
console.log("Got the postId from the URL:", pathParams._id);
console.log("Query parameters:", queryParams);
ReactLayout.render(App, {
content: <Play />
});
}
});
So this help me get the ID and then in my Play React Class i have this code
Play = React.createClass({
renderPlay() {
return Videos.findOne(FlowRouter.getParam("_id"));
},
render() {
return (
<div className="container">
{this.renderPlay()}
</div>
);
}
});
But what i really would like to do is to pass the information to my React Clip class and also put values in variables.
Clip = React.createClass({
getDefaultProps: function () {
return {
src : 'https://www.youtube.com/embed/',
width: 1600,
height: 900
}
},
propTypes: {
video: React.PropTypes.object.isRequired
},
render() {
return (
<iframe
src={this.props.src + this.props.video.videoId} frameBorder={ 0 }>
</iframe>
);
}
});
To do this i would need to include something like this in my Play class.
renderVideo() {
// Get tasks from this.data.tasks
return this.data.videos.map((video) => {
return <Clip key={video._id} video={video} />;
});
},
Would love to understand how to do this correctly and it would really be a big step in the right direction to to understand this stack.
Tutorials and guides covering Meteor + React + kadira:Flowrouter + kadira:ReactLayout that handle more than just single page apps are welcome.