I am trying to create a simple connection to my MongoDB database collection for my Stitch App. In the componentDidMount() method I initialize the default app client and store it in a variable of the component. But when I try to set the MongoDB remote after, it doesn't work, I get the
TypeError: this.client.getServiceClient is not a function. (In 'this.client.getServiceClient(MongoDB.RemoteMongoClient.factory, "mongodb-atlas")', 'this.client.getServiceClient' is undefined)
I have read all React Native docs such as this or this and see the structure isn't the same but I don't want the user to log in on the app (why I used the AnonymousCredential()) and even if I were to use this structure, I wouldn't know what to do once the user is logged in, how to get the data? Since there is no Remote Client defined, therefore no db and no collection.
Here is my component:
import React from "react";
import { StyleSheet, View, TextInput, Button, FlatList } from "react-native";
import PlayerItem from "./PlayerItem";
import { Stitch, AnonymousCredential } from "mongodb-stitch-react-native-sdk";
const MongoDB = require("mongodb-stitch-react-native-services-mongodb-remote");
export default class Search extends React.Component {
constructor(props) {
super(props);
this.state = {
players: [],
};
this.query = "";
}
componentDidMount() {
this.client = Stitch.initializeDefaultAppClient("kungfuzone-rzksu");
const mongodb = this.client.getServiceClient(
MongoDB.RemoteMongoClient.factory,
"mongodb-atlas"
);
this.db = mongodb.db("players");
this._displayPlayersOnLoad();
}
_displayPlayersOnLoad() {
this.client.auth
.loginWithCredential(new AnonymousCredential())
.then(this._displayPlayers)
.catch(console.error);
}
_displayPlayers() {
this.db
.collection("kungfuzone")
.find({}, { limit: 1000 })
.asArray()
.then((players) => {
this.setState({ players: players });
});
}
_updateQuery(text) {
this.query = text;
}
_searchPlayers(query) {
if (query.length > 0) {
this.stitchClient.auth
.loginWithCredential(new AnonymousCredential())
.then(() => this.setState({ players: db.find({ name: query }).asArray() }))
.catch(console.error);
}
}
render() {
return (
<View style={styles.container}>
<TextInput
style={styles.textinput}
onChangeText={(input) => this._updateQuery(input)}
placeholder="Player's name"
/>
<Button title="Search" onPress={() => this._searchPlayers(this.query)} />
<FlatList
data={this.state.players}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) => <PlayerItem player={item} />}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 20,
},
textinput: {
marginLeft: 5,
marginRight: 5,
height: 50,
borderColor: "#000000",
borderWidth: 1,
paddingLeft: 5,
},
});
Can anyone help? Thank you :)
Actually it's not a good idea to make a connection directly to a remote database from your mobile application. How about to use the atlas API or create an API to communicate with MongoDB?
Related
I have a custom filter values such as:
filterParams: {
values: ['Admin', 'Proje Yƶneticisi', 'Muhasebe'],
defaultToNothingSelected: true,
suppressSelectAll: true
},
However, I can choose multiple values like this. But I don't want to do that, I want to choose only one value instead of multiple choices.
Is there a way to convert this checkbox filter into a radio filter?
Thanks.
You can make a custom filter and there is a video on it: https://www.youtube.com/watch?v=yO3_nTyDv6o
Create a component like this, i am dynamically looking up the options to be displayed based on the extra column parameters supplied in the column def (e.g. thats where props.meta comes in)
import { Button, Radio, RadioGroup, Stack } from "#chakra-ui/react";
import { IFilterParams } from "ag-grid-community";
import React from "react";
import { IRegistryDataColumn } from "../../../../models/RegistryDataColumn";
interface IProps extends IFilterParams {
meta?: IRegistryDataColumn;
}
interface IOption {
value: string;
label: string;
}
export const FilterRadio = React.forwardRef((props: IProps, ref) => {
const [radioOptions, setRadioOptions] = React.useState<IOption[]>([]);
const [filterState, setFilterState] = React.useState<string>();
const handleClear = () => {
setFilterState(undefined);
};
// expose AG Grid Filter Lifecycle callbacks
React.useImperativeHandle(ref, () => {
return {
isFilterActive() {
return filterState !== undefined;
},
doesFilterPass(params) {
const isPass =
params.data[props.colDef.field as string] === filterState;
return isPass;
},
getModel() {},
setModel() {},
};
});
React.useEffect(() => {
props.filterChangedCallback();
}, [filterState]);
React.useEffect(() => {
const radioOptionsUpdate: IOption[] = [];
if (props.meta?.radio_options) {
Object.entries(props.meta.radio_options).forEach(([key, value]) => {
radioOptionsUpdate.push({ value: value.value, label: value.label });
});
}
setRadioOptions(radioOptionsUpdate);
}, [props.meta?.radio_options]);
return (
<Stack p={4} spacing={6} style={{ display: "inline-block" }}>
<Button size="sm" onClick={handleClear}>
Clear filter
</Button>
<RadioGroup onChange={setFilterState} value={filterState}>
<Stack spacing={4}>
{radioOptions.map((option) => (
<Radio key={option.value} value={option.value}>
{option.label}
</Radio>
))}
</Stack>
</RadioGroup>
</Stack>
);
});
And then include it in the column definition:
newCol.filter = FilterRadio;
I have a simple Android login system and a mongoDB & Express coupled with it. The front end has some input fields, with which i have implemented redux to access the variable in all pages of the system. Im having trouble posting user information from the front end fields to the database through the backend that i have.
I need to know eaxactly how to post that data from my frontend to the mongoose database that i have. Below is my code.
The form
import React, { Component } from 'react';
import { StyleSheet, View, TextInput, Text, StatusBar, TouchableOpacity } from 'react-native';
import { Field, reduxForm } from 'redux-form';
import InputText from './InputText';
import { connect } from 'react-redux';
import {bindActionCreators} from 'redux';
import {updatePlates, updateNumber} from '../actions/user';
const styles =StyleSheet.create({
container : {
padding:-10,
flex: 1,
alignItems: 'center',
justifyContent:'center'
},
textDesign:{
fontFamily: 'sans-serif-condensed',
width: 300,
elevation: 10,
padding: 10,
backgroundColor: '#ffffff',
borderRadius: 20,
marginVertical: 20,
fontSize: 15,
}
});
class Form extends Component{
//<Text style={styles.txt}>Home: {this.props.user.email}</Text>
render(){
return(
<View style={styles.container}>
<TextInput placeholder="Car Registration Plates"
style={styles.textDesign}
placeholderTextColor = '#878080'
value={this.props.user.plates}
onChangeText={input => this.props.updatePlates(input)}
// underlineColorAndroid='rgba(255, 0, 0, 0.8)'
/>
<TextInput placeholder="Mobile Number"
style={styles.textDesign}
placeholderTextColor = "#878080"
value={this.props.user.number}
onChangeText={input => this.props.updateNumber(input)}
/>
</View>
);
}
}
const mapDispatchToProps = (dispatch)=>{
return bindActionCreators({updatePlates, updateNumber},dispatch)
}
const mapStateToProps = (state)=>{
return {
user: state.user
}
}
export default connect(mapStateToProps,mapDispatchToProps )(Form)
The post method
router.post('/create', (req, res) => {
console.log(req.body);
const userData= {
phone: String( req.body.phone).replace(/[^\d]/g, ''),
car: req.body.contact_number
}
const user= new User(userData);
user.save().then((user) =>{
if(user){
return user.generateAuthToken();
} else{
res.sendStatus(400);
}
}).then((token) =>{
res.header({'x-auth': token}).send(user)
}).catch((error) =>{
res.status(400).send(error);
});
});
As per your problem you want to have a side effect in your action. So you need to use a middleware in your application either redux thunk middle ware or redux saga.
Create an action for the submission of data from your component. From this action call the side effect function and update the state to let the component that action is success or not.
Action creator
function postData(dispatch, data) { // needs to dispatch, so it is first argument
return dispatch=> fetch("api/postdata",
{
body: data,
method: "post"
})
.then(res => res.json())
.then(
data => dispatch({ type: 'POST_DATA_SUCCESS', data }),
err => dispatch({ type: 'POST_DATA_FAILURE', err })
);
}
in your component on submission
postData(this.props.dispatch, data); // don't forget to pass dispatch
so I have this code for posting to my backend API. Normal form perfectly fine; I managed to post to my database. So I add a Cascader from Ant Design CSS Framework, and every time I selected the value, it produced an error
TypeError: Cannot read property 'value' of undefined
Here is the code:
import React from 'react';
import axios from 'axios';
import { Button, Cascader, Form, Input, Modal } from 'antd';
const FormProduct = Form.Item;
const computerType = [
{
value: 'computer',
label: 'Computer',
},
{
value: 'laptop',
label: 'Laptop',
}
]
export default class FormInventory extends React.Component {
state = {
category: '',
productname: '',
};
handleCategoryChange = event => { this.setState({ category: event.target.value }) }
handleProductNameChange = event => { this.setState({ productname: event.target.value }) }
handleSubmit = event => {
event.preventDefault();
axios.post('myapi',
{
category: this.state.category,
productname: this.state.productname,
})
.then(
function success() {
const modal = Modal.success({
title: 'Success',
content: 'Data successfully add',
});
setTimeout(() => modal.destroy(), 2000);
}
)
}
render() {
return (
<Form onSubmit={this.handleSubmit}>
<FormProduct {...formProductLayout} label="Computer Category">
<Cascader options={computerType} category={this.state.value} onChange={this.handleCategoryChange} />
</FormProduct>
<FormProduct {...formProductLayout} label="Product Name">
<Input type="text" productname={this.state.productname} onChange={this.handleProductNameChange} />
</FormProduct>
<FormProduct wrapperCol={{ span: 12, offset: 2 }}>
<Button type="primary" htmlType="submit">
Add Item
</Button>
</FormProduct>
</Form>
)
}
}
You need to either bind your event handlers in the constructor or use arrow function.
Option 1: Bind
constructor(props) {
// This binding is necessary to make `this` work in the callback
this.handleClick = this.handleClick.bind(this);
}
Option 2: Arrow function
<Input onChange={(e) => this.handleChange(e)} />
According to antd docs you don't need event.target.
https://ant.design/components/cascader/
handleCategoryChange = category => { this.setState({ category }) }
The code above will work fine.
I'm currently following Facebook's React Native Tutorial and I'm having trouble fetching a json object from https://facebook.github.io/react-native/movies.json and displaying it in a FlatList. Here is my code:
import React, { Component } from 'react';
import {FlatList, ActivityIndicator, ListView, View } from 'react-native';
import { Card, CardItem, Text, Container, Header, Title, Content, Footer, FooterTab, Button, Left, Right, Body, Icon } from 'native-base';
class JobPost extends Component {
render(){
return(
<Card>
<CardItem header>
<Text>{this.props.header}</Text>
</CardItem>
<CardItem>
<Body>
<Text>
{this.props.body}
</Text>
</Body>
</CardItem>
</Card>
)
}
}
export default class Movies extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
dataSource: ''
}
}
componentDidMount() {
return fetch('https://facebook.github.io/react-native/movies.json')
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
isLoading: false,
dataSource: responseJson,
});
})
.catch((error) => {
console.error(error);
});
}
render() {
if (this.state.isLoading) {
return (
<View style={{flex: 1, paddingTop: 20}}>
<ActivityIndicator />
</View>
);
}
return (
<View style={{flex: 1, paddingTop: 20}}>
<FlatList
data={this.state.dataSource}
renderItem={({item}) => <Card header={item.title} body={item.releaseYear}/>}
keyExtractor={item => item.title}
/>
</View>
);
}
}
The console log to print out the json object works correctly. However, I just get a blank screen when I run it in the IOS Simulator.
The issue was it wasn't retrieving an array from the fetch, so I was supposed to specify dataSource: responseJson.movies
That did the trick.
Flat list will not update date if you don't set extraData.
You should use extraData for Flat list if want to update data (`extraData={this.state} ): https://facebook.github.io/react-native/docs/0.48/flatlist.html#extradata
new to Meteor and running into this issue. I am using Meteor 1.3.3
When I try to pass props from my parent Container to my React Component it keeps throwing an error I will post below.
Here is my React component Prospect.jsx:
import React from 'react'
import { createContainer } from 'meteor/react-meteor-data'
import { Residents } from '/collections/residents.jsx'
import ReactDOM from 'react-dom';
import RaisedButton from 'material-ui/RaisedButton';
// import '/collections/residents.jsx'
class Prospect extends React.Component {
render() {
return(
<div>
<h1>Prospect Resident - {this.props.prospect.name.first} </h1>
<RaisedButton label="Default" />
</div>
)
}
}
Prospect.propTypes = {
// prospect: React.PropTypes.object
}
export default createContainer((params) => {
const paramsId = params.params.prospectId
Meteor.subscribe('residents');
// Meteor.subscribe('resident');
prospect = Residents.find({_id: paramsId}).fetch()
console.log(prospect[0])
return {
prospect: prospect
}
}, Prospect)
and here is my Mongo collection
residents.jsx
import { Mongo } from 'meteor/mongo'
export const Residents = new Mongo.Collection('residents')
const nameSchema = new SimpleSchema({
first: {type: String},
last: {type: String}
})
const residentSchema = new SimpleSchema({
cId: { type: String },
name: { type: nameSchema },
status: { type: String },
})
Residents.attachSchema(residentSchema)
// METHODS
Meteor.methods({
'residents.insert'(resident) {
Residents.insert(resident)
}
})
// PUBLICATIONS
if(Meteor.isServer) {
Meteor.publish('residents', function() {
return Residents.find()
})
Meteor.publish('resident', function(id) {
return Residents.find({_id: id})
})
}
and here is my Route
FlowRouter.route('/prospects/:prospectId}', {
name: 'prospectShow',
action(params) {
mount(LoggedIn, { content:
<MuiThemeProvider muiTheme={getMuiTheme()}>
<Prospect params={{prospectId: params.prospectId}} />
</MuiThemeProvider>
})
}
So when I go to localhost:3000 route I get the error
Prospect.jsx:14Uncaught TypeError: Cannot read property 'name' of undefined
Exception from Tracker recompute function:
debug.js:41 TypeError: Cannot read property '_currentElement' of null
at ReactCompositeComponentWrapper._updateRenderedComponent (ReactCompositeComponent.js:772)
at ReactCompositeComponentWrapper._performComponentUpdate (ReactCompositeComponent.js:753)
at ReactCompositeComponentWrapper.updateComponent (ReactCompositeComponent.js:672)
at ReactCompositeComponentWrapper.receiveComponent (ReactCompositeComponent.js:571)
at Object.receiveComponent (ReactReconciler.js:127)
at ReactCompositeComponentWrapper._updateRenderedComponent (ReactCompositeComponent.js:775)
at ReactCompositeComponentWrapper._performComponentUpdate (ReactCompositeComponent.js:753)
at ReactCompositeComponentWrapper.updateComponent (ReactCompositeComponent.js:672)
at ReactCompositeComponentWrapper.performUpdateIfNecessary (ReactCompositeComponent.js:585)
at Object.performUpdateIfNecessary (ReactReconciler.js:160)
My console.log(prospect[0]) in the container returns the object just fine, and it also works if I pass it in like this
return {
prospect: {name: {first: 'Joe', last: 'Smith'}}
}
So it's something about the returned object I think. Any help would be greatly appreciated, thanks
I ended up going with a solution like this. If anyone wants to answer and explain why this is needed (I thought in meteor 1.3 this wasn't needed anymore) I will accept your answer.
import React from 'react'
import { createContainer } from 'meteor/react-meteor-data'
import { Residents } from '/collections/residents.jsx'
class Prospect extends React.Component {
render() {
if(!this.props.ready){return <span>Loading...</span>}
const { prospect } = this.props
return(
<div>
<h1>{prospect.name.first} {prospect.name.last}</h1>
<div>Company: <b>{prospect.cId}</b></div>
</div>
)
}
}
Prospect.propTypes = {
ready: React.PropTypes.bool.isRequired,
prospect: React.PropTypes.object.isRequired
}
export default createContainer((params) => {
return {
ready: Meteor.subscribe('resident', params.id).ready(),
prospect: Residents.findOne(params.id)
}
}, Prospect)