I am using Ionic react I have below tabs on the bottom of my app and want to navigate from job and messages to different components associated with tabs on the click of tabs. But the issue is Page do not render on the click of tabs but if I refresh my page then navigation works fine. I don't know what I am missing here.
render() {
const { _token } = this.state;
let isJobActive = Global.myJobActive();
let isMessageActive = Global.messageActive();
let isMoreActive = Global.moreActive();
let isAddJobActive = Global.addJobActive();
return (
<IonReactRouter>
<IonPage>
<Route exact path="/" render={() => <Redirect to="/home" />} />
<IonTabs>
<IonRouterOutlet>
{/* message */}
<Route
path="/messages"
component={WithRouterPath(MessagesHome)}
exact={true}
/>
{/* jobs */}
<Route
path="/add-job"
component={WithRouterPath(PostJob)}
exact={true}
/>
<Route
path="/my-jobs"
component={WithRouterPath(MyJobs)}
exact={true}
/>
<Route
path="/more-option"
component={WithRouterPath(MoreOptions)}
exact={true}
/>
</IonRouterOutlet>
{/* <div className="footer_menu"> */}
<IonTabBar slot="bottom">
<IonTabButton
tab="addjob"
href="/add-job"
onClick={() => {
this.setState({
isJobActive: 0,
isMessageActive: 0,
isMoreActive: 0,
isAddJobActive: 1
});
}}
>
<AddJob isActive={isAddJobActive} />
<IonLabel>Add Job</IonLabel>
</IonTabButton>
<IonTabButton
tab="myjobs"
href="/my-jobs"
onClick={() => {
this.setState({
isJobActive: 0,
isMessageActive: 0,
isMoreActive: 0,
isAddJobActive: 1
});
}}
>
<MyJob isActive={isJobActive} />
<IonLabel>My Jobs</IonLabel>
</IonTabButton>
<IonTabButton
tab="messages"
href="/messages"
onClick={() => {
this.setState({
isJobActive: 0,
isMessageActive: 1,
isMoreActive: 0,
isAddJobActive: 0
});
}}
>
<Message isActive={isMessageActive} />
<IonLabel>My Messages</IonLabel>
</IonTabButton>
<IonTabButton
tab="more-option"
href="/more-option"
onClick={() => {
this.setState({
isJobActive: 0,
isMessageActive: 0,
isMoreActive: 1,
isAddJobActive: 0
});
}}
>
<More isActive={isMoreActive} />
<IonLabel>More</IonLabel>
</IonTabButton>
</IonTabBar>
{/* </div> */}
</IonTabs>
</IonPage>
</IonReactRouter>
);
}
So this is my code when I click any tab it redirects to that URL but didn't render the component.
This all happened after I update ionic version
In my package.json
"#ionic/react": "^4.11.4",
"#ionic/react-router": "^4.11.4",
"react-router": "^5.1.2",
"react-router-dom": "^5.1.2",
and my WithRouterPath component is like below
const WithRouterPath = (WrappedComponent, options = {}) => {
const HOC = class extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
Global.isFooterVisible();
}
componentDidUpdate(prevProps) {
Global.isFooterVisible();
}
render() {
return <WrappedComponent {...this.props} />;
}
};
return HOC;
};
export default WithRouterPath;
I had this issue. I am new to Ionic and React, so I don't really know if this issue is the same as mine, but I will let you know what I found. In my app I had a router setup in the app file that redirected /tabs to a page called mainTabs. The Tabs were actually setup in that mainTabs page. The problem was that in the router settings for redirecting traffic to the tabs page I had "exact={true}" set. This doesn't allow you to pass /tab/* as possibilities. When I took "exact={true}" off the route going to my tabs it fixed it.
Related
I'm a totally newbie with React and React-Admin. IMHO, I'm trying to achieve something simple that many people must have already done but I cannot find any kind of tutorial anywhere.
I'd like to add another button to the list of action buttons (show/edit) within each row in a <List> component. This button would archive the record.
My last try looks like the code below.
import React from 'react';
import {
Datagrid,
EmailField,
List,
TextField,
ShowButton,
EditButton,
DeleteButton,
CloneButton,
} from 'react-admin';
import { makeStyles } from '#material-ui/core/styles';
import ArchiveIcon from '#material-ui/icons/Archive';
const useRowActionToolbarStyles = makeStyles({
toolbar: {
alignItems: 'center',
float: 'right',
width: '160px',
marginTop: -1,
marginBottom: -1,
},
icon_action_button: {
minWidth: '40px;'
},
});
const ArchiveButton = props => {
const transform = data => ({
...data,
archived: true
});
return <CloneButton {...props} transform={transform} />;
}
const RowActionToolbar = (props) => {
const classes = useRowActionToolbarStyles();
return (
<div className={classes.toolbar}>
<ShowButton label="" basePath={props.basePath} record={props.record} className={classes.icon_action_button}/>
<EditButton label="" basePath={props.basePath} record={props.record} className={classes.icon_action_button}/>
<ArchiveButton {...props} basePath={props.basePath} label="" icon={<ArchiveIcon/>} record={props.record} className={classes.icon_action_button} />
<DeleteButton basePath={props.basePath} label="" record={props.record} className={classes.icon_action_button}/>
</div>
);
};
export const UserList = props => {
return (
<List
{...props}
sort={{ field: 'first_name', order: 'ASC' }}
>
<Datagrid>
<TextField source="first_name"/>
<TextField source="last_name"/>
<EmailField source="email"/>
<RowActionToolbar/>
</Datagrid>
</List>
)
};
Obviously, this code does not work because the <CloneButton> component get rid of the id the record. Moreover, except if I did something wrong - which is totally possible -, it makes a GET request to a create endpoint.
I'm using different routes in my dataProvider (The back end is using Django and Django rest framework). I want to send a PATCH to the detail endpoint, like the <Edit> component does.
I also tried with a <SaveButton>, but it fails too.
Uncaught TypeError: Cannot read property 'save' of undefined
at useSaveContext (SaveContext.js:23)
I guess the <SaveButton> must be within a <SimpleForm>?
I'd like the save behaviour of the <DeleteButton>, i.e. update the record from the list, display the notification that the record has been archived (with the Undo link), send the request to the back end, refresh the list.
Any guidance, directions would be very appreciated.
I don't know that this is a full answer, but felt like more than a comment...
You are trying to archive the existing record, not create a whole new record, right? CloneButton is supposed to be used to create a new record with a new ID (which is why your ID is going away), so you don't want to us it here. note that I've never used CloneButton. it is not fully documented so I could be wrong about its use.
I am thinking that you should use the useRecordContext hook within your Archive button to pull in all of the record's data, including the id; read this little section: https://marmelab.com/react-admin/Architecture.html#context-pull-dont-push
And I don't think transform is what you're looking for here. You will need to use one of the dataProvider hooks, i'm assuming useUpdate: https://marmelab.com/react-admin/Actions.html#useupdate
//first create component
const MyButton = (props: any) => {
const [sendEmailLoading, setSendEmailLoading] =
React.useState<boolean>(false);
const record = useRecordContext(props);
const sendEmail = (id: Identifier) => {
setSendEmailLoading(true)
dataProvider.sendEmail(
"notifications", { id: id })
.then(({ data }: any) => {
if (data && data.status == "success")
notify('Email send success', { type: 'success' });
setSendEmailLoading(false);
refresh();
});
};
return (
<ButtonMUI color='primary' size="small" onClick={() => {
sendEmail(record.id) }}>
{
!record.publish &&(
!sendEmailLoading ? (
translate('resources.notifications.buttons.send')
) : (
<CircularProgress size={25} thickness={2} />
)
)
}
</ButtonMUI>
)
}
//and second add to datagrid list
<Datagrid>
<NumberField source="id" />
<TextFieldRA source="subject" />
<DateField source="date" />
<BooleanField source="publish" />
{/* <EditButton /> */}
<ShowButton />
<MyButton />
</Datagrid>
I'm using react-native-phone-number-input and i want to delete the call code from the number if the user types it.
my solution is :
class PhoneUserInput extends PureComponent {
...
<PhoneInput
ref={this.myRef}
onChangeFormattedText={(value) => {
if (value.substr(`+${this.myRef.current?.getCallingCode()}`.length)
.startsWith(`+${this.myRef.current?.getCallingCode()}`)) {
value = value.substr(`+${this.myRef.current?.getCallingCode()}`.length)
.replace(`+${this.myRef.current?.getCallingCode()}`, ''));
}
onChangeFormattedText(value);
console.log('formated value'+value);
}
}}
/>
}
I tried to the same thing on onChangeText props but it's doesn't give the effect instantly on the component.
Please try to do your work with
onChangeText={ (_text)=>{ //Your code} }
AND add :
value={value}
Here is a working example :
<PhoneInput
ref={phoneInput}
defaultValue={value}
value={value}
defaultCode="FR"
layout="first"
placeholder={label}
containerStyle={styles.phoneContainer}
onChangeText={(text) => {
setValue(text)
}}
onChangeFormattedText={(text) => {
setFormattedValue(text)
}}
withDarkTheme
withShadow
/>
I'm building a react-native application that displays Service overlay (like those facebook messenger bubble heads), implement in Android only, and on the overlay click it should go back to the app in a specific screen.
I'm using react-router-native and I have my routes structured like this:
App.js
<NativeRouter>
<ApolloProvider client={client}>
<Main>
<Switch>
<Route exact path="/home" component={Home} />
<Route exact path="/progress" component={RouteProgress} />
<Route exact path="/search" component={Search} />
</Switch>
</Main>
</ApolloProvider>
</NativeRouter>
The Main component has these:
Main.js
componentDidMount() {
console.log(this.props.location.pathname);
if(this.props.location.pathname === '/') {
this.props.history.push("/home");
}
}
The callback from my Native module is being called like this:
FloatingView.java
case MotionEvent.ACTION_UP:
if (lastAction == MotionEvent.ACTION_DOWN || delta < 3) {
Intent intent = new Intent(FloatingWindow.this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
FloatingViewPackage.callback.invoke();
stopSelf();
}
The callback is defined in the component Search, which also executes the native module:
Search.js
<Button onPress={() => FloatingView.init(() => {
console.log('go to progress 1');
this.props.history.push("/progress");
setTimeout(() => {
console.log('go to progress 2');
this.props.history.push("/progress");
}, 1000);
})}
The problem is that this.props.history.push("/progress"); doesn't work neither outside the timeout nor inside.
Outside the timeout, the function is called before Main componentDidMount but location.pathname is not updated. Inside it the function is called after, but it doesn't navigate to the right screen. It always fall into /home.
I thought this my be a life cycle issue, since the Search component is not mounted. I've been trying to figure a way out to make this work. I tried using the Redirect component:
<Button onPress={() => FloatingView.init(() => <Redirect to="/progress" />)}
Does anyway can think of a way around this? Thanks
Found a solution, don't know if the best one, but it works.
Created a singleton navigation.js
navigation.js
export default {
entryPoint: '/home'
};
And changed the following files:
Search.js
<Button onPress={() => FloatingView.init(() => {
navigation.entryPoint = "/progress";
})}
Main.js
componentDidMount() {
if(this.props.location.pathname === '/') {
this.props.history.push(navigation.entryPoint);
}
}
I want to use external web page in my React Native App . I have button on my app and want to open external web page onPress button in my app not on browser.
I have tried WEBVIEW but not helped me.
now I have Tried this :
<HTMLView
value={this.props.html}
onLinkPress={(url) => alert('clicked link: ', url)}
/>
how can i do this ?
I have tried this and its working for me.
install react-native-custom-tabs using this command
npm install react-native-custom-tabs --save
and than link custom tabs package using
react-native link react-native-custom-tabs
and than call it
import {CustomTabs,ANIMATIONS_SLIDE,ANIMATIONS_FADE} from 'react-native-custom-tabs';
openCustomizedCustomTabs() {
this.openGoogle({
toolbarColor: '#607D8B',
enableUrlBarHiding: true,
showPageTitle: true,
enableDefaultShare: true,
animations: ANIMATIONS_SLIDE
});
}
errorOccur() {
this.openGoogle({
//toolbarColor: '607D8B', // <--- Invalid toolbar color.
enableUrlBarHiding: '#607D8B', // <-- Type Error.
})
}
openGoogle(option) {
CustomTabs.openURL('https://www.google.com', option).then((launched: boolean) => {
console.log(`Launched custom tabs: ${launched}`);
}).catch(err => {
console.error(err)
});
}
render(){
return <Button marginTop={10} onPress={() => this.openCustomizedCustomTabs()}>
Custom Tab
</Button>
}
and run app.
function renderNode(node, index, siblings, parent, defaultRenderer) {
if (node.name == 'iframe') {
const a = node.attribs;
const iframeHtml = `<iframe src="${a.src}"></iframe>`;
return (
<View key={index} style={{width: Number(a.width), height: Number(a.height)}}>
<WebView source={{html: iframeHtml}} />
</View>
);
}
}
class Page extends React.Component {
render() {
const htmlContent = `
<div>
<iframe src={this.props.utl} width="360" height="300" />
</div>
return (
<HTMLView value={htmlContent} renderNode={renderNode} />
);
}
}
then use it like:
<Page url="the url here..." />
React Native WebView Component has been Added in new Release to Documentation .
https://facebook.github.io/react-native/docs/webview.html
import React, { Component } from 'react';
import { WebView } from 'react-native';
class MyWeb extends Component {
render() {
return (
<WebView
source={{uri: 'https://github.com/facebook/react-native'}}
style={{marginTop: 20}}
/>
);
}
}
I have a component that renders out a list of buttons, lets call this 'ButtonList'. When one of the buttons is clicked, the event is bubbled up like so:
<ButtonList onButtonPressed={(mins) => { console.log(mins); }} />
In response to this, I want to hide that ButtonList and show another component that is currently hidden. The ButtonList has some state such as "state { visible: true }" that I want to toggle that stops it rendering. How do I make a call to toggle the state of that ButtonList and then also call my other component in this view to also toggle its visible state to show?
Thanks.
swappingComponentsExample = () => {
return (
<View>
{this.state.showButtonList ? (
<ButtonList
onButtonPressed={mins => {
this.setState({showButtonList: false});
console.log(mins);
}}
/>
) : (
<OtherComponent />
)}
</View>
);
};
// Renders both components but passes style override to hide the object
// ButtonList/OtherComponent are not destroyed and recreated using this method
hidingExample = () => {
return (
<View>
<ButtonList
onButtonPressed={mins => {
this.setState({showButtonList: false});
console.log(mins);
}}
style={!this.state.showButtonList && {display: 'none'}}
/>
<OtherComponent
style={this.state.showButtonList && {display: 'none'}}
/>
</View>
);
};