FireBase dispatch function doesn't save to realtime DB - javascript

I need some help with a realtimeDB issue.Am using NuxtJS to store state and dispatch the state to DB.
My code is working fine regarding saving into to the DB. Whenever I want to edit it, I receive this 400 BAD Request error.
The same thing happens when i manually try to update info withing the Firebase realtime DB, I can't edit the line with the text.
ERROR:
vendor.js:387 PUT https://xxxx.firebaseio.com/posts.json-MI-Jym0mdX5jNNP89UH.json?auth=BIGKEY 400 (Bad Request)
My component
<template>
<div class="admin-post-page">
<section class="update-form">
<AdminPostForm :post="loadedPost" #submit="onSubmitted" />
</section>
</div>
</template>
<script>
import AdminPostForm from "#/components/Admin/AdminPostForm";
export default {
layout: "admin",
middleware: ['check-auth', 'auth'],
components: {
AdminPostForm
},
asyncData(context) {
return context.app.$axios
.$get(
process.env.baseUrl + "/posts/" +
context.params.postId +
".json"
)
.then(data => {
return {
loadedPost: { ...data, id: context.params.postId }
};
})
.catch(e => context.error());
},
methods: {
onSubmitted(editedPost) {
this.$store.dispatch("editPost", editedPost).then(() => {
this.$router.push("/admin");
});
}
}
};
</script>
The method from store is:
editPost(vuexContext, editedPost) {
return this.$axios
.$put(
"https://XXXX.com/posts.json" +
editedPost.id +
".json?auth=" +
vuexContext.state.token,
editedPost
)
.then(res => {
vuexContext.commit("editPost", editedPost);
})
.catch(e => console.log(e));
}
And my rules are:
{
"rules": {
".read": true,
".write": true
}
}
If you can help me with info regarding why I am not allowed, would owe you a lot!
Thank you!

Your URL contains two .json extensions, which won't work. You should only add .json after the full path of the JSON you are trying to write/update:
this.$axios
.$put(
"https://XXXX.com/posts/" +
editedPost.id +
".json?auth=" +
vuexContext.state.token,
editedPost
)

Related

Vue trigger request to fetch data from API

I'm fresh in Vue so this question can be dumb. I want to display data in Vue from my backend Rails API. The data should shows up each time a user enters the site. To do so I'm calling GET endpoint which is located below:
imports.js
const fetchSyncedProductsResultRequest = (self) => {
const jwtToken = self.$store.state.idToken;
return axios
.get(`/api/v1/imports/products/sync_result`, {
headers: {
Authorization: `Bearer ${jwtToken}`,
}
})
.then(response => {
self.unsyncedProducts = response.data['products']
})
};
export {
fetchSyncedProductsResultRequest
};
Expected JSON response from this GET will be:
{:products=>
[{:id=>"611ea9a7392ab50013cf4713", :name=>"2-Tone Hoodie", :code=>"SS22CH013", :result=>nil, :last_sync_at=>nil},
{:id=>"60ec84062f25d400150b351c", :name=>"5-Pocket Denim", :code=>"SS22WP014", :result=>nil, :last_sync_at=>nil},
{:id=>"61966dc83e81dd001731ccd7", :name=>"Zip Shirt Jacket", :code=>"FW22WT001", :result=>nil, :last_sync_at=>nil},
{:id=>"61d5cab6b41408001b0e9376", :name=>"Yankees Satin Varsity Jacket", :code=>"FW22WJ021", :result=>nil, :last_sync_at=>nil}]}
Inside my Vue file I've got:
sync_products.vue
<template>
<div>
<div class="panel">
<div class="panel-body">
<h4>Synchronize products</h4>
<div v-for="product in fetchedProductSyncStatus" :key="product" class="status">
{{product}}
</div>
</div>
</div>
</div>
</template>
<script>
import {
fetchUnsyncedProductsRequest,
} from '../../api/imports'
export default {
name: 'BackboneSyncProducts',
data(){
return{
fetchedProductSyncStatus: []
}
},
}
</script>
<style scoped>
</style>
Looks like request is not sent because nothing shows up and I don't see it in Network tab. What determines the sending of this request?
You need to hook the fetchUnsyncedProductsRequest function to Vue's lifecycles, like created or mounted. See: https://vuejs.org/guide/essentials/lifecycle.html
I would also change the function to just return the data.
const fetchSyncedProductsResultRequest = (token) => {
return axios
.get(`/api/v1/imports/products/sync_result`, {
headers: {
Authorization: `Bearer ${token}`,
}
})
.then(response => {
return response.data['products']
})
};
export {
fetchSyncedProductsResultRequest
};
Then add the created hook and add the response to fetchedProductSyncStatus
export default {
name: 'BackboneSyncProducts',
data() {
return{
fetchedProductSyncStatus: []
}
},
created () {
const jwtToken = this.$store.state.idToken;
fetchUnsyncedProductsRequest(jwtToken).then(data => {
this.fetchedProductSyncStatus = data
})
}
}
Edit: Fixed the self reference error you commented about. On that note it is bad practice to store token in the client like a store

NextJS: Failed when fallback set to true

I am using vercel for NextJS and this is my setup in getStaticPaths
const paths = posts.map((post) => ({
params: { player: post.player, id: post.id },
}))
return { paths, fallback: true }
When I set the fallback to true, I have got this error in vercel:
21:55:01.736 info - Generating static pages (1752/1752)
21:55:01.736 > Build error occurred 21:55:01.739 Error: Export
encountered errors on following paths: 21:55:01.739
/clip/[player]/[id]
It is ok when fallback is set to false but I really like to set fallback set to true so that pages can be updated frequently. Any help will be greatly appreciated...
Inside your /clip/[player]/[id].js file, you need to handle the fallback state when that page is being requested on-demand.
// pages/posts/[id].js
import { useRouter } from 'next/router'
function Post({ post }) {
const router = useRouter()
// If the page is not yet generated, this will be displayed
// initially until getStaticProps() finishes running
if (router.isFallback) {
return <div>Loading...</div>
}
// Render post...
}
// This function gets called at build time
export async function getStaticPaths() {
return {
// Only `/posts/1` and `/posts/2` are generated at build time
paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
// Enable statically generating additional pages
// For example: `/posts/3`
fallback: true,
}
}
// This also gets called at build time
export async function getStaticProps({ params }) {
// params contains the post `id`.
// If the route is like /posts/1, then params.id is 1
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()
// Pass post data to the page via props
return {
props: { post },
// Re-generate the post at most once per second
// if a request comes in
revalidate: 1,
}
}
export default Post
https://nextjs.org/docs/basic-features/data-fetching#fallback-true
What I did was conditionally render my component. So, my component receives the object data and if I need to use a value from data, such as "title", I will do...
data?.title
Also, for my entire return component I will conditionally render it. For example...
{data !== undefined ? (
<div className ='main-content'>
<p> This is the content that I want rendered if data is defined </p>
</div>
) : (
<div className = 'fallback-content'>
<p> This shows if data == undefined </p>
</div>
)

Problem in Vue Express with displaying image

I'm developing an express vue app. I have a problem in displaying image in vue.
In a vue page, I run an axios.get in vue js beforeMount hook, and get images data in base64 from API.
Then save data in an array. I don't see images but texts haven't problem. In some page refreshes like editing code and ... I see images but then problem remain.
vue js code:
<template>
<div v-for="(designImg, i) in designImgs" :key="i">
<q-img
:src="designImg"
height="100px"
class="bg-grey-4"
/>
</div>
<template>
<script>
data () {
return {
designImgs: null
}
},
beforeMount () {
this.$axios.get('shop/product', {
params: {
designId: this.$route.params.designId,
}
}).then((res) => {
if (res.data.error) {
console.log(res.data.error)
} else {
const designImgUrls = res.data.imageUrls.split(',')
const mydesignImgs = []
for (let i = 0; i < designImgUrls.length; i++) {
this.$axios.get('/shop/image', {
params: {
url: designImgUrls[i]
}
}).then((res) => {
const url1 = 'data:image/jpeg;base64, ' + res.data
mydesignImgs[i] = url1
}).catch(err => {
console.log(err)
})
}
this.designImgs = mydesignImgs
}
}).catch((err) => {
console.log(err)
})
}
<script>
Note that in above code we recieve from server these data:
imageUrls: "uploads\imagee-1592862806606.jpg,uploads\imagee-1592862806654.jpg"
and then after getting images data res.data is equals to a base64 image data like this:
/9j/2wBDAAYEBQYFBAY...
I have solved this problem.
I have changed the way of collecting image data in mydesignImgs array.
i have used this code:
mydesignImgs.push(url1)
instead of using this equality:
mydesignImgs[i] = url1
but why?

How to get country code and Country name using IP in react js

I am working on an application which is based on react.js. One of the requirements in the app is to detect the location(Country) from where it is opened and then pre-fill the phone number field on a form with the flag of this country.
I am thinking that it would be done more efficiently by first detecting the IP address and then finding out the country name using this IP address. For that purpose, I have tried many libraries e.g. "iplocation", "geoip-country-lite", "ip" etc but these are not compatible with my application. Can any please suggest me other library using which I can get the country name?
Or there is any other effective solution instead of detecting the IP address e.g. getting some info from the browser which can get me the country name? Please guide.
You can do this without using jQuery.
Install & import axios from npm
import axios from 'axios'
Initialize your component state with country name & country code
constructor(props) {
super(props);
this.state = {
countryName: '',
countryCode: ''
}
}
Add this function to your component
getGeoInfo = () => {
axios.get('https://ipapi.co/json/').then((response) => {
let data = response.data;
this.setState({
countryName: data.country_name,
countryCode: data.country_calling_code
});
}).catch((error) => {
console.log(error);
});
};
And call this.getGeoInfo() to set country name & country code to your state. I called that from componentDidMount()
componentDidMount(){
this.getGeoInfo();
}
And you can read the state to get country name & country code
render() {
return (
<div>
<p>Country Name: {this.state.countryName}</p>
<p>Country Code: {this.state.countryCode}</p>
</div>
)
}
With React hooks, this can be done like below:
import React, { useEffect } from 'react';
useEffect(() => {
fetch('https://extreme-ip-lookup.com/json/')
.then( res => res.json())
.then(response => {
console.log("Country is : ", response);
})
.catch((data, status) => {
console.log('Request failed:', data);
});
},[])
You can use an external API to get location details from the client IP address.
I've redone this to use http://api.hostip.info, which is free to use, and I'm using Fetch rather than jQuery to pull the data.
function getElementText(response, elementName) {
return response.getElementsByTagName(elementName)[0].innerHTML;
}
function getIpAddress() {
fetch('http://api.hostip.info').then(response => {
return response.text();
}).then(xml => {
return (new window.DOMParser()).parseFromString(xml, "text/xml");
}).then(xmlDoc => {
countryName = getElementText(xmlDoc , "countryName");
countryCode = getElementText(xmlDoc , "countryAbbrev");
$("#output").html("Country name: " + countryName + "<br>" + "Country code: " + countryCode);
});
}
<div style="text-align:center;line-height:30px;">
<button onclick="getIpAddress()">Click me to get IP AddressInfo </button>
<div id="output">Location:</div>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

VueJS throws errors because some datas are not ready yet

I'm rather new to VueJS, and I would like to add a picture loaded from an API as a background image. However, the image loading eventually works.
Here is the code:
<template>
<div id="bio" :style="{ backgroundImage: 'url(' + this.settings.bio_bg.url +')' }">
<h1>Biography</h1>
<router-link to="/">Home</router-link><br />
<span>Biography</span><br />
<router-link to="/shop">Shop</router-link><br />
<router-link to="/contact">Contact</router-link><br />
</div>
</template>
<style scoped>
</style>
<script>
export default {
data () {
return {
settings: {},
bio: {}
}
},
created () {
.catch(error => this.setError(error))
this.$http.secured.get('/settings')
.then(response => {
this.settings = response.data
console.log(this.settings)
})
.catch(error => this.setError(error))
}
}
</script>
The image is loaded, but my console returns two errors:
Error in render: "TypeError: Cannot read property 'url' of undefined"
Cannot read property 'url' of undefined
I guess that since the Axios call is asynchronous, everything arrives after the page is done loading, but is still loaded after.
What would the proper way be to correctly wait for data to be available? I tried a few things that I know from React, but it doesn't load at all (even though the errors stop showing up)
Thank you in advance
Yo need to be sure that this.settings.bio_bg.url exist from the component birth, so compiler doesn't broke trying to render it. In order to do so, just setup a 'fake' url in the original data of the component:
export default {
data () {
return {
settings: {
bio_bg: {
url: '',
}
},
bio: {}
}
},
created () {
this.$http.secured.get('/settings')
.then(response => {
this.settings = response.data
console.log(this.settings)
})
.catch(error => this.setError(error))
}
}
This not only prevent errors, also provides better intellisense since now your code editor can now that settings has a bio_bg member which in turn has an url.
If instead of ' ', you provide a real image url with a placeholder img, probably the UI will be nicer:
data () {
return {
settings: {
bio_bg: {
url: 'http://via.placeholder.com/350x150',
}
},
bio: {}
}
}

Categories