How to use dynamic style class in React Native - react-native

I am getting the style class from Rest Web Service.
try {
var securityTokenInBean = {
securityToken: authToken
};
fetchPost(
"monitorprobe/getAllMonitoringProbe",
"POST",
securityTokenInBean,
json => {
this.setState({
isLoading: false,
sumUp: json.sumUp,
styleClass : json.styleClass
});
this.state.isLoading = false;
},
err => {
console.log("needToCallBack: api call failed." + err);
//error(this.props.navigation,'error in needToCallBack ws call');
}
);
} catch (error) {
console.log("needToCallBack: api call failed." + error);
}
I need to use the style class in my View component. The value of styleClass is either criticalProbe,issueProbe,warningProbe,expiredProbe or okProbe
I have defined the styles for the all the classed defined in my StyleSheet.
const styles = StyleSheet.create({
criticalProbe : {
backgroundColor: 'black',
},
issueProbe : {
backgroundColor: 'red',
},
warningProbe : {
backgroundColor: 'orange',
},
expiredProbe : {
backgroundColor: 'yellow',
},
okProbe : {
backgroundColor: 'green',
}
});
How do I use the styleClass in my View Component which comes from rest service as the style class is Dynamic?
I tried with
const criticalProbeStyleClass = styleClass.criticalProbeStyleClass;
console.log(criticalProbeStyleClass);//comes as okProbe
<View style={[styles.box, styles.criticalProbeStyleClass ]}>
<Text style={styles.title}>Critical</Text>
<Text style={styles.criticalProbeStyleClass}>{sumUp.totalCriticalProbe}</Text>
</View>
But it does not work.
To verify I have tried with by hard coding style class and looks fine
<View style={[styles.box, styles.okProbe]}>
<Text style={styles.title}>Critical</Text>
<Text style={styles.criticalProbeStyleClass}>{sumUp.totalCriticalProbe}</Text>
</View>

If your request returning just a name for the style property;
Create a file including all your styling that you want (globalStyles.js for example) and export it. In the component you want to use import it. Then you can use the file shown like below.
const styles = StyleSheet.create({
criticalProbe : {
backgroundColor: 'black',
},
issueProbe : {
backgroundColor: 'red',
},
warningProbe : {
backgroundColor: 'orange',
},
expiredProbe : {
backgroundColor: 'yellow',
},
okProbe : {
backgroundColor: 'green',
}
});
export default styleClasses;
<View style={[styles.box, styleClasses[styleClass.criticalProbeStyleClass] ]}>
<Text style={styles.title}>Critical</Text>
<Text style={styles.criticalProbeStyleClass}>{sumUp.totalCriticalProbe}</Text>
</View>

Related

how to pass data from one screen to other screen using react-native-router

I'm very new to react-native.
can any one please tell me how to pass data to another screen using react-native-router.
I have a flatlist when a list item is clicked it will display an alert meassage , when i click on ok button it should display the RxNumberin next screen.enter image description here
here is my full class
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
FlatList,
Image,
Alert
} from 'react-native';
import { Actions } from 'react-native-router-flux';
import colors from '../styles/colors';
class MedicineFlatList extends Component {
constructor(props) {
super(props);
this.state = {
refreshing: false,
};
}
componentDidMount() {
fetch('https://api.myjson.com/bins/96ebw')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
//dataSource: responseJson,
dataSource: responseJson.map(item => item.ReadyForPickups).reduce((acc, currValue) => { return acc.concat(currValue); }, [])
},
);
})
.catch((error) => {
console.error(error);
});
}
GetItem(RxNumber) {
Alert.alert(
'RxNumber',
RxNumber,
[
{ text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel' },
{ text: 'OK', onPress: (item) => Actions.listitem({ item: item.RxDrugName }) },
],
{ cancelable: false },
);
}
listItem=(item) => {
return (
<Text style={styles.itemName}>{item.RxDrugName }</Text>
);
}
keyExtractor = (index) => {
return index.toString();
}
renderItem = ({ item }) => {
return (
<View style={styles.itemBlock}>
<View style={styles.itemMeta}>
<Text style={styles.itemName}>{item.RxDrugName}</Text>
<Text style={styles.itemLastMessage} onPress={this.GetItem.bind(this, item.RxNumber)}>{item.RxNumber}</Text>
</View>
<View style={styles.footerStyle}>
<View style={{ paddingVertical: 10 }}>
<Text style={styles.status}>{item.StoreNumber}</Text>
</View>
<View style={{ justifyContent: 'center', alignItems: 'center' }}>
<Image source={require('../assets/right_arrow_blue.png')} />
</View>
</View>
</View>
);
}
renderSeparator() {
return <View style={styles.separator} />;
}
render() {
return (
<View style={styles.container}>
<FlatList
data={this.state.dataSource}
keyExtractor={this.keyExtractor}
renderItem={this.renderItem}
ItemSeparatorComponent={this.renderSeparator.bind(this)}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
paddingHorizontal: 30,
backgroundColor: colors.white
},
itemBlock: {
flexDirection: 'row',
paddingVertical: 15,
},
itemMeta: {
justifyContent: 'center'
},
itemName: {
fontSize: 16,
color: colors.black_two,
paddingBottom: 10
},
itemLastMessage: {
fontSize: 14,
color: colors.black_two,
},
status: {
fontSize: 14,
color: colors.blue,
fontWeight: 'bold'
},
separator: {
borderRadius: 4,
borderWidth: 1,
borderColor: colors.light_gray,
},
footerStyle: {
flexDirection: 'row',
flex: 1,
paddingVertical: 10,
justifyContent: 'flex-end'
}
});
export default MedicineFlatList;
Thanks everyone I got the answer.
if your are using react-native-router-flux which i recommend
https://www.npmjs.com/package/react-native-router-flux
it is something like that
Action.Screen2({id : 1})
and on screen2
this.props.id will be 1
and if your are using react navigation
read the doc it will help you
it is something like this
this.props.navigation.navigate('Screen2', {data: 'some-stuff'})
and you can access data in other screen like this.
this.props.navigation.state.params('data')
Tulasi, Roozbeh Mohammadzadeh is correct and answers your question with the use of react-native-router-flux; however, as you continue you may wish to explore using redux or another alternative Appstate system, there are a few.
Reason: Passing data will work for small projects, but larger projects passing up and down the grandparent, parent, child component chain becomes cumbersome and inefficient to troubleshoot and/or maintain.
But to answer your question about passing data using react-native-router see the following right above the Todos section : https://www.npmjs.com/package/react-native-router
The this.props.toRoute() callback prop takes one parameter (a JavaScript object) which can have the following keys:
name: The name of your route, which will be shown as the title of the
navigation bar unless it is changed.
component (required): The React
class corresponding to the view you want to render.
leftCorner:
Specify a component to render on the left side of the navigation bar
(like the "Add people"-button on the first page of the Twitter app)
rightCorner: Specify a component to render on the right side of the
navigation bar
titleComponent: Specify a component to replace the
title. This could for example be your logo (as in the first page of
the Instagram app)
headerStyle: change the style of your header for
the new route. You could for example specify a new backgroundColor
and the router will automatically make a nice transition from one
color to the other!
data: Send custom data to your route.

React Native - text disappearing on custom component style change

Getting a strange error when trying to apply conditional styling to a custom component. Whenever the style change should appear the text completely disappears. If I start typing again, the new styling appears but once the style would change again, the text disappears again. If I apply the styling as static, the custom styling works completely fine. I'm not sure what the issue could be. Thanks in advance for the help.
<UserInput
style = {!this.state.isValidEmail ? styles.errorInline : styles.default}
placeholder="Email"
autoCapitalize={'none'}
returnKeyType={'next'}
autoCorrect={false}
onSubmitEditing={() => this.focusNextField('password')}
updateState={(email) => {
let formattedEmail = email.trim();
this.state.initialValidationChecked? this.validate(formattedEmail) : this.setState({formattedEmail})}
}
blurOnSubmit={true}
onBlur2={(event) => this.validate(event.nativeEvent.text.trim())}
/>
errorInline: {
color: 'red',
},
default : {
color: '#777777'
}
export default class UserInput extends Component {
componentDidMount() {
if (this.props.onRef != null) {
this.props.onRef(this)
}
}
onSubmitEditing() {
if(this.props.onSubmitEditing){
this.props.onSubmitEditing();
}
}
focus() {
this.textInput.focus();
}
render() {
return (
<View style={styles.inputWrapper}>
<TextInput
style={[styles.input, this.props.style]}
placeholder={this.props.placeholder}
secureTextEntry={this.props.secureTextEntry}
autoCorrect={this.props.autoCorrect}
autoCapitalize={this.props.autoCapitalize}
returnKeyType={this.props.returnKeyType}
onChangeText={(value) => this.props.updateState(value)}
onEndEditing={(value) => { if(this.props.onBlur2) return this.props.onBlur2(value)}}
ref={input => this.textInput = input}
blurOnSubmit={this.props.blurOnSubmit}
onSubmitEditing={this.onSubmitEditing.bind(this)}
underlineColorAndroid='transparent'
/>
</View>
);
}
}
UserInput.propTypes = {
placeholder: PropTypes.string.isRequired,
secureTextEntry: PropTypes.bool,
autoCorrect: PropTypes.bool,
autoCapitalize: PropTypes.string,
returnKeyType: PropTypes.string,
};
const DEVICE_WIDTH = Dimensions.get('window').width;
const styles = StyleSheet.create({
input: {
width: DEVICE_WIDTH - 70,
height: 40,
marginHorizontal: 20,
marginBottom: 30,
color: '#777777',
borderBottomWidth: 1,
borderBottomColor: '#0099cc'
},
inputWrapper: {
justifyContent: 'center',
alignItems: 'center',
flex: 1,
},
});
Styles are given as object (key-value pair).
But looking at your codes in the following line
style = {!this.state.isValidEmail ? styles.errorInline : 'none'}
When this.state.isValidEmail returns true, you're just giving 'none' to the style, which is a syntax error, you should return something like this
style = {!this.state.isValidEmail ? styles.errorInline : {display: 'none'}}

Getting Undefined is not a function in one of the function

I am very new to React Native. I am trying to make autocomplete text box in React Native. I am using react-native-autocomplete-input plugin. I am reading the data from JSON file. I keep getting this error. user is entering the service name in the text box so they can enter ser and it will show service1 as an option for user to select.
Below is my App.js code:
/**
* Sample React Native App
* https://github.com/facebook/react-native
* #flow
*/
import service from './services.json';
import Autocomplete from 'react-native-autocomplete-input';
import React, { Component } from 'react';
import {
StyleSheet,
Text,
TouchableOpacity,
View
} from 'react-native';
class Autocomp extends Component {
static renderServices(coservice) {
const { ser, Location, secondLoc} = coservice;
return (
<View>
<Text style={styles.titleText}>{ser}</Text>
<Text style={styles.openingText}>{secondLoc}</Text>
</View>
);
}
constructor(props) {
super(props);
this.state = {
query: '',
services:[]
};
}
componentDidMount(){
const {results: services} = service;
this.setState({services});
}
findServices(query) {
if (query === '') {
return [];
}
const {services } = this.state;
const regex = new RegExp(`${query.trim()}`, 'i');
return services.filter(coservice=> coservice.ser.search(regex) >= 0);
}
render() {
const { query } = this.state;
const services = this.findservices(query);
const comp = (a, b) => a.toLowerCase().trim() === b.toLowerCase().trim();
return (
<View style={styles.container}>
<Autocomplete
autoCapitalize="none"
autoCorrect={false}
containerStyle={styles.autocompleteContainer}
data={services.length === 1 && comp(query, services[0].ser) ? [] : services}
defaultValue={query}
onChangeText={text => this.setState({ query: text })}
placeholder="Enter Services here"
renderItem={({ ser, Phone }) => (
<TouchableOpacity onPress={() => this.setState({ query: ser })}>
<Text style={styles.itemText}>
{ser}
</Text>
</TouchableOpacity>
)}
/>
<View style={styles.descriptionContainer}>
{services.length > 0 ? (
Autocomp.renderServices(services[0])
) : (
<Text style={styles.infoText}>
Enter services
</Text>
)}
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#F5FCFF',
flex: 1,
paddingTop: 25
},
autocompleteContainer: {
flex: 1,
left: 0,
position: 'absolute',
right: 0,
top: 0,
zIndex: 1
},
itemText: {
fontSize: 15,
margin: 2
},
descriptionContainer: {
// `backgroundColor` needs to be set otherwise the
// autocomplete input will disappear on text input.
backgroundColor: '#F5FCFF',
marginTop: 25
},
infoText: {
textAlign: 'center'
},
titleText: {
fontSize: 18,
fontWeight: '500',
marginBottom: 10,
marginTop: 10,
textAlign: 'center'
},
directorText: {
color: 'grey',
fontSize: 12,
marginBottom: 10,
textAlign: 'center'
},
openingText: {
textAlign: 'center'
}
});
export default Autocomp;
below is my JSON (services.json) file:
{
"id":1,
"ser": "Service1",
"Location": "TestLoc1",
"Phone":"(999)-921-9292",
"SecondLoc": "TestLoc",
"email":"accrmail#asrclkrec.com",
"sourceLat":"33.977806",
"sourceLong":"-117.373261",
"destLatL1":"33.613355",
"destLongL1":"-114.596569",
"destLatL2":"33.761693",
"destLongL2":"-116.971169",
"destAddr1": "Test Drive, 99999",
"destAddr2": "Test City, Test Drive, 92345"
},
{
"id":1,
"ser": "TestService",
"Location": "TestLoc1",
"Phone":"(999)-921-9292",
"SecondLoc": "TestLoc",
"email":"accrmail#asrclkrec.com",
"sourceLat":"33.977806",
"sourceLong":"-117.373261",
"destLatL1":"33.613355",
"destLongL1":"-114.596569",
"destLatL2":"33.761693",
"destLongL2":"-116.971169",
"destAddr1": "Test Drive, 99999",
"destAddr2": "Test City, Test Drive, 92345"
},
]
Any help will be highly appreciated.
This is just a silly mistake, your function names don't match. You called findservices, but it should be findServices, with an uppercase S
Also, I want to point out that your way of finding suggestions is fine, but there's a bug in it. In your findServices function, you have
const regex = new RegExp(`${query.trim()}`, 'i');
You're constructing a new regular expression from query, but this doesn't always succeed. For example, if user enters a special character such as [, then this line of code will throw an error, because query now contains an open bracket but not a closing bracket ], therefore, a regex cannot be constructed from query. You should change it to something like this:
findServices(query) {
const inputValue = query.trim().toLowerCase();
const inputLength = inputValue.length;
const { services } = this.state;
return inputLength === 0 ? [] : services.filter(ser =>
ser.toLowerCase().slice(0, inputLength) === inputValue);
}
In addition of K.Wu answer, please remove this line const services = this.findservices(query); in render method and placed it inside onChangeText of autocomplete . It should be triggered after user has typing the text on autocomplete box not rendered by default
Autocomplete
autoCapitalize="none"
autoCorrect={false}
containerStyle={styles.autocompleteContainer}
data={services.length === 1 && comp(query, services[0].ser) ? [] : services}
defaultValue={query}
onChangeText={text => this.findServices(text}
placeholder="Enter Services here"
renderItem={({ ser, Phone }) => (
<TouchableOpacity onPress={() => this.setState({ query: ser })}>
<Text style={styles.itemText}>
{ser}
</Text>
</TouchableOpacity>
)}
/>

Type Error in filter function

I am trying to make a autocomplete text box in React Native. I am getting an error in filter function. When the user types the services then the text box should get autocompleted with the full name of the service.The service name is coming from my json file. I am using 'react-native-autocomplete-input' in order to accomplish this. Below is the screen shot of the error:
Below is my App.js code.
/**
* Sample React Native App
* https://github.com/facebook/react-native
* #flow
*/
import service from './services.json';
import Autocomplete from 'react-native-autocomplete-input';
import React, { Component } from 'react';
import {
StyleSheet,
Text,
TouchableOpacity,
View
} from 'react-native';
class Autocomp extends Component {
static renderServices(coservice) {
const { ser, Location, secondLoc} = coservice;
return (
<View>
<Text style={styles.titleText}>{ser}</Text>
<Text style={styles.openingText}>{secondLoc}</Text>
</View>
);
}
constructor(props) {
super(props);
this.state = {
query: '',
services:[]
};
}
componentDidMount(){
const {results: services} = service;
this.setState({services});
}
findServices(query) {
const inputValue = query.trim().toLowerCase();
const inputLength = inputValue.length;
const { services } = this.state;
return inputLength === 0 ? [] : services.filter(ser =>ser.toLowerCase().slice(0, inputLength) === inputValue);
}
render() {
const { query } = this.state;
const services = this.findServices(query);
const comp = (a, b) => a.toLowerCase().trim() === b.toLowerCase().trim();
return (
<View style={styles.container}>
<Autocomplete
autoCapitalize="none"
autoCorrect={false}
containerStyle={styles.autocompleteContainer}
data={services.length === 1 && comp(query, services[0].ser) ? [] : services}
defaultValue={query}
onChangeText={text => this.setState({ query: text })}
placeholder="Enter Services here"
renderItem={({ ser, Phone }) => (
<TouchableOpacity onPress={() => this.setState({ query: ser })}>
<Text style={styles.itemText}>
{ser}
</Text>
</TouchableOpacity>
)}
/>
<View style={styles.descriptionContainer}>
{services.length > 0 ? (
Autocomp.renderServices(services[0])
) : (
<Text style={styles.infoText}>
Enter services
</Text>
)}
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#F5FCFF',
flex: 1,
paddingTop: 25
},
autocompleteContainer: {
flex: 1,
left: 0,
position: 'absolute',
right: 0,
top: 0,
zIndex: 1
},
itemText: {
fontSize: 15,
margin: 2
},
descriptionContainer: {
// `backgroundColor` needs to be set otherwise the
// autocomplete input will disappear on text input.
backgroundColor: '#F5FCFF',
marginTop: 25
},
infoText: {
textAlign: 'center'
},
titleText: {
fontSize: 18,
fontWeight: '500',
marginBottom: 10,
marginTop: 10,
textAlign: 'center'
},
directorText: {
color: 'grey',
fontSize: 12,
marginBottom: 10,
textAlign: 'center'
},
openingText: {
textAlign: 'center'
}
});
export default Autocomp;
Below is my services.json file
{
"id":1,
"ser": "Service1",
"Location": "TestLoc1",
"Phone":"(999)-921-9292",
"SecondLoc": "TestLoc",
"email":"accrmail#test.com",
"sourceLat":"33.977806",
"sourceLong":"-117.373261",
"destLatL1":"33.613355",
"destLongL1":"-114.596569",
"destLatL2":"33.761693",
"destLongL2":"-116.971169",
"destAddr1": "Test Drive, 99999",
"destAddr2": "Test City, Test Drive, 92345"
},
{
"id":1,
"ser": "TestService",
"Location": "TestLoc1",
"Phone":"(999)-921-9292",
"SecondLoc": "TestLoc",
"email":"accrmail#test.com",
"sourceLat":"33.977806",
"sourceLong":"-117.373261",
"destLatL1":"33.613355",
"destLongL1":"-114.596569",
"destLatL2":"33.761693",
"destLongL2":"-116.971169",
"destAddr1": "Test Drive, 99999",
"destAddr2": "Test City, Test Drive, 92345"
},
]
any help will be highly appreciated. I checked the function. everything looks correct.
Assuming that your json file is as shown here, there are two problems with your code.
Destructuring is wrong. Since you're directly importing an object from a json file as name services, which has not been assigned to any named constant / variable, therefore it cant be destructured.
Therefore you must change the code as
import services from './services.json';
componentDidMount(){
this.setState({services});
}
You're trying to convert a service object toLowerCase here
ser =>ser.toLowerCase()
which needs to be changed to
services.filter(({ser}) => ser.toLowerCase().slice(0, inputLength) === inputValue);

How to check if a component is mounted in React-Native ES6

I am setting a listener in my application and using force update whenever it is broadcasted but it gives error forceUpdate cant be called on unmounted component. How can I check if a component is mounted now that the isMounted() function is deprecated.
'use strict';
var React = require('react-native');
import ExpAndroid from './ExpAndroid';
var {
AppRegistry,
Image,
ListView,
TouchableHighlight,
StyleSheet,
Text,
View,
Component,
AsyncStorage,
Navigator,
DeviceEventEmitter
} = React;
var rowID;
var img=require('./resource/ic_pause_white.png');
class Example1 extends Component{
constructor(props) {
super(props);
this.state = {
};
}
componentWillMount(){
rowID = this.props.rowIdentity;
console.log("rowID "+rowID);
}
componentDidMount(){
console.log('component mounted')
this.start();
DeviceEventEmitter.addListener('playMusicStatus', (data)=> {
if(data.playMusic==true){
img=require('./resource/ic_pause_white.png');
rowID++;
this.setState(this.state);
ExpAndroid.someMethod1("someurl);
}
});
}
componentWillUnmount(){
console.log('componentwill unmounted')
}
start() {
var url = "some url";
ToastAndroid.prepareToPlay(url,true);
}
render() {
return (
<Image source={require('./resource/album_back.png')} style={styles.background}>
<Image
source={{uri:this.state.trackDetails[rowID].thumnail_loc}}
style={styles.thumbnail}
/>
<View style={styles.flowRow}>
<Text
style={styles.titles}
>text1 + {rowID}: </Text>
<Text
style={styles.titles}
>{this.state.details[rowID].text1}</Text>
</View>
<View style={styles.flowRow}>
<Text
style={styles.titles}
>text2 : </Text>
<Text
style={styles.titles}
>{this.state.details[rowID].text2}</Text>
</View>
<View style={styles.flowRow}>
<Text
style={styles.titles}
>Text3 : </Text>
<Text
style={styles.titles}
>{this.state.Details[rowID].Text3}</Text>
</View>
<View style={styles.flowRow}>
<Text
style={styles.titles}
>Text4 : </Text>
<Text
style={styles.titles}
>{this.state.details[rowID].Text4}</Text>
</View>
</Image>
);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
},
background: {
flex: 1,
width: null,
height: null,
},
flowRow : {
flexDirection :'row',
},
flowRowPlay : {
flexDirection :'row',
alignSelf:'center',
},
backgroundImage: {
flex: 1,
resizeMode: 'cover', // or 'stretch'
},
thumbnail: {
width: 100,
height: 120,
alignSelf:'center',
margin :30
},
controls: {
width: 30,
height: 30,
margin:20
},
titles: {
fontSize: 15,
margin:20,
color: 'white',
},
timings: {
fontSize: 12,
margin:5,
color: 'white',
},
});
module.exports = Example1;
You can handle this yourself in your component:
componentDidMount() {
this._mounted = true;
}
componentWillUnmount() {
this._mounted = false;
}
Then you can check the value of this._mounted in your listener.
Please note that using forceUpdate() should be avoided https://facebook.github.io/react/docs/component-api.html#forceupdate
Normally you should try to avoid all uses of forceUpdate() and only read from this.props and this.state in render(). This makes your component "pure" and your application much simpler and more efficient.
What I did was changing the callback in componentWillMount.
let asyncCallback;
componentDidMount(){
asyncCallback = res=> this.setState({data: res});
asyncTask(asyncCallback);
}
componentWillUnmount(){
asyncCallback = ()=> console.log("AsyncCallback called but component has unmounted");
}
Using ReactUpdateQueue, you can avoid managing your own isMounted state.
const ReactUpdateQueue = require('ReactUpdateQueue');
// Pass the ref to your component.
if (ReactUpdateQueue.isMounted(view)) {
// Your component is mounted!
}