Vue v-if not affect to Dom when using interval - javascript

I'm trying to make polling with setInterval and rendering some element conditionally with Vue. But it's not working, so I set my data to true but on DOM nothing happened.
P.S: I'm using Vue.js with CDN so my app not created with VueCLI.
here is my HTML:
<div id="app">
<div class="container">
<h1 v-if="showtext">
text
</h1>
</div>
</div>
here is my script. When coming response with status 200, my data it's switching to true. I can see it on console but my text not rendering on DOM.
var app = new Vue({
el: "#app",
data: {
polling: null,
showtext: false
},
methods: {
pollData() {
this.polling = setInterval(() => {
axios({
method: "get",
url: "https://jsonplaceholder.typicode.com/comments"
}).then(function(response) {
console.log(response);
if (response.status == 200) {
this.showtext = true
}
console.log(this.showtext)
});
}, 7000);
}
},
beforeDestroy() {
clearInterval(this.polling);
},
created() {
this.pollData();
},
});

You should use an arrow function like in order to get access to the vue instance scope:
then((response)=> { ...
or assign this to a global variable as follows (this works with old browsers) :
var that=this; ///<------
axios({
method: "get",
url: "https://jsonplaceholder.typicode.com/comments"
}).then(function(response) {
console.log(response);
if (response.status == 200) {
that.showtext = true
}
console.log(that.showtext)
});
Full running example :
Vue.config.devtools = false;
Vue.config.productionTip = false;
var app = new Vue({
el: "#app",
data() {
return{
polling: null,
showtext:false
}
},
methods: {
pollData() {
this.polling = setInterval(() => {
axios({
method: "get",
url: "https://jsonplaceholder.typicode.com/comments"
}).then((response)=> {
if (response.status == 200) {
this.showtext = true
}
console.log(this.showtext)
});
}, 4000);
}
},
beforeDestroy() {
clearInterval(this.polling);
},
created() {
this.pollData();
},
});
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://unpkg.com/vue-axios#2.1.4/dist/vue-axios.min.js"></script>
<div id="app">
<div class="container">
test:
<h1 v-if="showtext">
text
</h1>
</div>
</div>

// You have lost context in this function, use arrow function instead
.then(function(response) {
console.log(response);
if (response.status == 200) {
this.showtext = true
}
console.log(this.showtext)
});
Something like this:
.then(response => {
console.log(response);
if (response.status == 200) {
this.showtext = true
}
console.log(this.showtext)
});

Why my text is not getting rendered ?
because this.showtext that you see on the console is not the one on your $data object ... it's a globlal variable window.showtext because the this bidden to then is window .
solution:
you have to bind your vue instance this instead to your then :
you can do it by using:
then((response) => {}) (which binds this implicitly)
or :
then((function(response) { ... }).bind(this) )

Related

Vue data() is unavailable in events when using #microsoft/fetch-event-source for Server Sent Events

I'm trying to use fetchEventSource (from #microsoft/fetch-event-source) to process Server Sent Events for streaming data to the client. It works, in that the data is returned and I can log it to the console, but when I try to update my vue data in the onmessage event, I get the error:
TypeError: Cannot set properties of undefined (setting 'messages')
Any thoughts on the best way to get this working?
Basic test template:
<template>
<div>
<p>
<label>Message</label><br />
<textarea id="messages" v-model="messages"></textarea><br />
<button #click="getMessage">GET</button>
</p>
</div>
</template>
and the script:
import { fetchEventSource } from "#microsoft/fetch-event-source";
export default {
data() {
return {
messages: "",
};
},
mounted() {
this.messages = "initialized"; // this works
},
methods: {
getMessage() {
fetchEventSource("url-here", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
onmessage(msg) {
console.log("message", msg.data); // this works - data is here!
this.messages = msg.data; // this returns the error
},
});
},
},
};
You can try with arrow function or like :
getMessage() {
const self = this
fetchEventSource("url-here", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
onmessage(msg) {
console.log("message", msg.data); // this works - data is here!
self.messages = msg.data; // this returns the error
},
});
},

Set data from method in vuejs

I am trying to set an data from a method. I am using fetch to get an rest data. But, when I try to set the data, using this.item = 'test' doesn't work. So, when my this.item is inside ".then" doesn't working. But when is out of ".then" it working... But I need to use a rest call to get the data...
Vue.component('internal_menu', {
props: ['list'],
data: function () {
return {
item: '1'
}
},
methods: {
teste(event)
{
event.preventDefault();
var payload = {
method: 'GET',
headers: { "Accept": "application/json; odata=verbose" },
credentials: 'same-origin' // or credentials: 'include'
}
const url = _spPageContextInfo.webAbsoluteUrl +
"/_api/Web/Lists/GetByTitle('"+ this.list +"')/Items?
$select=Title,Id,Link,Icone&$orderby=Title%20asc";
fetch(url,payload)
.then((resp) => resp.json())
.then(function(data)
{
let items = data.d.results;
this.item = 'teste';// this not working here
})
. catch(function(error) {
console.log(JSON.stringify(error));
});
this.item = 'tst123'; //this working here
},
},
template: `
<div id='tst'>
<h3>{{list}} - {{item}}</h3>
<button v-on:click="teste">Try Me</button>
</div>
`,
mounted: function () {
this.getMenuData();
}
})
new Vue({
el: "#app"
})
thanks
Everton
When you do this:
.then(function(data)
{
let items = data.d.results;
this.item = 'teste';// this not working here
})
Your closure's reference to this is the within the context of the anonymous function. Instead, you need to use the fat arrow function in order to maintain the context of the Component.
.then((data) => {
let items = data.d.results;
this.item = 'test';
})

Fetch data with Vue from Web API

I have a Web API and I'm trying to get JSON Data from it by using Vue, but I get neither data or errors, so I don't what is wrong. I want to load the data when the page is loaded.
Here is my code:
const v = new Vue({
el: '#divContent',
ready: function () {
this.loadData();
},
data: {
content: 'loading',
serverData: null
},
methods: {
loadData: function (viewerUserId, posterUserId) {
const that = this;
$.ajax({
contentType: "application/json",
dataType: "json",
url: "http://my-webapi/",
method: "Post",
success: function (response) {
that.$data.serverData = response;
},
error: function () {
alert('Error')
}
});
}
}
});
My HTML
<div id="divContent" class="content">
{{ content }}
</div>
Yes you can use jQuery’s $.ajax() API. However, using jQuery just for making Ajax calls is not recommended. You don’t want to include the whole jQuery library just for the purpose of using Ajax, do you? :-)
For Vue.js, you have quite a few options for using Ajax, such as:
Axios
vue-resource
Browser's built-in fetch API (Using fetch)
Here is an example of using the Browser's fetch API.
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
</head>
<body>
<div id="divContent">
<h1>Article Search Results</h1>
<form v-on:submit.prevent="search">
<input type="text" v-model="query">
<button type="submit">Search</button>
</form>
<ul>
<li v-for="article in articles" v-bind:key="article.source + article.id">
{{ article.title }}
</li>
</ul>
</div>
</body>
</html>
JavaScript
const vm = new Vue({
el: '#divContent',
data() {
return {
query: 'gene',
articles: 'loading'
}
},
created() {
this.search();
},
methods: {
search: function () {
fetch(`https://www.ebi.ac.uk/europepmc/webservices/rest/search?query=${this.query}&format=json`)
.then(response => response.json())
.then(json => {
this.articles = json.resultList.result;
});
}
}
});
Output
You appear to already be using jQuery, so to load the Vue when the page is loaded you can update your code to the following:
$(function(){
const v = new Vue({
el: '#divContent',
created: function () {
this.loadData();
},
data: {
content: 'loading',
serverData: null
},
methods: {
loadData: function (viewerUserId, posterUserId) {
const that = this;
$.ajax({
contentType: "application/json",
dataType: "json",
url: "http://my-webapi/",
method: "Post",
success: response => this.serverData = response,
error: err => alert('Error')
});
}
}
});
})
The syntax above is using the jQuery.ready shorthand to create the Vue only after the page is loaded.
Without jQuery, you might want to listen for the DOMContentLoaded event.
Alternatively, just load the script that creates the Vue at the bottom of the page and not in the header.
Here is a complete, working example.
console.clear()
$(function(){
const v = new Vue({
el: '#divContent',
created: function () {
this.loadData();
},
data: {
content: 'loading',
serverData: null
},
methods: {
loadData: function (viewerUserId, posterUserId) {
$.ajax({
contentType: "application/json",
dataType: "json",
url: "https://httpbin.org/post",
data: JSON.stringify({testing: "some value"}),
method: "Post",
success: response => {
this.content = "loaded"
this.serverData = response.json
},
error: err => console.log('Error')
});
}
}
});
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.9/vue.js"></script>
<div id="divContent" class="content">
{{ content }}
<hr>
Response: <br>
{{ serverData }}
</div>
Anything your put inside methods: {} won't work
unless you call loadData() with #click on the element or when page loads.
So, you should call it on the element or using either created/mount methods:
So, in your case either do this.
<div id="divContent" class="content" #click='loadData'>
or call the method when the page loads as:
created () {
this.loadData()
}
For Loading it on the page load, you can do the following:
const v = new Vue({
el: '#divContent',
data: {
content: 'loading',
serverData: null
},
methods: {
loadData(viewerUserId, posterUserId) {
$.ajax({
contentType: "application/json",
dataType: "json",
url: "http://my-webapi/",
method: "POST",
success: function (response) {
this.content = 'loaded';
this.serverData = response;
},
error: function () {
alert('Error')
}
});
}
},
mounted() {
this.loadData()
}
});

Property or method "orgs" is not defined on the instance but referenced

I am using vue2 and I am trying to fetch an api and render the contents in my page, this is all done in my Orgs.vue file and here is the code:
<template lang="html">
<div class="">
{{ orgs | json }}
</div>
</template>
<script>
export default {
data: {
orgs: false
},
created() {
request = axios({
url: 'https://....',
method: 'GET',
})
.then(function(response) {
this.orgs = response;
})
.catch(function(error) {
console.log('error getting orgs::', error);
});
}
};
</script>
<style lang="css">
</style>
However everytime I run the page I get this error:
Property or method "orgs" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option. found in Orgs.vue
I tried to change
data: {
orgs: false
},
to
data() {
return {orgs: false}
},
but the error is still there
You need save vue instance reference in variable before making request and use it to access vue in response handler. I used vue_instance in example.
And for components init data as function.
data: function() {
return {
orgs: false
}
},
created() {
var vue_instance = this;
request = axios({
url: 'https://....',
method: 'GET',
})
.then(function(response) {
vue_instance.orgs = response.data;
})
.catch(function(error) {
console.log('error getting orgs::', error);
});
}
EDIT: In axios response handler this is reference on window. Axios don't know anything about vue.

Changing Vue.js example to use ajax

Im using Vue.js in my latest project and in part of the project i need to render a tree view which is stored in a db - Im using the Vue.js tree view example as a base and have the data coming from my server in the correct format.
Ive found a way to modify the example to load the data from js but by the time it does, the component has already been rendered. Ive checked that the data works when I preload a var with the data from the server.
How would I change things to make this load from ajax?
My js:
Vue.component('item', {
template: '#item-template',
props: {
model: Object
},
data: function() {
return {
open: false
}
},
computed: {
isFolder: function() {
return this.model.children && this.model.children.length
}
},
methods: {
toggle: function() {
if (this.isFolder) {
this.open = !this.open
}
},
changeType: function() {
if (!this.isFolder) {
Vue.set(this.model, 'children', [])
this.addChild()
this.open = true
}
}
}
})
var demo = new Vue({
el: '#demo',
data: {
treeData: {}
},
ready: function() {
this.fetchData();
},
methods: {
fetchData: function() {
$.ajax({
url: 'http://example.com/api/categories/channel/treejson',
type: 'get',
dataType: 'json',
async: false,
success: function(data) {
var self = this;
self.treeData = data;
}
});
}
}
})
the template :
<script type="text/x-template" id="item-template">
<li>
<div
:class="{bold: isFolder}"
#click="toggle"
#dblclick="changeType">
#{{model.name}}
<span v-if="isFolder">[#{{open ? '-' : '+'}}]</span>
</div>
<ul v-show="open" v-if="isFolder">
<item
class="item"
v-for="model in model.children"
:model="model">
</item>
</ul>
</li>
</script>
And the html:
<ul id="demo">
<item
class="item"
:model="treeData">
</item>
</ul>
The problem is in the $.ajax() call. The value of self in the success handler has the wrong value
success: function(data) {
var self = this; // this = jqXHR object
self.treeData = data;
}
Either use the context option and this.treeData
$.ajax({
url: 'http://example.com/api/categories/channel/treejson',
type: 'get',
context: this, // tells jQuery to use the current context as the context of the success handler
dataType: 'json',
async: false,
success: function (data) {
this.treeData = data;
}
});
Or move the var self = this line in the correct place right before $.ajax();
fetchData: function () {
var self = this;
$.ajax({
url: 'http://example.com/api/categories/channel/treejson',
type: 'get',
dataType: 'json',
async: false,
success: function (data) {
self.treeData = data;
}
});
}

Categories

Resources