I am trying to build a GPS-Tracker using react-map-gl and want to draw a line with the data retreived from the where-is-iss-API. If the coordinates in the source JSON are initilized staticaly the line is shown.
const [geojson, setGeojson]: any = useState(
{
type: "Feature",
geometry: {
type: "LineString",
coordinates: [
[-77.0323, 38.9131],
[-80.0323, 40.9131]
]
},
properties: {
"name": "Route"
}
});
but when addind data via useEffect it isn't displayed
const [data, setData]: any = useState(dataProp);
const updateLayer = () => {
console.log(data)
if (data.latitude !== undefined && data.longitude !== undefined) {
setGeojson({
...geojson,
geometry: {
coordinates: [
...geojson.geometry.coordinates,
[data.longitude, data.latitude]
]
}
})
}
console.log(geojson);
}
useEffect(() => {
setData(dataProp);
if(data !== undefined && data !== null){
updateLayer();
}
}, [dataProp]);
In this case the line is only displayed for the first two coodinates.
const route: LayerProps = {
id: 'route',
type: 'line',
source: 'geojson',
paint: { 'line-color': 'red', "line-width": 4 }
};
return (
<div>
<ReactMapGL
{...viewport}
mapboxApiAccessToken={token}
mapStyle={"mapbox://styles/gobsej/ckomzwjdg377w18ozdhm1by36"}
width="100vw"
height="100vh"
onViewportChange={(viewport: React.SetStateAction<{ latitude: number; longitude: number; zoom: number; }>) => setViewport(viewport)}
>
<Source id="my-data" type="geojson" data={geojson}>
<Layer {...route} />
</Source>
</ReactMapGL>
</div >
);
The data is retreived with axios and given to the component as a prop
const getGPSLocation = async () => {
await Axios.get('https://api.wheretheiss.at/v1/satellites/25544').then((response) => {
console.log(response.data);
setData(response.data);
}).catch((error) => {
console.log(error);
});
};
useEffect(() => {
getGPSLocation();
const interval = setInterval(getGPSLocation, 1000)
return () => {
clearInterval(interval); }
}, []);
return (
<div>
<Map dataProp={data}></Map>
</div>
);
The console output is the following:
https://i.stack.imgur.com/oZIlb.png
Related
I am using Vue.js 2 and Laravel 7.
I want to pass some errors from the child component to the parent controller. But for some reasons emit did not work.
This is the method of the child component AllocateTask:
methods: {
assignTask: function() {
this.form.task_id = this.user.tasks;
this.form.user_id = this.dev.id;
alert(this.form.task_id);
alert(this.form.user_id);
axios.post('/ticketsapp/public/api/store_task_user', this.form)
.then((response) => {
console.log(response.data);
alert('ok');
this.errors = response.data;
alert(Object.keys(this.errors).length);
if (Object.keys(this.errors).length === 0) {
alert('viva');
} else {
alert('noviva');
this.$emit('failure');
this.$emit('pass-errors', this.errors);
}
})
.catch(error => {
alert('no ok');
console.log(error);
});
}
}
This is the parent component TheReporterTickets:
<template>
<div>
<allocate-task :dev="dev" :tasks="tasks" #pass-errors="onPassErrors" #failure="displayErrors=true" #success="displaySuccess=true"></allocate-task>
<hr>
<validated-errors :errorsForm="errorsTicket" v-if="displayErrors===true"></validated-errors>
</div> </template>
<script>
import AllocateTask from "./AllocateTask.vue"
import ValidatedErrors from "./ValidatedErrors.vue"
export default {
components: {
'allocate-task': AllocateTask,
'validated-errors': ValidatedErrors
},
props: {
dev: {
type: Array,
required: true,
default: () => [],
},
tasks: {
type: Array,
required: true,
default: () => [],
}
},
mounted() {
console.log('Component mounted.');
},
data: function() {
return {
displayErrors: false,
errorsTicket: []
}
},
methods: {
onPassErrors(value) {
alert('error');
console.log('errors passed');
const values = Object.values(value);
this.errorsTicket = values;
console.log(this.errorsTicket);
}
}
} </script>
As you can imagine, I am unable to call the method onPassErrors located in the parent component. I visualize correctly the alert in the else statement of the child component, so I suppose that I am unable to pass the data from the child to the parent component.
Can help?
I have defined the function in my vue js file but it is giving me error for nameWithLang() function Please have a look
My Form
<multiselect v-model="selected" track-by="id" label="name" :options="options" :loading="isLoading" :internal-search="false" #search-change="getData" :multiple="true" :close-on-select="false" :hide-selected="true":internal-search="false" name="books[]" :show-labels="false" :custom-label="nameWithLang"></multiselect>
My vue js file
import AppForm from '../app-components/Form/AppForm';
Vue.component('coupon-form', {
mixins: [AppForm],
data: function() {
return {
form: {
name: '' ,
description: '' ,
valid_from: '' ,
valid_till: '' ,
discount: '' ,
enabled: false,
books: [],
},
isLoading: false,
options: [],
selected: [],
}
},
methods: {
nameWithLang({ name, sku }) {
return `${name} — ${sku}`
},
getData(query){
this.isLoading = true;
axios.post('/admin/books/find/'+query)
.then((response) => {
this.options = response.data;
this.isLoading = false;
})
.catch((error) => {
this.isLoading = false;
});
},
},
watch: {
selected (newValues) {
this.form.books = newValues.map(obj => obj.id)
}
}
});
Other properties and functions are working nameWithLang is not working
It gives me error this
Property or method "nameWithLang" is not defined on the instance but referenced during render.
why not you just return the value into a variable in data, and set the function into mounted/watch instead using the function to get the value.
just for refer, you can make the script like this :
import AppForm from '../app-components/Form/AppForm';
Vue.component('coupon-form', {
mixins: [AppForm],
data: function() {
return {
form: {
name: '' ,
description: '' ,
valid_from: '' ,
valid_till: '' ,
discount: '' ,
enabled: false,
books: [],
},
isLoading: false,
options: [],
selected: [],
newName: '',
}
},
methods: {
nameWithLang({ name, sku }) {
this.newName = `${name} — ${sku}`;
},
getData(query){
this.isLoading = true;
axios.post('/admin/books/find/'+query)
.then((response) => {
this.options = response.data;
this.isLoading = false;
})
.catch((error) => {
this.isLoading = false;
});
},
},
watch: {
selected (newValues) {
this.form.books = newValues.map(obj => obj.id)
this.nameWithLang();
}
}
});
then you can make the template like this:
<multiselect v-model="selected" track-by="id" label="name" :options="options" :loading="isLoading" :internal-search="false" #search-change="getData" :multiple="true" :close-on-select="false" :hide-selected="true":internal-search="false" name="books[]" :show-labels="false" :custom-label="newName"></multiselect>
this is just another way you can make it and the way i'm understand what actually you want to do. you want to pass the name with lang value into the :custom-label right? so why not just defined one more variable and add the value into the variable. so you just need to pass the value instead the function. in v-bind it's more appropiate to pass a property instead of a method
I was trying to update the user profile but the profile picture only changes ones.To change it each time i had to change the image name each time how to solve it.I have tried to send the request in post method but my api does not support post.I will post my code below.Could some one help me and Thanks in advance.
class ProfileEdit extends Component {
state = {
username: '',
email: '',
about: '',
userInfo: '',
avatarSource: null,
showAlert: false,
showCancelButton: false,
showConfirmButton: false,
};
constructor(props) {
super(props);
this.selectPhotoTapped = this.selectPhotoTapped.bind(this);
}
hideAlert = () => {
this.setState({
showAlert: false
});
};
selectPhotoTapped() {
const options = {
quality: 1.0,
maxWidth: 500,
maxHeight: 500,
storageOptions: {
skipBackup: true,
},
};
ImagePicker.showImagePicker(options, response => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled photo picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
} else {
const source = { uri: response.uri }
this.setState({
avatarSource: source,
});
this.upLoadImage(response.uri);
}
});
}
upLoadImage = async (image_uri) => {
const value = await AsyncStorage.getItem('userToken');
//alert(value)
var url = 'http://www.dev.beta.duklr.com:8000/api/v2/profile/';
var b_url = url + value + '/';
let data = new FormData();
data.append('photo', { type: 'image/jpg', uri: image_uri, name: 'profile_image1.jpg' });
data.append('Content-Type', 'image/jpg');
fetch(b_url, {
method: 'PUT',
body: data
}).then((res) => res.json())
.then((res) => {
// alert("response" + JSON.stringify(res));
})
.catch((e) => this.setState({
showAlert: true,
message: e,
showCancelButton: true,
cancelText: 'close',
}))
.done()
}
componentDidMount = async () => {
const value = await AsyncStorage.getItem('userToken');
//alert(value)
var url = 'http://www.dev.beta.duklr.com:8000/api/v2/profile/';
var b_url = url + value + '/';
//alert(value);
return fetch(b_url)
.then(res => res.json())
.then(res => {
this.setState(
{
isLoading: false,
refreshing: false,
userInfo: res,
},
function () { }
);
})
.catch(error => {
this.setState({
showAlert: true,
message: error,
showCancelButton: true,
cancelText: 'close',
})
});
}
onUpdate = async () => {
const value = await AsyncStorage.getItem('userToken');
var url = 'my_api';
var b_url = url + value + '/';
//alert(b_url);
const { email, about, avatarSource } = this.state;
//alert(`${email},${about}`);
fetch(b_url, {
method: 'PUT',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: email,
about_us: about,
}),
})
.then((response) => response.json())
.then((responseJson) => {
this.setState({
showAlert: true,
message: "Saved successfully",
showCancelButton: true,
cancelText: 'close',
})
// this.setState({
// dataSource: responseJson.promptmsg,
// })
})
.catch((error) => {
this.setState({
showAlert: true,
message: error,
showCancelButton: true,
cancelText: 'close',
})
});
}
catch(errors) {
this.setState({
showAlert: true,
message: errors,
showCancelButton: true,
cancelText: 'close',
});
}
render() {
const value_email = this.state.userInfo.email;
const value_about = this.state.userInfo.about_us;
return (
<View style={styles.continer}>
<ScrollView>
<View style={{ alignItems: 'center', padding: 20 }}>
<Avatar
source={this.state.avatarSource}
size="xlarge"
// showEditButton
onPress={this.selectPhotoTapped.bind(this)}
/>
</View>
<View style={styles.textContiner}>
{/* <TextField
label='User Name'
title={this.state.userInfo.name}
value={this.state.username}
onChangeText={(username) => this.setState({ username })}
/> */}
<TextField
label='Email Id'
placeholder={value_email}
//value={value_email}
onChangeText={(email) => this.setState({ email })}
/>
<TextField
label='About'
//value={value_about}
placeholder={value_about}
onChangeText={(about) => this.setState({ about })}
/>
<View style={{ marginTop: 20 }}>
<Button
title="Save"
onPress={this.onUpdate.bind(this)}>
</Button>
</View>
</View>
</ScrollView>
<AwesomeAlert
show={this.state.showAlert}
showProgress={false}
title="Hello There"
message={this.state.message}
closeOnTouchOutside={true}
closeOnHardwareBackPress={true}
showCancelButton={this.state.showCancelButton}
showConfirmButton={this.state.showConfirmButton}
cancelText={this.state.cancelText}
confirmText={this.state.confirmText}
confirmButtonColor="#DD6B55"
onCancelPressed={() => {
this.hideAlert();
}}
onConfirmPressed={() => {
this.hideAlert();
}}
/>
</View>
);
}
}
export default ProfileEdit;
Is Avatar based on React Native's Image? To my experience, the Image component shipped with React Native is very buggy. Indeed, reloading issue is one of them. I often use FastImage as replacement for Image.
I got an vue-warning (which results to as an error on my end coz my code is not working) that says:
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "editmode"
With it, tried the suggestion here but can't make it work. Below is my work:
props:{
editmode:{
type: Boolean,
default: false,
}
},
methods:{
toggleM(){
var editmode = this.editmode;
editmode = !editmode;
this.editmode = editmode;
if(editmode == false){
//dothis
}else{
//dothat
}
},
}
TEMPLATE
<template>
<div class="ui-table-container-body">
<div class="ui-table" v-if="Boolean(items.length) || Boolean(Object.keys(items).length)" v-cloak>
<ui-table-body ref="body" v-model="items"
:editmode="editmode"
>
</ui-table-body>
</div>
</div>
</template>
The line this.editmode = editmode; is the one pointed in my console, is there any way I can surpass this?
You must use a data variable as a gateway to your prop.
In your component, the code code should look like this:
props:{
editmode:{
type: Boolean,
default: false,
}
},
data: {
dataEditMode = false
},
watch: {
'editmode': {
handler: 'onEditmodeChanged',
immediate: true,
},
'dataEditMode': {
handler: 'onDataEditModeChanged'
}
},
methods:{
toggleM(){
var editmode = this.dataEditMode;
editmode = !editmode;
this.dataEditMode = editmode;
if(editmode == false){
//dothis
}else{
//dothat
}
},
onEditmodeChanged (newVal) {
this.dataEditMode = newVal
},
onDataEditModeChanged (newVal) {
this.$emit('editmodeChanged', newVal)
}
}
and the the inclusion of this component in your parent-component should look like this:
<my-component-name :editmode="editmode" #editmodeChanged="(e) => { editmode = e }"></my-component-name>
You shouldn't mutate props from the component itself. See the One Way Data Flow section of the guide. You can use a prop as the initial value, and then keep a value in the data section and mutate that:
props: {
editmode: {
type: Boolean,
default: false,
}
},
data () {
return {
emode: this.editmode,
}
},
methods: {
toggleM () {
let editmode = this.emode;
editmode = !editmode;
this.emode = editmode;
if (editmode == false) {
// dothis
} else {
// dothat
}
},
}
Demo
Vue.component('editbox', {
template: '<div>' +
'<button #click="toggleM">{{ btext }}</button>' +
'<input v-if="emode" />' +
'</div>',
props: ['editmode'],
data () {
return {
emode: this.editmode,
}
},
computed: {
btext () {
return this.emode ? "Text" : "Edit";
}
},
methods:{
toggleM() {
this.emode = !this.emode;
},
}
})
var app = new Vue({
el: '#app',
data: {
mode: true,
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<editbox :editmode="mode" />
</div>
I would send back an event to the parent so it could modify its value:
For example (not tested):
Child Component
props:{
editmode:{
type: Boolean,
default: false,
}
},
methods:{
toggleM(){
var editmode = !this.editmode;
this.$emit('changeEditMode', editmode);
if (editmode == false){
//dothis
} else {
//dothat
}
},
}
Parent
<child-component #changeEditMode="editModeChanged" :editmode="editmode"></child-component>
...
methods:{
editModeChanged(value){
this.editmode = value
},
}
I've recently started to study reactjs and I'm currently experimenting with ajax requests and passing properties from parent to children. I have a react component Competitions which performs an ajax request:
var Competitions = React.createClass({
getInitialState: function() {
return {
compData: [],
}
},
componentDidMount: function() {
axios.get(this.props.source, {
headers: {'X-Auth-Token': '*******************',
'Content-type': 'application/json'}
})
.then(result => {
this.setState({compData: result.data});
})
.catch(error => {
console.log(error);
});
},
render: function() {
return (
<CompTable compData={this.state.compData} />
);
}
});
module.exports = Competitions;
The Competitions component passes the results data to CompTable
var CompTable = React.createClass({
propTypes: {
compData: React.PropTypes.array.isRequired
},
handleClick: function(e) {
var url = 'http://api.football-data.org/v1/competitions/x/teams';
var source = url.replace(url.split('/')[5], e);
console.log(source);
},
render: function() {
var list = this.props.compData.map(function (comp, i) {
return (
<tr key={i+1}>
<th scope="row">{i+1}</th>
<td className={comp.id} onClick={this.handleClick.bind(this, comp.id)} >{comp.caption}</td>
</tr>
);
}, this);
return (
<tbody>{list}</tbody>
)
}
});
module.exports = CompTable;
This is the Teams component
var Teams = React.createClass({
getInitialState: function() {
return {
teamData: [],
}
},
componentDidMount: function() {
axios.get(this.props.source, {
headers: {'X-Auth-Token': '*******************',
'Content-type': 'application/json'}
})
.then(result => {
this.setState({teamData: result.teams.data});
})
.catch(error => {
console.log(error);
});
},
render: function() {
return (
<TeamsTable teamData={this.state.teamData} />,
);
}
});
module.exports = Teams;
What I'm trying to do is take on click the compData.id property of the CompTable component with a handleClick function and use it as a source property on another component named Teams (identical with the Competitions component) that uses the given property as a source url in order to perform a new ajax request. Is there a way to do that? Thank you
I think I found a solution to my problem.
So, Competitions is the Parent and CompTable and Teams are the children. I don't know if there is a simpler way, but this one seems to work. It's not perfect, I have other problems to solve, but I managed to make a second ajax call inside a child component using my first ajax call inside the parent component, by grabbing the compData.id property and passing it to the children, on click. Any comments are welcome.
Competitions component
var Competitions = React.createClass({
getInitialState: function() {
return {
compData: [],
id: "",
}
},
componentDidMount: function() {
axios.get(this.props.source, {
headers: {'X-Auth-Token': '********************',
'Content-type': 'application/json'}
})
.then(result => {
this.setState({compData: result.data});
})
.catch(error => {
console.log(error);
});
},
changeId: function (newId) {
this.setState({
id: newId
});
},
render: function() {
return (
<CompTable compData={this.state.compData} id={this.state.id} onClick= {this.changeId} />
);
}
});
module.exports = Competitions;
CompTable component
var CompTable = React.createClass({
propTypes: {
compData: React.PropTypes.array.isRequired
},
getInitialState: function() {
return {
showTeams: false,
hide: false,
};
},
teamsClick: function() {
this.setState({
showTeams: true,
hide: true,
});
},
handleClick: function(e) {
this.props.onClick(e);
},
render: function() {
var list = this.props.compData.map(function (comp, i) {
return (
<tr key={i+1}>
<th scope="row">{i+1}</th>
<td className={comp.id} onClick={function() { this.teamsClick(); this.handleClick(comp.id); }.bind(this)}> {comp.caption} </td>
<td>{comp.league}</td>
<td>{comp.numberOfTeams}</td>
</tr>
);
}, this);
return (
<div > { this.state.showTeams ? <Teams id={this.props.id}/> : null } </div>
<tbody>{list}</tbody>
)
}
});
module.exports = CompTable;
Teams component
var Teams = React.createClass({
getInitialState: function() {
return {
teamData: [],
}
},
componentDidMount: function() {
var url = 'http://api.football-data.org/v1/competitions/x/teams';
var source = url.replace(url.split('/')[5], this.props.id);
axios.get(source, {
headers: {'X-Auth-Token': '********************',
'Content-type': 'application/json'}
})
.then(result => {
this.setState({teamData: result.data.teams});
})
.catch(error => {
console.log(error);
});
},
render: function() {
return (
<TeamsTable teamData={this.state.teamData}/>
);
}
});
module.exports = Teams;