Vue.js Axios: unable to update page after HTTP GET request - javascript

I'm quite new to Vue.js and Axios. I'd like to learn it to create A REST CRUD Interface.
Starting from the HTTP GET request, the examples I've found so far all execute an HTTP GET when the page load and print the returned data. That works pretty well.
On the other hand, I need to display the data when I click a button. Here's what I have coded so far:
<script>
new Vue({
el: "#app",
data() {
return {
users: []
}
},
})
</script>
<script>
function performGetRequest1() {
axios
.get('http://localhost:8080/users')
.then(response => {
this.users = response.data,
})
.catch(function (error) {
console.log(error);
})
}
</script>
<button onclick="performGetRequest1()">Get Todos</button>
<tr v-for="user in users" :key="user.id">
<td>{{user.id}}</td>
<td>{{user.name}}</td>
<td>{{user.surname}}</td>
</tr>
So, I can see that when I hit the button the function correctly invokes the backend and data is returned. However, even if I set the users array to the response that is not updated in the table.
I believe I should set my request to be ajax based, just my attempts so far have failed.
Any help?

I believe the issue here is that you are working in 2 different contexts: you create the Vue app in one context and then you write the Axios script in a totally different context. Vue is reactive and will update your HTML, but only with data that it knows about. Thus, you're very close, but you just need to move your Axios script into Vue's context! Your best bet is going to be turning performGetRequest1 into a Vue method.
Additionally, your "onclick" handler on the button is a Javascript handler and not something Vue is going to listen to. You should be using the v-on:click (or shorthand, #click) prop to listen for the click event.
Check out the "Handling User Input" section of the Vue docs: https://v2.vuejs.org/v2/guide/#Handling-User-Input
<script>
new Vue({
el: "#app",
methods: {
performGetRequest1() {
axios
.get('http://localhost:8080/users')
.then(response => {
this.users = response.data
})
.catch(function (error) {
console.log(error);
})
}
}
data() {
return {
users: []
}
},
})
</script>
<button #click="performGetRequest1">Get Todos</button>
<tr v-for="user in users" :key="user.id">
<td>{{user.id}}</td>
<td>{{user.name}}</td>
<td>{{user.surname}}</td>
</tr>

Your script tag where you define performGetRequest1 is not associated with your Vue instance, so the this in this.users = response.data is not pointing to the Vue instance. Instead, it's likely pointing to the global window object. You should put performGetRequest1 in the Vue instance's methods property:
new Vue({
el: '#app',
data () {
return {
users: []
}
},
// ADD THE CODE BELOW
methods: {
performGetRequest1 () {
// Load the data
}
}
}

Related

getting a restful Api using the fetch() in Vuex

im really going through hard times trying to figure out how to get my API data through Vuex, is there some body whom has accurate bibliography of how to do this step by step, or even better help me with this code?
Formerly without using Vuex , but Vue all request worked perfectly, but now i dont understand clearly what i should do, here sharing part of my code:
data() {
return {
testArray: []
};
methods: {
getJsonData() {
fetch(
"https://app.ticketmaster.com/discovery/v2/events.json?countryCode=" +
this.countriesDrop +
"&apikey=xxxxxxxxxxxxxxxxxxxxxxxx",
{
method: "GET"
}
)
.then(response => {
return response.json();
})
.then(test => {console.log(this.testArray)
this.testArray = test._embedded.events;
})
.catch(err => {
console.log(err);
});
},
watch: {
countriesDrop: function(val) {
this.getJsonData();
}
},
As you can see in the request also is included an external element which make it changes attuning with the watcher and the value the user might asign.
I already got set Vuex and all else pluggins...just dont know how to act like , thus would appreciate an accurate link or tutorial either help with this basic problem resolved on detail step by step, .....thanks!
In your code there's nothing with Vuex. I guessed you want to set the state so that the getJsonData() method is called according to what's in the store.
Here's a snippet as an example of handling async in a Vuex environment.
const store = new Vuex.Store({
state: {
testArray: []
},
mutations: {
setTestArray(state, data) {
state.testArray = data
}
},
actions: {
getJsonData({
commit
}, countriesDrop) {
if (countriesDrop && countriesDrop !== '') {
fetch(`https://jsonplaceholder.typicode.com/${countriesDrop}`, {
method: "GET"
})
.then(response => {
return response.json();
})
.then(json => {
commit('setTestArray', json)
})
.catch(err => {
console.log(err);
});
}
}
}
})
new Vue({
el: "#app",
store,
computed: {
getDataFromStore() {
return this.$store.state.testArray
}
},
methods: {
getData(countriesDrop) {
this.$store.dispatch('getJsonData', countriesDrop)
}
}
})
<script src="https://cdn.jsdelivr.net/npm/es6-promise#4/dist/es6-promise.auto.js"></script>
<script src="https://unpkg.com/vuex#3.1.2/dist/vuex.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="getData('todos')">GET TODOS</button>
<button #click="getData('albums')">GET ALBUMS</button>
<ol>
<li v-for="data in getDataFromStore">{{data.title}}</li>
</ol>
</div>
The point is that Vuex is a central element in a Vue-Vuex application. You can store app state, handle async and sync functions (actions, mutations) with it, and all your Vue components can rely on the state - that should be the "single source of truth".
So, you get your input from a component (the Vue instance in this snippet), and dispatch an action that is available in the Vuex store. If the action needs to modify the state, then you call a mutation to do that. With this flow you keep reactivity for all your components that use that state.
I used a computed to get data from the Vuex store, but getters can be set also.
This way you don't "pollute" your components with functions and data that should be in the store.

vue.js render ajax data that contains vue.js syntax

Vue.js version is: 2.x
Hi. I'm sending an ajax request in vue js to another page and getting it's source which contains vue.js syntax such as events. When this source is added to property and property added to a template, the ajax data source (that contains vue.js syntax) can not be rendered and does not work properly.
For example template is:
<div id="app">
{{{ foo }}}
</div>
and app.js is:
var app = new Vue({
el: '#app',
data: {
foo: 'bar'
},
mounted(){
this.$http.get('/media').then(function(response){
data = response.body;
Vue.set(app, 'foo', data);
});
},
methods: {
alertVideoLink: function(event){
alert(event.target.href);
}
}
});
In the above app.js code, ajax request returns this code (that is response.body):
Video Link
but this link can't be rendered and does not work properly! I'm testing the render method and some useful hints, but no way found. Please help... Thanks
Sounds like you want to use an Async Component.
Something like...
components: {
'async-media': () => Vue.http.get('/media').then(res => ({
template: res.body,
methods: {
alertVideoLink (event) {
this.$emit('click', event)
}
}
}))
}
Then in your template...
<async-media #click="handleClickEventFromChildComponent" />
Here's an example using a timeout to fake "load" a template
var app = new Vue({
el: '#app',
data: {},
components: {
'async-media': () => new Promise(resolve => {
setTimeout(() => {
resolve({
template: 'Video Link',
methods: {
alertVideoLink(event) {
this.$emit('click', event.target.href)
}
}
})
}, 2000)
})
},
methods: {
handleClickEventFromChildComponent (href) {
console.info('Clicked on', href)
}
}
});
<div id="app">
<p>Wait 2 seconds</p>
<async-media #click="handleClickEventFromChildComponent" />
</div>
<script src="https://unpkg.com/vue#2.4.2/dist/vue.min.js"></script>
#Phil's answer is correct but in my project need to be changed. in this case, the better way is: using global components vs local components because is simple for this work.

How to get the latest data from parent to child components after page refresh

I am working on a project and using Vue.js for the frontend. I have following code in the main.js file.
new Vue({ // eslint-disable-line no-new
//el: '#app',
router,
data () {
return {
friends: []
}
},
methods: {
getFriends: function () {
return this.friends;
}
},
created: function () {
this.$http.get('/user/' + this.getUserIDCookie('userID') +
'/friends').then(function (response) {
this.friends = response.data;
});
},
components: {
'nav-bar': require('./components/Navigation.vue')
},
template: `
<div id="app">
<nav-bar></nav-bar>
<router-view class="router-view"></router-view>
</div>`
}).$mount('#app');
In one of the pages(for ex. when the page is redirected to localhost/#/user/1/details, I am retrieving the friends' list from main.js like below:
<script type="text/babel">
export default {
name: 'profile',
data: function () {
return {
user: {},
friends: []
}
},
methods: {
// Some methods
},
created: function () {
this.friends = this.$root.getFriends();
}
}
</script>
The problem arises when I refresh the current page. After page refresh, this.friends is null/undefined because this.$root.getFriends() is returning null/undefined. I can move it to user component, but I want to keep it in main.js so that GET call is used once and data will be available to the whole application.
Any input regarding how to solve this issue would be great. I am using Vue 2.0.1
Really, what you want to do, is pass the data the component needs as props.
The dirt simple easiest way to do it is this.
<router-view class="router-view" :friends="friends"></router-view>
And in your profile component,
export default {
props:["friends"],
name: 'profile',
data: function () {
return {
user: {},
friends: []
}
},
methods: {
// Some methods
}
}
If you want to get more sophisticated, the later versions of VueRouter allow you to pass properties to routes in several ways.
Finally, there's always Vuex or some other state management tool if your application gets complex enough.
The problem is that when you refresh the page, the whole app reloads, which includes the get, which is asynchronous. The router figures out that it needs to render details, so that component loads, and calls getFriends, but the asynchronous get hasn't finished.
You could work around this by saving and pulling the Promise from the get, but Bert's answer is correct: the Vue Way is to send data as props, not to have children pull it from parents.

Language in VueJS from JSON

I am trying to load locale language variables from a JSON Request (laravel generated) to VueJS since VueJS does not support locale out of the box. The ready function alert does not alert but the random text data variable does work. I know VueJS is loading correctly. There are no console errors and webpack compiles the vue. The lang array says empty and the lang.email shows blank. This is my issue. Any help appreciated.
const app = new Vue({
el: '#app',
data: {
lang: [],
randomtext: 'This is Random Text'
},
ready: function() {
alert('THIS DOES NOT ALERT');
this.getLanguage();
},
methods: {
getLanguage: function() {
this.$http.get('/lang/auth').then((response) => {
this.$set("lang", response)
}, (response) => {
alert(response);
});
}
}
});
the 'lang/auth'
{"email":"Email Address","password":"Password"}
my html:
<h5 class="content-group">#{{ randomtext }}</h5> // This Works
<input type="text" class="form-control" :placeholder="lang.email"> // This does not
Indeed, "ready" was deprecated in Vue.js 2
Try using "mounted" instead.
First, Change ready: into mounted:
(Because, vuejs version 2 doesn't support it anymore)
Second, Instead of using this.$set use this.lang = response
Here is the full code
https://jsfiddle.net/uqp7f4zL/

How to call a vue.js function on page load

I have a function that helps filter data. I am using v-on:change when a user changes the selection but I also need the function to be called even before the user selects the data. I have done the same with AngularJS previously using ng-init but I understand that there is no such a directive in vue.js
This is my function:
getUnits: function () {
var input = {block: this.block, floor: this.floor, unit_type: this.unit_type, status: this.status};
this.$http.post('/admin/units', input).then(function (response) {
console.log(response.data);
this.units = response.data;
}, function (response) {
console.log(response)
});
}
In the blade file I use blade forms to perform the filters:
<div class="large-2 columns">
{!! Form::select('floor', $floors,null, ['class'=>'form-control', 'placeholder'=>'All Floors', 'v-model'=>'floor', 'v-on:change'=>'getUnits()' ]) !!}
</div>
<div class="large-3 columns">
{!! Form::select('unit_type', $unit_types,null, ['class'=>'form-control', 'placeholder'=>'All Unit Types', 'v-model'=>'unit_type', 'v-on:change'=>'getUnits()' ]) !!}
</div>
This works fine when I select a specific item. Then if I click on all lets say all floors, it works. What I need is when the page is loaded, it calls the getUnits method which will perform the $http.post with empty input. In the backend I have handled the request in a way that if the input is empty it will give all the data.
How can I do this in vuejs2?
My Code: http://jsfiddle.net/q83bnLrx
You can call this function in the beforeMount section of a Vue component: like following:
// .....
methods: {
getUnits: function() { /* ... */ }
},
beforeMount() {
this.getUnits()
},
// ......
Working fiddle: https://jsfiddle.net/q83bnLrx/1/
There are different lifecycle hooks Vue provide:
I have listed few are :
beforeCreate: Called synchronously after the instance has just been initialized, before data observation and event/watcher setup.
created: Called synchronously after the instance is created. At this stage, the instance has finished processing the options which means the following have been set up: data observation, computed properties, methods, watch/event callbacks. However, the mounting phase has not been started, and the $el property will not be available yet.
beforeMount: Called right before the mounting begins: the render function is about to be called for the first time.
mounted: Called after the instance has just been mounted where el is replaced by the newly created vm.$el.
beforeUpdate: Called when the data changes, before the virtual DOM is re-rendered and patched.
updated: Called after a data change causes the virtual DOM to be re-rendered and patched.
You can have a look at complete list here.
You can choose which hook is most suitable to you and hook it to call you function like the sample code provided above.
You need to do something like this (If you want to call the method on page load):
new Vue({
// ...
methods:{
getUnits: function() {...}
},
created: function(){
this.getUnits()
}
});
you can also do this using mounted
https://v2.vuejs.org/v2/guide/migration.html#ready-replaced
....
methods:{
getUnits: function() {...}
},
mounted: function(){
this.$nextTick(this.getUnits)
}
....
Beware that when the mounted event is fired on a component, not all Vue components are replaced yet, so the DOM may not be final yet.
To really simulate the DOM onload event, i.e. to fire after the DOM is ready but before the page is drawn, use vm.$nextTick from inside mounted:
mounted: function () {
this.$nextTick(function () {
// Will be executed when the DOM is ready
})
}
If you get data in array you can do like below. It's worked for me
<template>
{{ id }}
</template>
<script>
import axios from "axios";
export default {
name: 'HelloWorld',
data () {
return {
id: "",
}
},
mounted() {
axios({ method: "GET", "url": "https://localhost:42/api/getdata" }).then(result => {
console.log(result.data[0].LoginId);
this.id = result.data[0].LoginId;
}, error => {
console.error(error);
});
},
</script>
methods: {
methodName() {
fetch("url").then(async(response) => {
if (response.status === 200) {
const data = await response.json();
this.xy = data.data;
console.log("Success load");
}
})
}
}
you can do it using created() method. it will fire once page fully loaded.
created:function(){
this.fillEditForm();
},

Categories