data in Vue instance doesn't get updated after axios post response - vue.js

I am writing a code piece to submit the html form data on a POST REST API. Using Vue.js and axios for that.
My Vue.js code is like this -
const app = new Vue({
el: "#main-div",
data() { return {
name: 'Please enter the name',
showEdit: true,
showResponse: true,
responseText: null
}
},
methods: {
savePerson: function () {
this.showEdit = false;
axios
.post('/api/person', {
name: this.name
})
.then(function (response) {
this.responseText = response.data.name+ ' added successfully.';
console.log(response);
console.log(response.data.name+ ' added successfully.');
})
.catch(function (error) {
this.responseText = error.message;
console.log(error);
});
}
}
}
)
And html -
<div id="main-div">
<h2> Fill out the details to create a Person</h2>
<div v-if="showEdit">
<form >
<div>
Name: <input v-bind:value = 'name' type="text" v-on:focus="name= ''" />
</div>
<div>
<button v-on:click="savePerson">Save</button>
</div>
</form>
</div>
<div v-if="showResponse">
<div><p>{{ responseText }}</p></div>
<div>
<button v-on:click="showEdit = true">Add one more person</button>
</div>
</div>
This code doesn't update responseText. That I can check in Vue plugin in browser.
Any idea what is not correct in my example?

You need to use an arrow function in the callback or else the function injects its own this context:
.then((response) => {
...
})
.catch((error) => {
...
})
Or you could use async/await:
async savePerson() {
this.showEdit = false;
try {
const response = await axios.post('/api/person', {
name: this.name
})
this.responseText = response.data.name+ ' added successfully.';
} catch(error) {
this.responseText = error.message;
}
}

to bind data with the input field you need to use v-model in the HTML and try to use the arrow function in the API call.

Related

Nuxt.js Hackernews API update posts without loading page every minute

I have a nuxt.js project: https://github.com/AzizxonZufarov/newsnuxt2
I need to update posts from API every minute without loading the page:
https://github.com/AzizxonZufarov/newsnuxt2/blob/main/pages/index.vue
How can I do that?
Please help to end the code, I have already written some code for this functionality.
Also I have this button for Force updating. It doesn't work too. It adds posts to previous posts. It is not what I want I need to force update posts when I click it.
This is what I have so far
<template>
<div>
<button class="btn" #click="refresh">Force update</button>
<div class="grid grid-cols-4 gap-5">
<div v-for="s in stories" :key="s">
<StoryCard :story="s" />
</div>
</div>
</div>
</template>
<script>
definePageMeta({
layout: 'stories',
})
export default {
data() {
return {
err: '',
stories: [],
}
},
mounted() {
this.reNew()
},
created() {
/* setInterval(() => {
alert()
stories = []
this.reNew()
}, 60000) */
},
methods: {
refresh() {
stories = []
this.reNew()
},
async reNew() {
await $fetch(
'https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty'
).then((response) => {
const results = response.slice(0, 10)
results.forEach((id) => {
$fetch(
'https://hacker-news.firebaseio.com/v0/item/' +
id +
'.json?print=pretty'
)
.then((response) => {
this.stories.push(response)
})
.catch((err) => {
this.err = err
})
})
})
},
},
}
</script>
<style scoped>
.router-link-exact-active {
color: #12b488;
}
</style>
This is how you efficiently use Nuxt3 with the useLazyAsyncData hook and a setInterval of 60s to fetch the data periodically. On top of using async/await rather than .then.
The refreshData function is also a manual refresh of the data if you need to fetch it again.
We're using useIntervalFn, so please do not forget to install #vueuse/core.
<template>
<div>
<button class="btn" #click="refreshData">Fetch the data manually</button>
<p v-if="error">An error happened: {{ error }}</p>
<div v-else-if="stories" class="grid grid-cols-4 gap-5">
<div v-for="s in stories" :key="s.id">
<p>{{ s.id }}: {{ s.title }}</p>
</div>
</div>
</div>
</template>
<script setup>
import { useIntervalFn } from '#vueuse/core' // VueUse helper, install it
const stories = ref(null)
const { pending, data: fetchedStories, error, refresh } = useLazyAsyncData('topstories', () => $fetch('https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty'))
useIntervalFn(() => {
console.log('refreshing the data again')
refresh() // will call the 'topstories' endpoint, just above
}, 60000) // every 60 000 milliseconds
const responseSubset = computed(() => {
return fetchedStories.value?.slice(0, 10) // optional chaining important here
})
watch(responseSubset, async (newV) => {
if (newV.length) { // not mandatory but in case responseSubset goes null again
stories.value = await Promise.all(responseSubset.value.map(async (id) => await $fetch(`https://hacker-news.firebaseio.com/v0/item/${id}.json?print=pretty`)))
}
})
function refreshData() { refreshNuxtData('topstories') }
</script>

Tableau Vuejs getWorkBook() "Cannot read property get_workbook of null"

I am trying to follow the getData example found on the tableau javascript tutorial (https://github.com/tableau/js-api-samples/blob/master/getDataBasic.html) , but for vue js, however, I am unable to get it to work. I am able to render the tableau object, but when it comes to getting the underlying data or even trying to get the workbook name, I get the error: "Cannot read property get_workbook of null". Below is my code:
<template>
<div class="container" style="margin-top: 90px;">
<div id="vizContainer2"></div>
</div>
</template>
<script>
export default {
name: 'TableauHolder',
methods: {
getUnderlyingData(){
const containerDiv = document.getElementById("vizContainer2")
let url = "http://public.tableau.com/views/RegionalSampleWorkbook/Storms"
let options = {
hideTabs: true,
hideToolbar: true,
onFirstInteractive: () => {
}
}
this.viz = new window.tableau.Viz(containerDiv, url, options)
let sheet = this.viz.getWorkbook().getActiveSheet().getWorksheets().get("Storm Map Sheet")
console.log(sheet)
},
},
mounted () {
window.addEventListener('load', () => {
this.getUnderlyingData();
})
}
}
</script>
Placing getWorBbook() in onFirstInteractive successfully gets me the workbook name (as shown below), but I am not sure where to go from there in terms rendering the data.
<template>
<div class="container" style="margin-top: 90px;">
<div id="vizContainer2"></div>
</div>
</template>
<script>
export default {
name: 'TableauHolder',
methods: {
getUnderlyingData(){
const containerDiv = document.getElementById("vizContainer2")
let url = "http://public.tableau.com/views/RegionalSampleWorkbook/Storms"
let options = {
hideTabs: true,
hideToolbar: true,
onFirstInteractive: () => {
let sheet = this.viz.getWorkbook()
console.log(sheet)
}
}
this.viz = new window.tableau.Viz(containerDiv, url, options)
},
},
mounted () {
window.addEventListener('load', () => {
this.getUnderlyingData();
})
}
}
</script>
I realized that the JavaScript API is asynchronous and therefore the let sheet line is executed before while executing the API. Therefore, something like setTimeout will make the line execute after the API has been executed. See below incase anyone was having similar issues:
<template>
<div class="container" style="margin-top: 90px;">
<div id="vizContainer2"></div>
</div>
</template>
<script>
export default {
name: 'TableauHolder',
methods: {
getUnderlyingData(){
const containerDiv = document.getElementById("vizContainer2")
let url = "http://public.tableau.com/views/RegionalSampleWorkbook/Storms"
let options = {
hideTabs: true,
hideToolbar: true,
onFirstInteractive: () => {
}
}
this.viz = new window.tableau.Viz(containerDiv, url, options)
setTimeout(() => {
let sheet = this.viz.getWorkbook().getActiveSheet();
console.log(sheet);
}, 3000);
},
},
mounted () {
window.addEventListener('load', () => {
this.getUnderlyingData();
})
}
}
</script>

Why Vue doesn't refresh list using props?

On my App, on mounted() method, I call an API, which give to me a JSON with a list of items; than, I update the prop I've set in my target Homepage component:
Homepage.pages = resJSON.data.pages;
Here's the App code:
<template>
<div id="app">
<Homepage title="PWA Test"/>
</div>
</template>
<script>
import Homepage from './components/Homepage.vue'
export default {
name: 'App',
components: {
Homepage
},
mounted() {
let endpoint = "http://localhost:5000/api/graphql?query={pages(orderBy:{contentItemId:asc}){contentItemId,createdUtc,author,displayText,description%20}}";
fetch(endpoint, {
method:'GET',
headers: {
'Accept':'application/json',
'Content-Type':'application/json'
}
})
.then((response) => {
// check for HTTP failure
if (!response.ok) {
throw new Error("HTTP status " + response.status);
}
// read and parse the JSON
return response.json();
})
.then((res) => {
Homepage.pages = res.data.pages;
})
.catch((error) => {
console.log(error);
});
}
}
</script>
<style>
</style>
Here's the Homepage component:
<template>
<div id="homepage">
<h1>{{ title }}</h1>
<ul>
<li v-for="page in pages" :key="page.description">#{{ page.description }}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'Homepage',
props: {
title: String,
pages: []
}
}
</script>
<style scoped>
</style>
But the ul doesn't update after receiving the JSON and updating the props pages. Where's my error?
you need to get the response.json(); in a data property of the App and then pass it down to the Homepage component. So your code should you look like this,
App code:
<template>
<div id="app">
//binding page into data property
<Homepage title="PWA Test" :pages="pages"/>
</div>
</template>
<script>
import Homepage from './components/Homepage.vue'
export default {
name: 'App',
data: function () {
return {
//data propety
pages : []
}
},
components: {
Homepage
},
mounted() {
let endpoint = "http://localhost:5000/api/graphql?query={pages(orderBy:{contentItemId:asc}){contentItemId,createdUtc,author,displayText,description%20}}";
fetch(endpoint, {
method:'GET',
headers: {
'Accept':'application/json',
'Content-Type':'application/json'
}
})
.then((response) => {
if (!response.ok) {
throw new Error("HTTP status " + response.status);
}
// assign the result to the data property
this.page = response.json();
})
.then((res) => {
Homepage.pages = res.data.pages;
})
.catch((error) => {
console.log(error);
});
}
}
</script>
Do you pass the props in a template after this.pages = res.data.pages?
<Homepage :pages="pages" />
I think there are some mistakes that you have done in your code, if you want change update prop value then you have to initialized your props values in script.
<template>
<div id="homepage">
<h1>{{ title }}</h1>
<ul>
<li v-for="page in currentPages" :key="page.description">#{{ page.description }}
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'Homepage',
props: {
title: String,
pages: []
}
data: function () {
return {
currentPages: this.pages
}
}
}
</script>
I hope this will help you to solve your issue- thanks!

How I can upload files using Laravue with Dropzone

i'm trying to make work Laravue Dropzone, but I have'nt working yet
Here is the code:
<el-dialog :title="'Importar Bitacora'" :visible.sync="dialogFormVisible">
<div v-loading="weblogCreating" class="form-container">
<el-form ref="weblogForm" :rules="rules" :model="newBitacora" label-position="left" label-width="150px">
<div class="editor-container">
<dropzone id="CargarBitacora" url="/api/bitacora/importar" #dropzone-removedFile="dropzoneR(e)" #dropzone-error="dropzoneError" #dropzone-success="dropzoneS" />
</div>
</el-form>
</div>
<div slot="footer" class="dialog-footer">
<el-button #click="dialogFormVisible = false">
{{ $t('bitacora.cancel') }}
</el-button>
<el-button type="primary" #click="handleUpload()">
{{ $t('bitacora.confirm') }}
</el-button>
</div>
</el-dialog>
<script>
import Dropzone from '#/components/Dropzone';
export default {
name: 'BitacoraList',
components: { Dropzone },
data() {
return {
files: [],
},
created() {
.. code here ..
},
methods: {
handleUpload(e) {
const formData = new FormData();
this.files.forEach(file => {
formData.append('files[]', file);
});
console.log(this.files);
},
}
};
</script>
I've tried to pass the files to handleUpload, but I can't make it work to the moment
I figured out how to upload files with dropzone, en the method handleUpload I just have to send the file to a post method in laravel backend who upload a temporary file
dropzoneR(file) {
var name = file.upload.filename;
fileResource.borrar(name).then(response => {
this.files.splice(this.files.indexOf(name), 1);
if (this.files.length < 1) {
this.btnUpload = true;
}
}).catch(error => {
console.log(error);
});
},
and returns an ok if it gets uploaded, then when I confirm thats the files I need up, other method in laravel backend who do what a want to do with the file if its an excel file (in mi case) upload the data to the database, or what ever I want. like this
async handleUpload(e) {
this.weblogCreating = true;
await bitacoraResource.store(this.files).then(response => {
this.$message({ message: 'Bitacoras importadas satisfactoriamente', type: 'success' });
this.files = '';
this.dialogImportVisible = false;
this.weblogCreating = false;
this.getList();
}).catch(error => {
this.$message({
message: 'Error importando las bitacoras ' + error.getMessage,
type: 'error',
});
this.weblogCreating = false;
console.log(error.message);
});
},

I don't have enough knowledge as to why my DOM isn't displaying my API call results from storyblok

I am making an app in Nuxt using storyblok as my CMS. However, I was receiving errors when trying to link the storyblok array to my arrays called in my template using v-for. I got a bit of help from another user and fixed the errors, but now I don't have enough knowledge as to why the DOM isn't displaying the results of my API call on my v-for's called in the template ("books" and "posts")
Here is the template:
<template>
<div>
<!-- instance header -->
<InstanceHeader title="Books" />
<div class="pageContainer">
<div class="booksInfoPost">
<div class="booksInfoPost__subHeader"><h3>Top Books</h3></div>
<div class="booksInfoPost__topBooks">
<BooksInfoPostTop
v-for="book in books"
:key ="book.id"
:bookCover="book.bookCover"
:title="book.title"
:author="book.author"
:content="book.content"
:id="book.id"
/>
</div>
<div class="booksInfoPost__subHeader"><h3>Book Titles</h3></div>
<BooksInfoPost
v-for="book in posts"
:key ="book.id"
:bookCover="book.bookCover"
:title="book.title"
:author="book.author"
:content="book.content"
:id="book.id"
/>
</div>
</div>
</div>
</template>
Here is my script:
<script>
import InstanceHeader from '~/components/InstanceHeader';
import BooksInfoPostTop from '~/components/BooksInfoPostTop';
import BookTitles from '~/components/BookTitles';
import BooksInfoPost from '~/components/BooksInfoPost';
import axios from 'axios';
export default {
components: {
InstanceHeader,
BooksInfoPostTop,
BookTitles,
BooksInfoPost
},
data() {
/* return {
books: [],
posts: []
} */
},
async asyncData(context) {
const result = {};
const mapBooks = b => {
return {
id: b.slug,
bookCover: b.content.bookCover,
title: b.content.title,
author: b.content.author
};
};
result.posts = await context.app.$storyapi
.get("cdn/stories", {
version: "draft",
starts_with: 'books/book-titles'
}).then(response => {
console.log(response);
response.data.stories.map(mapBooks);
})
result.books = await context.app.$storyapi
.get("cdn/stories", {
version: "draft",
starts_with: 'books/top-books'
}).then(response => {
console.log(response);
response.data.stories.map(mapBooks);
})
return result; // it has right property names {books:[], posts:[]}
}
}
</script>
I am not the most experienced developer and If anyone can help I'll appreciate it. Thanks
You do not need to use then when awaiting a promise.
const { data } = await context.app.$storyapi
.get("cdn/stories", {
version: "draft",
starts_with: 'books/book-titles'
}).then(response => {
console.log(response);
response.data.stories.map(mapBooks);
});
result.posts = data.stories.map(mapBooks);
By the way, you forgot to return a value in your promises:
result.posts = await context.app.$storyapi
.get("cdn/stories", {
version: "draft",
starts_with: 'books/book-titles'
}).then(response => {
console.log(response);
return response.data.stories.map(mapBooks); // return the array of books
})
Also, you should check that response.data.stories is not undefined or you might get an error.