Vuejs does not render data from ajax - vuejs2

I use jQuery ajax to request api and get the respone, but the data cannot be rendered. Does someone know how to fix this problem?
var app = new Vue({
//router,
data: {
people: null
},
created: function() {
$.ajax({
url: 'test.php',
}).done(function(res){
console.log(res);
this.people = JSON.parse(res);
//console.log('124234234523');
//console.log(this.people.name);
});
}
}).$mount('#app');
<div id="app">
<ol>
<li v-for="person in people">
{{ person.name }}
</li>
</ol>
</div>
Code use vue router:
While I use Vue router, even I use arrow function. The template cannot be render by Vue. Whether do I misuse Vue router?
// Listing people component
var PeopleListing = Vue.extend({
template: '#people-listing-template',
data: function() {
return {
people: this.$parent.people
}
}
});
// Create the router
var router = new VueRouter({
mode: 'hash',
base: window.location.href,
routes: [
{path: '#/', component: PeopleListing},
{name: 'person', path: '/:id', component: PersonDetail }
]
});
var app = new Vue({
router,
data: {
people: null
},
created: function() {
$.ajax({
url: 'test.php',
}).done((res) =>{
//console.log(res);
this.people = JSON.parse(res);
//console.log('124234234523');
//console.log(this.people.name);
});
}
}).$mount('#app');
<div id="app">
<router-view class="view"></router-view>
</div>
<template id="people-listing-template">
<ul>
<li v-for="person in people">
{{ person.name }}
<router-link :to="{ name: 'person', params: { id: person.guid }}">View Details</router-link>
</li>
</ul>
</template>

Scope of this is creating issue, use arrow function like following:
var app = new Vue({
//router,
data: {
people: null
},
created: function() {
$.ajax({
url: 'test.php',
}).done((res) => {
console.log(res);
this.people = JSON.parse(res);
//console.log('124234234523');
//console.log(this.people.name);
});
}
}).$mount('#app');
You can get more details about this issue here.

Related

how to use router-link custom navigation instead of `to` prop

<router-link to="/" tag="a" :title="title">
<span class="icon icon-home i-large" />
<span class="class-2">Name</span>
</router-link>
This is what I have...
As you can see , I am using to prop. But I don't want to use it. Whenever someone clicks on this, i want to execute a function and use programatic navigation.
How is this possible? the structure and htmls that I have shouldn't change and it still should work as expected.
Something like this you mean?
<a #click="functionThatExecutesMyCode">
<span class="icon icon-home i-large" />
<span class="class-2">Name</span>
</a>
functionThatExecutesMyCode() {
this.$router.push({ to: 'newRoute'})
}
Else you should use the navigation guards: https://router.vuejs.org/guide/advanced/navigation-guards.html
I don't think it's possible to change :to props to add a function, because it is predefined as only accept a string in its docs. https://router.vuejs.org/api/#to
However, I suggest another way to implement what you want, you can add the logic in beforeEach hook. For example
router.beforeEach( (to, from, next) => {
// implement your logic here, for example if no internet, go to error page
if (!navigator.onLine && to.name !== "NetworkError") {
next({ name: "NetworkError" });
return false;
}
next();
}
For more info, look at their docs: https://router.vuejs.org/api/#router-beforeeach
It depends on what you exactly want.
There are easier solutions, like:
const Root = {
template: '<div>Root</div>'
}
const Route1 = {
template: '<div>Route1</div>'
}
const routes = [{
path: '/',
name: 'root',
component: Root
},
{
path: '/1',
name: 'route1',
component: Route1
}
]
const router = new VueRouter({
routes // short for `routes: routes`
})
new Vue({
el: "#app",
router,
data: {
selected: 'root',
options: ['root', 'route1']
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<select v-model="selected">
<option v-for="(option, i) in options">
{{ option }}
</option>
</select>
<router-view></router-view>
<router-link :to="{ name: selected }">{{ selected }}</router-link>
</div>
In this solution I used a named route, and the "name" can be changed by the select input.
The next solution is to incorporate a function:
const Root = {
template: '<div>Root</div>'
}
const Route1 = {
template: '<div>Route1</div>'
}
const routes = [{
path: '/',
name: 'root',
component: Root
},
{
path: '/1',
name: 'route1',
component: Route1
}
]
const router = new VueRouter({
routes // short for `routes: routes`
})
new Vue({
el: "#app",
router,
data: {
selected: 'root',
options: ['root', 'route1']
},
methods: {
changeRouteName() {
return this.selected
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<select v-model="selected">
<option v-for="(option, i) in options">
{{ option }}
</option>
</select>
<router-view></router-view>
<router-link :to="{ name: changeRouteName() }">{{ selected }}</router-link>
</div>
By adding a method to resolve the name of the component, it's possible to build ANY logic on the to of the <router-link. You could also use path instead of name of course - I just like named components.
It does not remove the click event from the to prop, but you can do your logic before returning the name it's "waiting" for.

Cant store api data called by axios in array through mounted, unless clicking on <Root> element from vue devtools (in browser)

i'm using axios to get data from api and store in an array after mounting then run a search query in the array later on, but it's not working unless i click on Root element in browsers Vue developer tools, after i click on vue Root element from vue dev tool everything works fine.Here is my code..
<script type="module">
const vueApp = new Vue({
el: "#pos",
data: {
searchTerm: "",
allProducts: [],
selectedProducts: [],
suggestions: []
},
mounted: function (){
axios.get("api/products").then( res => this.allProducts = res.data );
},
methods: {
select(item){
this.selectedProducts.push(item);
this.suggestions = [];
}
},
computed:{
matches(){
if(!this.searchTerm) return;
this.suggestions = this.allProducts.filter(sP=>(sP.prod_name).includes(this.searchTerm));
}
}
});
</script>
//HTML below------------------
<div id="pos">
<input type="text" v-model="searchTerm">
<ul v-for="match in suggestions">
<li #click="select(match)">
{{match.prod_name}}
</li>
</ul>
<table>
<tr v-for="(product,i) in selectedProducts">
<td>#{{product.prod_name}}</td>
</tr>
</table>
</div>
const vueApp = new Vue({
el: "#pos",
data: {
searchTerm: "",
allProducts: [],
selectedProducts: [],
suggestions: []
},
mounted: function() {
axios.get("api/products").then(res => this.allProducts = res.data);
},
methods: {
select(item) {
this.selectedProducts.push(item);
this.suggestions = [];
}
},
computed: {
matches() {
if (!this.searchTerm) return;
this.suggestions = this.allProducts.filter(sP => (sP.prod_name).includes(this.searchTerm));
}
}
});
<div id="pos">
<input type="text" v-model="searchTerm">
<ul v-for="match in suggestions">
<li #click="select(match)">
{{match.prod_name}}
</li>
</ul>
</div>
As I mentioned in the comments on your question, this is an error I cannot seem to understand how you are getting. I sense there is information that we are not being presented with.
As such, here is a quick "working" example of fetching items from the mounted lifecycle hook in a component. Note: If you are creating the component via a Single-File Component (.vue files) then don't worry too much about the declaration, pay attention only to the data and mounted methods.
const App = Vue.component('App', {
template: `<div>
<input v-model="searchTerm" type="search">
{{items.length}} results fetched
</div>`,
data() {
return {
searchTerm: '',
items: []
}
},
mounted() {
//Timeout used to mimic axios query
setTimeout(()=> this.items= [1,2,3,4], 1000)
}
});
const app = new App({
el: '#app'
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">Placeholder</div>
Edit
The code you have given us after your update seems to be working just fine. See the below snippet.
I noticed you are looping over suggestions but that value is never updated anywhere in your given code.
const vueApp = new Vue({
el: "#pos",
data: {
searchTerm: "",
allProducts: [],
selectedProducts: [],
suggestions: []
},
mounted: function() {
setTimeout(() => this.allProducts = [1,2,3,4,5], 1000);
},
methods: {
select(item) {
this.selectedProducts.push(item);
this.suggestions = [];
}
},
computed: {
matches() {
if (!this.searchTerm) return;
this.suggestions = this.allProducts.filter(sP => (sP.prod_name).includes(this.searchTerm));
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="pos">
<input type="text" v-model="searchTerm">
<ul v-for="match in suggestions">
<li #click="select(match)">
{{match.prod_name}}
</li>
</ul>
{{allProducts.length}} results loaded
</div>
mounted: function(){
var _self = this;
axios.get("api/products").then( res => _self.allProducts = res.data );
}

match vue js routes with query string in them?

I was reading here:
https://router.vuejs.org/en/essentials/dynamic-matching.html
but it doesn't seem to let me match say:
/mycoolapp?someid=123
yes, I could do
/mycoolapp/123
but that is not the question
The question is: can I match routes dynamically with get query parameters?
You can access the query parameters, in your example someid via $route.query.someid. From $route docs:
$route.query
type: Object
An object that contains key/value pairs of the query string. For
example, for a path /foo?user=1, we get $route.query.user == 1. If
there is no query the value will be an empty object.
Demo below:
const UserList = {
template: '#users',
data() { return { users: [] } },
created() {
axios.get('https://jsonplaceholder.typicode.com/users').then(r => this.users = r.data);
}
};
const User = {
props: ['uid', 'user'],
template: '#user'
}
var router = new VueRouter({
routes: [{
path: '/',
component: UserList
},
{
path: '/user/:uid',
component: User,
name: 'user',
props: true
}]
});
var app = new Vue({
el: '#app',
router: router,
template: '<router-view></router-view>'
});
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vue-router"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<template id="users" functional>
<div>
<ul>
<li v-for="user in users">
<div>
{{ user.name }} -
<router-link :to="{name: 'user', params: {uid: user.id, user: user}, query: {field: 'email'}}">(email)</router-link> -
<router-link :to="{name: 'user', params: {uid: user.id, user: user}, query: {field: 'website'}}">(website)</router-link>
</div>
</li>
</ul>
</div>
</template>
<template id="user" functional>
<div class="row">
<b>{{ user.name }}</b><br>
{{ $route.query.field }}: {{ user[$route.query.field] }}<br>
<router-link :to="{path: '/'}">back</router-link>
</div>
</template>
<div id="app">
<p>{{ message }}</p>
</div>
On the other hand, if you want to redirect to a specific component depending on the query parameters, you can use navigation guards. For instance, beforeEach:
router.beforeEach((to, from, next) => {
if (to.query.field === 'email') {
next({path: '/email'}); // some hypothetical path
} else {
next();
}
});
vue-router uses this to handle paths
can help you find a solution
there are only a few mentions of query in the documentation
When dealing with query strings, escape the question mark (?) so it doesn't mark the parameter as optional. Handling unordered data is outside the scope of this library.
const regexp = pathToRegexp("/search/:tableName\\?useIndex=true&term=amazing");
regexp.exec("/search/people?useIndex=true&term=amazing");
//=> [ '/search/people?useIndex=true&term=amazing', 'people', index: 0, input: '/search/people?useIndex=true&term=amazing', groups: undefined ]
// This library does not handle query strings in different orders
regexp.exec("/search/people?term=amazing&useIndex=true");
//=> null
but I still couldn't make a route with a query string

Vue.js Passing Data via httpVueLoader

I have a Vue instance.
var myApp = new Vue({
el: '#my-App',
data: {
user: sessionStorage.getItem('user')
},
components: {
'header-component': httpVueLoader('./components/header-component.vue'),
'footer-component': httpVueLoader('./components/footer-component.vue')
}
});
And a single file component header-component
<template>
<li v-if="user !== ''" class="nav-item">
<a class="nav-link" v-on:click="openProfilePage" href="#">{{user}}</a>
</li>
</template>
<script>
module.exports = {
data: function () {
return {}
},
props: ['user'],
methods:
{
openProfilePage: function () {
if (userName !== '') {
myApp.page = 'profile';
sessionStorage.setItem('page', 'profile');
page = 'profile';
}
else {
myApp.page = 'login';
sessionStorage.setItem('page', 'login');
page = 'login';
}
}
}
}
</script>
I don't want to define a new data.user in my single file component and i want to use the data.user of the vue instance. How can i do that? How can i pass this data?
Pass it as you would normally pass values from parent to child; using a prop.
Here is an example.
index.html
<body>
<div id="app">
<test :user="user"></test>
</div>
<script>
new Vue({
el: '#app',
data: {
user: "This is a test string"
},
components:{
test: httpVueLoader("/Test.vue")
}
})
</script>
</body>
Test.vue
<template>
<div>{{user}}
</template>
<script>
module.exports = {
props:["user"]
}
</script>
This will pass the user defined in the Vue to the Test component and the resulting output will be "This is a test string".

How to display data in template from Vue.extend?

Here is my code:
var guestContent = Vue.extend({
template: `
<p>Guest content</p>
`,
data: function () {
return {
qs: getQuestionsContent(); // here I would like to get in qs data from function
}
}
});
Here is my App.js:
App = new Vue ({ /
el: '#app',
data: {
topMenuView: "guestmenu",
contentView: "guestcontent",
}
});
I need to display qs instead of Guest content and do for example v-for or some kind of other iteration. How can I do it?
Why:
var guestContent = Vue.extend({
template: `
<p>Guest content</p>
<p>{{foo}}</p> // foo not display
`,
data: function () {
foo: "dddddddddd";
}
});
Why is this not working?
Try something like this:
html
<body>
<guest-content></guest-content>
</body>
<template id="guest-content-template">
Guest Content
<ul>
<li v-for="question in questions">
{{question}}
</li>
</ul>
</template>
js
var guestContent = Vue.extend({
template: "#guest-content-template",
data: function (){
return {
questions: []
}
},
ready(){
this.getQuestionsContent();
},
methods:{
getQuestionsContent(){
this.questions = [
"Why?",
"What?",
"When?"
];
}
}
});
Vue.component('guest-content',guestContent);
new Vue({
el:'body'
});
Anything in a {{}} is assumed to be within the current Vue scope, so you just use foo or questions not guestContent.foo.
The data attribute is a function that has to return the data for the app. If you don't return anything, the component wont have any data.