I am learning vue.js and trying to call a json file and parse the data. Everything is working but when I refresh the page, I see a blank page before my data is loaded and in console log I get TypeError: e.myData is null. After few second the data is displayed on the page.
main.js:
new Vue({
el: `#app`,
render: h => h(App,{
props:{
todoID: this.dataset.id
}
})
})
and my App.vue:
<template>
<div>
<div>{{myData.getName()}}</div>
</div>
</template>
<script>
import Info from '#/getInfo'
export default {
name: 'App',
props: {
todoID: String,
},
data() {
return {
data: null,
myData: null
}
},
created() {
fetch(`http://localhost/json-end-point/`)
.then(async response => {
const data = await response.json();
if (!response.ok) {
const error = (data && data.message) || response.statusText;
return Promise.reject(error);
}
// set the date here, am I doing this right?
this.myData = new Info(data);
this.data = data;
})
.catch(error => {
this.errorMessage = error;
console.error("There was an error!", error);
});
}
}
</script>
getInfo.js
export default class Info {
constructor(Data) {
if (Data) {
const data = JSON.parse(Data);
console.log(data.name); // returns name
// console.log(data); // returns the json data
this.name = data.name;
}
}
getName() {
return this.name;
}
}
I think I am doing something wrong here this.myData = new Info(data); but I am not sure what I can do.
Update
I was able to remove the console log by adding v-if="myData !== null". Still not sure assigning data like this this.myData = new Info(data); is a good approach. How can I improve this code?
Here's an example of how to let the template show different states so it doesn't try to render the data before it arrives, but shows a loading indicator instead.
<template>
<div v-if="myData">
<div>{{ myData.getName() }}</div>
</div>
<div v-else-if="isLoading">
Loading data...
</div>
<div v-else-if="errorMessage">
{{ error.message }}
</div>
</template>
<script>
import Info from '#/getInfo'
export default {
name: 'App',
props: {
todoID: String,
},
data() {
return {
data: null,
myData: null,
error: null
}
},
async created() {
await this.getData()
},
methods: {
async getData() {
try {
const response = await fetch(`http://localhost/json-end-point/`)
if (!response.ok) {
throw new Error(data?.message || response.statusText)
}
this.data = await response.json();
this.myData = new Info(this.data);
} catch (error) {
this.error = error;
console.error("There was an error!", error);
}
}
}
}
</script>
You could stick the myData.getName() call inside a computed field that either returns the name if myData != null or an empty string (or whatever value you want when there is no data available).
Something like this
computed: {
getName() {
return this.myData ? this.myData.getName() : '';
}
}
Related
In my Angular app I am having trouble with getting the value from my params and thus data from my API call.
I keep getting null and [object Object] in browser console for my console.log
EDIT: I have noticed that upon loading this page the tag value is overwhritten wit undefined.. image bellow:
Here is the code I am using to get params value and show products with this tag:
EDIT: search.service.ts file where the API is called
searchByTagCall(tag: string) {
return from(Preferences.get({key: 'TOKEN_KEY'})).pipe(
switchMap(token => {
const headers = new HttpHeaders().set('Authorization', `Bearer ${token.value}`);
let params = new HttpParams();
params = params.append('tag', tag);
return this.httpClient.get(`${environment.apiUrl}search`, {headers, observe: 'response', params});
}),
catchError(err => {
console.log(err.status);
if (err.status === 400) {
console.log(err.error.message);
}
if (err.status === 401) {
this.authService.logout();
this.router.navigateByUrl('/login', {replaceUrl: true});
}
return EMPTY;
}),
);
}
EDIT: home.page.ts Code where I click the tag that redirects to the page where products with this tag should be shown:
searchByTag(tag: string) {
this.tagsSubscription = this.searchService.searchByTagCall(tag).subscribe((data: any) => {
this.searchService.tag = data;
this.router.navigate(['/tag-search/', tag]);
},
error => {
console.log('Error', error);
});
}
and html:
<ion-chip *ngFor="let tag of tags">
<ion-label class="tag" (click)="searchByTag(tag.tags)">{{ tag.tags }}</ion-label>
</ion-chip>
tag-search.page.ts:
export class TagSearchPage implements OnInit {
tag: string;
products: any = [];
constructor(
private route: ActivatedRoute,
private searchService: SearchService,
) { }
ngOnInit() {
this.showTagProducts();
}
showTagProducts() {
const tag = String(this.route.snapshot.paramMap.get('tag'));
this.searchService.searchByTagCall(tag).subscribe(
(data: any) => {
console.log('Products with tag: ' + tag + ' ' + data);
},
error => {
console.log('Error', error);
});
}
}
Here is how my JSON response looks like:
[
{
"id": 1283,
"name": "Some product name",
"product_code": "470631"
},
{
"id": 786,
"name": "A different product name",
"product_code": "460263"
}
]
Sorry for such noob question but I'm a simply gave up. I've got below code which creates a POST request to the BE part of the app - user provides input (productCodes) and push submit button. That part works well, Vue sends request to BE but in the response FE should have received JSON with result: { id: 1234 }
How do I get this response and display it inside the app? I've got below:
imports.js
const createProductsRequest = (self, products) => {
const jwtToken = self.$store.state.idToken;
const payload = JSON.stringify({ product_codes: products['product_codes'].split(',') })
return axios
.post(`/api/v1/imports/products/`, payload,{
headers: {
Authorization: `Bearer ${jwtToken}`,
'Content-Type': 'application/json',
'Accept': 'application/json'
}
})
.then(response => response.data)
};
export {
createProductsRequest
};
sync_product.vue
<script>
import {
createProductsRequest
} from '../../api/imports'
import ModalController from '../general/modal_controller'
export default {
name: 'BackboneSyncProducts',
data() {
return {
styleCodes: [],
}
},
computed: {
productsToSyncAmount () {
return this.styleCodes.length
},
},
methods: {
async syncProducts() {
let confirmationText = `Do you want to ${this.productsToSyncAmount} sync products?`
if (this.productsToSyncAmount === 0) {
ModalController.showToast('', 'Type product codes for sync first, please!', 'warning')
}
else if (await ModalController.showConfirmation('Confirmation', confirmationText)) {
try {
ModalController.showLoader()
await createProductsRequest(this, this.styleCodes)
const successMessage = `${this.productsToSyncAmount} products have been queued for sync`
await ModalController.showToast('', successMessage)
} catch (data) {
const errorMessage = `Error occurred during queueing products to sync - `
ModalController.showToast('', errorMessage + data?.message, 'error')
} finally {
this.styleCodes = []
ModalController.hideLoader()
}
}
},
}
}
</script>
That's all what I have.
Instead of calling your request without getting the return value:
await createProductsRequest(this, this.styleCodes)
You can get the return value which is the result of the request :
const data = await createProductsRequest(this, this.styleCodes)
By doing that, data must contain the result of the request, as you mentionned { id: 1234 }.
--
If you want to use this result in your component, you can create a reactive value in data()
data() {
return {
styleCodes: [],
data: null
}
},
And store the result like this :
this.data = await createProductsRequest(this, this.styleCodes)
With that you can display it in your template for example :
<template>
<!-- There is a v-if because before doing the request, data is null -->
<div v-if="data">{{ data.id }}</div>
</template>
I followed the next docs regarding a custom error page. I want to reuse the error page if certain errors occur at getStaticProps. Something like:
const Page: NextPage<Props> = ({ pageData, error }: Props) => {
if (error) return <Error statusCode={500} />;
return <Page data={pageData} />;
};
export const getStaticProps: GetStaticProps = async ({
params,
}: {
params: { [prop: string]: string[] };
}) => {
const { slug } = params;
const {pageData, error} = getPageData(slug)
return {
props: {
pageData: page || null,
error: error || null,
},
};
};
export default Page;
The error page is just like in the docs:
function Error({ statusCode }) {
return (
<p>
{statusCode ? `An error ${statusCode} occurred on server` : 'An error occurred on client'}
</p>
);
}
Error.getInitialProps = ({ res, err }) => {
const statusCode = res ? res.statusCode : err ? err.statusCode : 404;
return { statusCode };
};
export default Error;
This works but the status code ist wrong. Nextjs still answers a request to this page with a status code 200. I need it to set the status code to 500 as if there was a server error.
you can change your page status code if you are using "getServerSideProps" or "getStaticProps", you only need to change the response status code before returning the page props:
const HomePage = ({pageProps}) => {
if (pageProps.hasError) {
return <CustomError status={error.status} message={error.message}/>
}
return <div>This is home page </div>
}
export const getServerSideProps = async ({req,res}) => {
try {
const homeData = await fetchHomeData()
return {
props: {
data: homeData
}
}
} catch (err) {
res.statusCode = exception.response.status /* this is the key part */
return {
props: {
hasError: true, error: {
status: exception.response.status || 500,
message: exception.message
}
}
}
}
}
My component script is:
export default {
name: "Authenticate",
data: () => {
return {
validationFailed: {}
};
},
methods: {
validateForm() {
this.validationFailed = {};
if (this.createEmail.trim().length === 0) {
this.validationFailed.createEmailField = "Email cannot be blank. ";
}
if (this.createPassword.trim().length === 0) {
this.validationFailed.createPasswordField =
"Password cannot be blank. ";
}
if (Object.keys(this.validationFailed).length === 0) {
return true;
}
return false;
},
handleSubmit() {
const that = this;
axios
.request({
url: `${process.env.VUE_APP_API_URL}/users`,
method: "POST",
data: {
email: this.createEmail,
password: this.createPassword
}
})
.then(response => {
console.log(response);
})
.catch(err => {
that.validationFailed.createEmailField = "something";
});
}
}
};
But inside the catch, with a debugger, I can see that the value gets set. But in my template, the validationFailed doesn't get updated. What am I doing wrong?
It's Vue reactivity problem. You need to assign this.validationFailed to new object. You can try ES6 syntax in catch block:
that.validationFailed = {
...that.validationFailed,
createEmailField: 'something'
}
I have blog in vue.js
I want to preview each post separately.
I do this>
export default{
name: 'post',
props:['id'],
data(){
return {
singlePost: { }
}
},
created() {
BlogPostsApi.getPost(this.id)
.then(response => {
console.log(response)
this.singlePost = response.data
})
}
in blogPosts.js i have this code>
import axios from'axios';
export default{
getPost (id) {
return axios.get('http://localhost:8000/api/posts/ddc/' + id)
.then(response => {
debugger
return response.data
})
}
}
When i'm debugging i get this error Message Cannot read property 'singlePost' of undefined
created() {
var self = this
BlogPostsApi.getPost(this.id)
.then(response => {
console.log(response)
self.singlePost = response.data
})
}
The problem is solved