modifying data variable in vue.js using axios - javascript

Here is my script :
<html>
<script src="https://unpkg.com/vue"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.17.0/axios.js"></script>
<body>
<div id="app-3">
<span v-if="seen">{{ textFromApi }}</span>
</div>
<br/>
<script type="text/javascript">
var app3 = new Vue({
el: '#app-3',
data: {
seen: true,
textFromApi: "hello"
},
methods: {
getData() {
return axios.get('https://jsonplaceholder.typicode.com/posts/1')
},
},
created: function () {
this.textFromApi = this.getData();
}
})
</script>
</body>
</html>
I'm trying to modify this.textFromApi from the call of this api: https://jsonplaceholder.typicode.com/posts/1
but my this.textFromApi doesn't seems to update, any ideas why?
Here is a fiddle code:
https://jsfiddle.net/bussiere/5t3v013o/
Edited from remark just below
Regards and thanks

created() is a lifecycle hook, it should be at the same level as data, methods, computed etc. Not a child of methods (so if you nest created() in methods() it will never get executed unless you call the method).
You also don't do anything with the axios promise, you should process it using then ().
<script src="https://unpkg.com/vue"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.17.0/axios.js"></script>
<body>
<div id="app-3">
<span v-if="seen">{{ textFromApi }}</span>
</div>
<br/>
<script type="text/javascript">
var app3 = new Vue({
el: '#app-3',
data () {
return {
seen: true,
textFromApi: { title: 'empty'}
}
},
methods: {
getData() {
return axios.get('https://jsonplaceholder.typicode.com/posts/1').then(response => {
this.textFromApi = response.data
})
},
},
created: function () {
this.getData();
}
})
</script>
</body>
</html>

Related

How to insert PHP variable to Vue computed functions in Laravel blade?

I need to bind $price_php with price in this Vue object. We do not use templates and imported components in the project
<html >
<head>
<meta charset="utf-8">
<title>Laravel</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="example">
<?php $price_php = 100 ?>
<p>Price: "{{ $price_php }}"</p>
<p v-bind:price="$price_php">Computed amount: "#{{ amount }}"</p>
</div>
<script>
var vm = new Vue({
el: '#example',
data: {
quantity: 10
},
// props: ['price'],
computed: {
amount: function () {
return price*this.quantity
}
}
})
</script>
I believe something like this would work for you.
<script>
var vm = new Vue({
el: '#example',
data: {
quantity: 10,
price: <?php echo $price_php; ?>,
},
// props: ['price'],
computed: {
amount: function () {
return this.price*this.quantity
}
}
})
</script>
Reference of Idea: See "Rendering JSON" subheading on https://laravel.com/docs/7.x/blade#displaying-data

MathJax not always rendering with Vue filtered list

I'm trying to build a filtered list in Vue with equations rendered with MathJax, and it seems to be having some problems, since the equations renders on the first load, but when I search for terms, some equations render and some don't, I can't understand why.
Basically on the first load, if I type a character in my search bar, everything renders correctly, but when I search more, or erase it and do it again, it doesn't, as you can see in these images:
my Vue code is as follows:
var analisiMatematica = new Vue({
el: '#searcher',
data: {
searchQuery: '',
isResult: false,
results: [],
//json: 'json/analisimatematica.json',
error: ''
},
mounted: function() {
axios.get('./json/analisimatematica.json')
.then(function(response) {
this.results = response.data.Domande;
console.log(this.results);
}.bind(this))
.catch(function(error) {
this.error = error.data;
console.log(error.data);
}.bind(this));
},
methods: {
removeSearchQuery: function() {
this.searchQuery = '';
this.isResult = false;
},
submitSearch: function() {
this.isResult = true;
}
},
computed: {
filteredObj: function() {
var list = [];
this.results.forEach(function(el) {
if(el.domanda.toLowerCase().indexOf(this.searchQuery.toLowerCase()) > -1) {
list.push(el);
}
}.bind(this))
return list;
}
}
});
MathJax is loaded in my html file's <head> like this:
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {
inlineMath: [ ['$','$'], ["\\(","\\)"] ],
}
});
</script>
<script type="text/javascript" async
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/latest.js?config=TeX-MML-AM_CHTML">
</script>
While the vue app section is like this:
<div id="searcher">
<p v-show="error" v-html="error"></p>
<form class="searchForm" v-on:submit.prevent="submitSearch">
<input type="text" name="queryInput" v-model="searchQuery" placeholder="Che domanda cerchi?" #keyup="submitSearch">
<span v-show="searchQuery" class="removeInput" #click="removeSearchQuery">+</span>
</form>
<div class="results" v-show="isResult">
<ul>
<li v-for="result in filteredObj">
<p id="domanda">{{ result.domanda }}</p>
<p id="risposta">{{ result.risposta }}</p>
</li>
</ul>
</div>
</div>
All you need is to trigger MathJax to render again when filteredObj is changed. Watch filteredObj:
watch: {
filteredObj: function () {
if ('MathJax' in window) {
this.$nextTick(function() {
MathJax.Hub.Queue(["Typeset",MathJax.Hub, document.body])
});
}
}
}
var analisiMatematica = new Vue({
el: '#searcher',
data: {
searchQuery: '',
isResult: false,
results: [],
//json: 'json/analisimatematica.json',
error: ''
},
mounted: function() {
this.results = [{domanda: '$a+b=c$', risposta: '$a+b=c$'}]
},
methods: {
removeSearchQuery: function() {
this.searchQuery = '';
this.isResult = false;
},
submitSearch: function() {
this.isResult = true;
}
},
computed: {
filteredObj: function() {
var list = [];
this.results.forEach(function(el) {
if(el.domanda.toLowerCase().indexOf(this.searchQuery.toLowerCase()) > -1) {
list.push(el);
}
}.bind(this))
return list;
}
},
watch: {
filteredObj: function () {
if ('MathJax' in window) {
this.$nextTick(function() {
MathJax.Hub.Queue(["Typeset",MathJax.Hub, document.body])
});
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {
inlineMath: [ ['$','$'], ["\\(","\\)"] ],
}
});
</script>
<script type="text/javascript" async
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/latest.js?config=TeX-MML-AM_CHTML">
</script>
<div id="searcher">
<p v-show="error" v-html="error"></p>
<form class="searchForm" v-on:submit.prevent="submitSearch">
<input type="text" name="queryInput" v-model="searchQuery" placeholder="Che domanda cerchi?" #keyup="submitSearch">
<span v-show="searchQuery" class="removeInput" #click="removeSearchQuery">+</span>
</form>
<div class="results" v-show="isResult">
<ul>
<li v-for="result in filteredObj">
<p id="domanda">{{ result.domanda }}</p>
<p id="risposta">{{ result.risposta }}</p>
</li>
</ul>
</div>
</div>

Use variables from other Vue instances and cross reference them

I have 2 different parts of the website
First: is it ok to use one instance in another especially with v-model, is this have any disadvantages.
Second: Is there any way I can cross reference each other, like footer in aside even though one is declared before the other. I get an error with this code. "footer is undefined"
My JS:
var aside = new Vue({
"el":"aside",
data:{
name:"Peylan"
}
});
var footer= new Vue({
"el":"footer",
data:{
companyname:"Company Inc"
}
});
My HTML
<aside><h3 v-bind="footer.companyname"></h3></aside>
<footer>
<input type="text" v-model="aside.name">
</footer>
Standard way of handling what you want is using a shared Vuex store.
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vuex"></script>
<aside><h3 v-text="footer.companyname"></h3></aside>
<footer>
<input type="text" v-model="aside.name">
</footer>
<script>
const store = new Vuex.Store({
strict: false,
state: {
aside: {
name:"Peylan"
},
footer: {
companyname:"Company Inc"
}
}
});
var aside = new Vue({
store,
"el":"aside",
data:{},
computed: {
...Vuex.mapState(['aside', 'footer'])
}
});
var footer= new Vue({
store,
"el":"footer",
data:{},
computed: {
...Vuex.mapState(['aside', 'footer'])
}
});
</script>
The demo above is a very simplified way of using it. For optimal usage (like with getters, actions and mutations) consider Vuex's official docs.
Or you can use a computed property on both, like below.
This creates a bit of a chicken and egg issue, that's why you need to use .$mount() in this case.
<script src="https://unpkg.com/vue"></script>
<aside><h3 v-text="footer.companyname"></h3>
</aside>
<footer>
<input type="text" v-model="aside.name">
</footer>
<script>
var aside = new Vue({
data:{
name:"Peylan"
},
computed: {
footer() { return footer; }
}
});
var footer = new Vue({
data:{
companyname:"Company Inc"
},
computed: {
aside() { return aside; }
}
});
aside.$mount("aside");
footer.$mount("footer");
</script>

Render the binding value in dynamic generated html template in vuejs2

For following code: I want the "test1 span" could be changed with javascript. How can I do it? NOTE: the {{msg}} maybe from ajax output.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://cdn.bootcss.com/vue/2.4.2/vue.min.js"></script>
</head>
<body>
<!-- app -->
<div id="app">
<span v-html="test"></span>
<span v-html="test1"></span>
{{test3}}
</div>
<script>
var app1 = new Vue({
el: '#app',
data: {
test: '<p style="color: red">THIS IS HTML</p>',
test1: '{{msg}}',
test3: 20,
msg: 10
}
})
function change() {
app1.msg = Math.random()
app1.test3 = Math.random()
}
setInterval(change, 2000)
</script>
</body>
</html>
Modification:
Maybe I need to make my question clear:
For next modify code, when launch the page, you will see Go to Foo link in the page, then you click the link, you will see hello {{msg}}
NOTE: this comes from the remote server: b.html.
I set a timer there, every 2 seconds, change the value of msg, I wish the {{msg}} in page could change to a random number.
main.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script>
<script src="https://cdn.bootcss.com/vue/2.4.2/vue.min.js"></script>
<script src="https://cdn.bootcss.com/vue-router/2.7.0/vue-router.min.js"></script>
</head>
<body>
<div id="app">
<p>
<router-link to="/foo">Go to Foo</router-link>
</p>
<router-view></router-view>
</div>
<script>
const Foo = {
template: '<div v-html="template1"></div>',
data: function () {
return {
template1: null
}
},
created: function () {
this.fetchData()
},
watch: {
'$route': 'fetchData'
},
methods: {
fetchData () {
var that = this
$.get("http://localhost/try/b.html", function(data, status) {
that.template1 = data
})
}
}
}
const routes = [
{ path: '/foo', component: Foo }
]
const router = new VueRouter({
routes
})
const app = new Vue({
router
}).$mount('#app')
function change() {
app.msg = Math.random()
}
setInterval(change, 2000)
</script>
</body>
</html>
b.html
<div>
hello
{{msg}}
</div>
Use the tools that Vue.js gives you. Put change() in your VM's methods object, then create a created() hook that sets up the interval.
Please note that v-html expects a String, not a Number, so just add .toString() when generating the random number.
var app1 = new Vue({
el: '#app',
data: {
test: '<p style="color: red">THIS IS HTML</p>',
test1: null,
test3: 20,
msg: 10
},
watch: {
msg: function(newVal, oldVal) {
this.test1 = newVal
}
},
methods: {
change() {
this.msg = Math.random().toString()
this.test3 = Math.random()
}
},
created() {
setInterval(this.change, 2000)
}
})
<script src="https://cdn.bootcss.com/vue/2.4.2/vue.min.js"></script>
<div id="app">
<span v-html="test"></span>
<span v-html="test1"></span>
{{ test3 }}
</div>
Instead of a watcher it is even easier to go for a computed property instead.
var app1 = new Vue({
el: '#app',
data: {
test: '<p style="color: red">THIS IS HTML</p>',
test3: 20,
msg: 10
},
computed: {
test1() {
return this.msg.toString()
}
},
methods: {
change() {
this.msg = Math.random()
this.test3 = Math.random()
}
},
created() {
setInterval(this.change, 2000)
}
})
<script src="https://cdn.bootcss.com/vue/2.4.2/vue.min.js"></script>
<div id="app">
<span v-html="test"></span>
<span v-html="test1"></span>
{{ test3 }}
</div>
Use v-model instead of v-html :-
var app1 = new Vue({
el: '#app',
data: {
test: '<p style="color: red">THIS IS HTML</p>',
test1: '{{msg}}',
test3: 20,
msg: 10
}
})
function change() {
app1.msg = Math.random()
app1.test3 = Math.random()
}
setInterval(change, 2000)
<script src="https://cdn.bootcss.com/vue/2.4.2/vue.min.js"></script>
<div id="app">
<span v-html="test"></span>
<span v-model="test1">{{msg}}</span>
{{test3}}
</div>
Finally I get the answer from here
Vue.compile( template )
this will make the template from remote server be parsed again by vuejs.
main.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script>
<script src="https://cdn.bootcss.com/vue/2.4.2/vue.min.js"></script>
<script src="https://cdn.bootcss.com/vue-router/2.7.0/vue-router.min.js"></script>
</head>
<body>
<div id="app">
<p>
<router-link to="/foo">Go to Foo</router-link>
</p>
<router-view></router-view>
</div>
<script>
const Foo = {
data: function () {
return {
template1: null,
msg: null
}
},
created: function () {
this.fetchData()
setInterval(this.change, 2000)
},
render: function(createElement) {
if (this.template1)
{
return this.template1();
}
},
methods: {
change() {
this.msg = Math.random()
},
fetchData () {
var that = this
$.get("http://localhost/try/b.html", function(data, status) {
that.template1 = Vue.compile(data).render
})
}
}
}
const routes = [
{ path: '/foo', component: Foo }
]
const router = new VueRouter({
routes
})
const app1 = new Vue({
router
}).$mount('#app')
</script>
</body>
</html>
b.html
<div>
hello
{{msg}}
</div>

Watched prop callback of a component inside a v-if statement is not called

I have a component, "cmptest", which have a watched property, "needWatch".
This component is inside a v-if statement, but the watched function is not called when it is rendered.
As shown in the example, the "needWatch" prop is setted with "value" data property from "cmpcheck", what makes me expect that the watch callback should be fired here.
If I remove the v-if statement, the function is called as expected when the checkbox is clicked.
<div v-if="value===true"><!--remove-->
<cmptest :need-watch="value"></cmptest>
</div><!--remove-->
Is this by design? What am I doing wrong here?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue Example</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="vue.js"></script>
<script type="text/x-template" id="cmptesttemplate">
<div>
<p>needWatch: {{needWatch}}</p>
<p>updateByWatch: {{updateByWatch}}</p>
</div>
</script>
<script type="text/x-template" id="cmpchecktemplate">
<div>
<input id="checkBox" type="checkbox" value="1" v-on:click="setCheckboxValue()">
<div v-if="value===true">
<cmptest :need-watch="value"></cmptest>
</div>
</div>
</script>
</head>
<body>
<div id="container">
<cmpcheck></cmpcheck>
</div>
<script>
var cmptest = Vue.component('cmptest', {
template: '#cmptesttemplate',
data: function() {
return {
updateByWatch: ''
}
},
props: ['needWatch'],
watch: {
needWatch: function(v) {
console.log('Watched!');
this.updateByWatch = Math.random();
}
}
});
var cmpcheck = Vue.component('cmpcheck', {
template: '#cmpchecktemplate',
data: function() {
return {
value: 'Unitialized'
};
},
methods: {
setCheckboxValue: function() {
console.log('SELECTED');
var el = $(this.$el).children('#checkBox').is(':checked');
this.value = el;
}
}
});
new Vue({
el: '#container',
components: {
'cmptest': cmptest,
'cmpcheck': cmpcheck
}
});
</script>
</body>
</html>
Well, as long as value is Unitialized (thus, not true), <cmptest :need-watch="value"></cmptest> will never be rendered, so the watcher does not actually exist. Once setCheckboxValue is called, if value is true, the cmptest will be rendered and then the watcher initialized. But value is already true, so it's not triggered.
However, you can use:
watch: {
needWatch: {
immediate: true,
handler(nv, ov) { ... }
}
}
so that your watcher callback runs when needWatch is initiated.

Categories

Resources