How to detect tapped word in WebView? - react-native

I have a simple WebView and would like to know which word in it was tapped. For example if a user taps on any of the words in the article on the picture, such as "balloon", I would like to capture that.
Here is the code and the render.
export default class App extends React.Component {
render() {
return (
<View style={{top:100, height: 500, backgroundColor:'red' }}>
<WebView
source={{uri: 'https://www.reuters.com/article/us-art-banksy/we-just-got-banksy-ed-balloon-girl-painting-self-destructs-at-sale-idUSKCN1MG0B4?feedType=RSS&feedName=artsNews'}}
style={{height:"200", marginTop: 20}}
/>
</View>
);
}
}
UPDATE:
This is how I got WebView to communicate back the JS events based on #pritesh answer.
<WebView
source={{uri: 'https://www.reuters.com/article/us-art-banksy/we-just-got-banksy-ed-balloon-girl-painting-self-destructs-at-sale-idUSKCN1MG0B4?feedType=RSS&feedName=artsNews'}}
style={{height:"200", marginTop: 20}}
javaScriptEnabled={true}
injectedJavaScript={`document.body.addEventListener('click',
function(e){
window.postMessage("Message from WebView","*");
console.log(e);
})`}
onMessage={e => console.log("message", e)}
/>

On top of my head one approach you can try is by using the injectJavascript or injectedJavascript props of WebView.So you can register some kind of listener on the body and the use it to detect what is being pressed, like:
<WebView
ref={c => this._webview = c}
javaScriptEnabled={true}
injectedJavaScript={`document.body.addEventListener('click', function(e){
console.log(e)
})`}
/>
But you check to research how to pass the callback from Webview to React.

Related

How to implement page refresh by swipe for WebView?

There is a standard WebView and I want to implement an update in it using a swipe down, well, about like on a FlatList (onRefresh), but I don't know how to do it.
export default function QrScreen () {
return (
<View style={styles.ert__webv__container}>
<View style={styles.ert__webv__main}>
<WebView
originWhitelist={['*']}
source={{ uri: `${e_glav.e_url}/eqrcode/index.html` }}
/>
</View>
</View>
);
}

Autoplay video on element focus in react-native

import {Video} from 'expo-av';
return (
<FlatList
data={videos}
// keyExtractor={(item,ind}
keyExtractor={(item) => item.names}
renderItem={({item})=>(
<TouchableOpacity
onPress={() => {console.log('pushed');navigation.push('Details',{url:item.videourl})}}>
<Video
usePoster="true"
source={{ uri: item.videourl }}
rate={1.0}
volume={1.0}
isMuted={false}
resizeMode="cover"
shouldPlay={isFocused ? true : false}
// isLooping
// useNativeControls
posterSource={{uri:item.imageurl}}
style={{ height: 300 }}
/>
</TouchableOpacity>
)}/>
);
If one video gets focused then the video must be played and if the video is not focused then it should pause.I am using expo-av for playing video. The above code is playing all videos on the screen but I want to play the video which is focused just like what youtube does.
To do this you need to keep track of how the scrollview has moved (the offset). FlatList has an onScroll property, where the callback is given information about the list layout etc., and you are interested in tracking how much the content has been scrolled vertically - that is contentOffset.y.
Dividing this value by the list item height (a constant 300 in your case) and rounding will give you the index of the item that should be playing.
Use state to store the currently focused index:
const [focusedIndex, setFocusedIndex] = React.useState(0);
Add a handler for the onScroll event :
const handleScroll = React.useCallback(({ nativeEvent: { contentOffset: { y } } }: NativeSyntheticEvent<NativeScrollEvent>) => {
const offset = Math.round(y / ITEM_HEIGHT);
setFocusedIndex(offset)
}, [setFocusedIndex]);
Pass the handler to your list:
<FlatList
onScroll={handleScroll}
...
/>
and modify the video's shouldPlay prop:
<Video
shouldPlay={focusedIndex === index}
...
/>
You can see a working snack here: https://snack.expo.io/#mlisik/video-autoplay-in-a-list, but note that the onScroll doesn't seem to be called if you view the web version.
Try https://github.com/SvanBoxel/visibility-sensor-react-native
Saved my time. You can use it like.
import VisibilitySensor from '#svanboxel/visibility-sensor-react-native'
const Example = props => {
const handleImageVisibility = visible = {
// handle visibility change
}
render() {
return (
<View style={styles.container}>
<VisibilitySensor onChange={handleImageVisibility}>
<Image
style={styles.image}
source={require("../assets/placeholder.png")}
/>
</VisibilitySensor>
</View>
)
}
}

React Native WebView not working IOS simulator

Does the WebView work in IOS simulator?
The code below does not return an error, but also doesn't display anything.
import React, { Component } from 'react';
import { WebView } from 'react-native';
class MyTest extends Component {
render() {
return (
<WebView
source={{uri: 'https://github.com/facebook/react-native'}}
style={{marginTop: 20}}
/>
);
}
}
export default MyTest;
Thanks
WebView work well in my simulator. My code:
<WebView
useWebKit={true}
style={{flex:1}}
source={{uri:url}}
startInLoadingState={true}
renderLoading={()=>(<ActivityIndicator size='large' color={COLOR_STANDARD}
style={{marginTop:100}} />)}>
</WebView>
I want to contribute here for those getting white screen on ios. First the webview is inside scrollview because I have other content. I know it is adviced for webview not to be inside any component. I was battling this for weeks until I came upon James Liu's. I was running it on expo client (ios) and was getting white screen. Here is my code before I saw his answer.
contentContainerStyle={{
flexGrow: 1,
}}>
<WebView
ref={ref => (this.webview = ref)}
source={{uri: currentSite}}
style={{ height:550}}
scrollEnabled={true}
startInLoadingState={true}
onNavigationStateChange={this._onNavigationStateChange.bind(this)}
javaScriptEnabled = {true}
domStorageEnabled = {true}
startInLoadingState={false}
onLoad={() => this.hideSpinner()}
injectedJavaScript={jsCode}
onMessage={event => {
//Html page
const wishData = event.nativeEvent.data;
this._getProductName(wishData);
this._getProductPrice(wishData);
}}
/>
</ScrollView>
All I needed to add is useWebKit={true} and from the documentation it says:
useWebKit->If true, use WKWebView instead of UIWebView. And this props is ios specific. Furthermore, I googled and found that WKWebView is more recent than UIWebView ( I don't know more about this).
For me, the solution was to wrap my component that returned my WebView in a View with a set height OUTSIDE the file with the component that returns my WebView.
The wrapper View with the height should be in the file that component with the WebView was imported into.
It took several takes and prayer but I finally found it out muahahaha!
The real problem is in the property startInLoadingState, you have to set this to true:
<WebView
startInLoadingState={true} />

React Native: How to use Webview?

I've been testing out the WebView component, but I can't seem to get it to render things.
Sample here: https://snack.expo.io/r1oje4C3-
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.paragraph}>
Change code in the editor and watch it change on your phone!
Save to get a shareable url. You get a new url each time you save.
</Text>
<WebView source={{html: '<p>Here I am</p>'}} />
<WebView source={{ uri: 'http://www.google.com'}} />
</View>
);
}
}
When running the above example in Expo, neither of the two WebView components seem to render. What am I doing wrong?
It seems that you need to provide a width style parameter, like so :
<WebView
source={{uri: 'https://github.com/facebook/react-native'}}
style={{width: 300}}
/>
Note that you might have to provide a height style parameter as well. You can also add flex: 1 to the style.
add style prop with flex: 1 on WebView
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.paragraph}>
Change code in the editor and watch it change on your phone!
Save to get a shareable url. You get a new url each time you save.
</Text>
<WebView style={{flex: 1}} source={{html: '<p>Here I am</p>'}} />
<WebView style={{flex: 1}} source={{ uri: 'http://www.google.com'}} />
</View>
);
}
}

How to get the html source of WebView object in react native

I'm trying to access the HTML source code of a 3rd party web page to read a specific DOM element value of a page which is loaded in WebView component in react-native.
<WebView
source={{uri: 'https://www.amazon.com'}}
/>
and Suppose there's a DOM element like this:
<span class="price bold some-class-name">$459.00</span>
I also tried this component but could not do that:
https://github.com/alinz/react-native-webview-bridge
Is there any way to get the current HTML source code of page inside a WebView and Read specific DOM element value?
Looks like this functionality was added in React Native v0.37. Adding an onMessage parameter will inject a postMessage variable into your WebView. You can then just inject JavaScript as normal, select your element and postMessage it back.
render (
const jsCode = "window.postMessage(document.getElementsByClassName("price bold some-class-name"))"
return (
<View style={styles.container}>
<WebView
source={{uri: "http://..."}}
onMessage={this._onMessage}
injectedJavaScript={jsCode}
/>
</View>
);
)
The answer by Brian F is great and helped me a lot. There is just one thing missing. You need to append ReactNativeWebView to the postMessage function.
So it would look like
render (
const jsCode = "window.ReactNativeWebView.postMessage(document.getElementsByClassName("price bold some-class-name"))"
return (
<View style={styles.container}>
<WebView
source={{uri: "http://..."}}
onMessage={this._onMessage}
injectedJavaScript={jsCode}
/>
</View>
);
)
In my experience, It will work well, because I've tried to get product information from Amazon and Taobao, Rakuten.
_onMessage = (message) => {
// you can put processing code here.
}
render (
const jsCode = "window.ReactNativeWebView.postMessage(document.getElementsByClassName("class name"))"
// or you can use `document.querySelector("element query")` instead of `document.getElementsByClassName("class name")`
return (
<View style={styles.container}>
<WebView
source={{uri: "url here"}}
onMessage={this._onMessage}
injectedJavaScript={jsCode}
/>
</View>
);
)
For those who are still not getting then try this for the latest react-native
window.ReactNativeWebView.postMessage(document.getElementById('id_here').innerHTML);
const INJECT_JS = `window.ReactNativeWebView.postMessage(document.getElementById('id_here').innerHTML);
alert("Hel0....")
`
return (
<View style={styles.container}>
<WebView
source={{uri: "http://..."}}
onMessage={event => {
console.log(event.nativeEvent.data);
}}
injectedJavaScript={INJECT_JS }
/>
</View>
);
<WebView
source={{html: "<span class="price bold some-class-name">$459.00</span>"
/>
or you can right your template into a constant, then do this:
const HTMLTemplate = `<span class="price bold some-class-name">$459.00</span>`;
<WebView
source={{html: HTMLTemplate}}
/>