Vue.js re-render static content - vue.js

I'm new with Vue.js, and I notice some content re-render after changing any data that is not part of that content, here is an example:
https://jsfiddle.net/gustavompons/rtxqhyv2/1/
HTML
<div id="app">
<input v-model="foo1">
<div v-html="showFoo1()"></div>
<div v-html="showFoo2()"></div>
</div>
JS
new Vue({
el: '#app',
data: {
foo1: 'foo1',
foo2: 'foo2'
},
methods: {
showFoo1 () {
console.log('this is ok to execute on input')
return this.foo1
},
showFoo2 () {
console.log('this should NOT execute on input')
return this.foo2
}
}
})
So every time I type on the input, I get "this should NOT re-render on input" in the console, which I think it's not ok because there is no reason to execute that piece of code every time.
Is this the way Vue work or am I doing something wrong?
I'm using vue.js v2

The results of methods are not cached and will be executed every time the component is re-rendered. If you want caching and dependency tracking, use computed properties instead:
computed: {
showFoo1 () {
console.log('this is ok to execute on input')
return this.foo1
},
showFoo2 () {
console.log('this should NOT execute on input')
return this.foo2
}
}
And get rid of the () when accessing them.

Related

Problem with rendering data and heavy data loading

The first problem is that when getDetails(‘multiple’, ‘2’) function is called inside HTML, it takes some time until de data is displayed from v-for.
The second problem is that when I call the console.log(userDetails) from inside of anotherFunction() I got the undefined answer. It doesn’t wait for the this.getDetails(‘multiple’, ‘1’) to execute completely.
How can I improve the time for rendering, or should I use another way to display de data?
How can I make the second function to wait until the first function is complete?
VUE version: 2.7.10
<div id="app">
<p v-for="item in userDetails">item is displayed</p> //
<button #click="anotherFunction()">Click Me!</button>
</div>
<script>
export default {
name: 'App',
data: {
userDetails: []
}
}
// axios function
getDetails(actionType, idUser) {
axios.post("https://example.com/link", {
Username: username
}).then(response => {
const result = response.data;
// push data into variable
this.userDetails.push(result[0])
}).catch(error => {
this.showError('Error', 4000);
console.error('Error:' + error);
});
// another function from where I want to call the axios function
anotherFunction() {
this.getDetails('multiple', '1')
// call the userDetails into another function will output "undefined"
console.log(this.userDetails);
}

Vue 3 data is not updating after change triggered in methods

I am trying to understand Vue 3 data management for Shopify Theme. After going through my old code which is based on Vue 2, I cannot update the data object by changing value in methods function.
Below is the snippet with issue.
Vue.createApp({
delimiters: ['${', '}'],//for NO CONFLICT with liquid theme
data: () => {
return {
message: 'Hello Vue'
}
}, //data ends
methods: {
setMessage: (params) => {
//setting new message
this.message = params;
}
}, //methods ends
}).mount('#app1')
<script src="https://unpkg.com/vue#3.2.31/dist/vue.global.js"></script>
<div id="app1">
<h5>${ message }</h5>
<button v-on:click="setMessage('new message')">Submit</button>
</div>
Define method like this setMessage(params) { not like this setMessage: (params) => {

Accessing data inside a render function of a functional vuejs component

I'm trying to use a functional component to render multiple elements without having to have a single root element but I can't seem to have access to the component data, see this simplified example:
Trying to access context.data logs an empty object {}:
<div id="app">
<hello />
</div>
Vue.component('hello', {
functional: true,
render: function(h, context) {
console.log(context.data) // This logs {}
return new Array(5).fill(1).map((_, index) => h('p', {}, 'Hello world'))
},
data () {
return {
foo: 'bar'
}
}
})
new Vue({
el: '#app',
data: function() {
return {
foo: '<p>foo</p>',
bar: 'bar'
}
}
})
A working jsfiddle
Thanks in advance
A functional component has no data which is why it does not receive data in the context. You can find additional information in this section of the manual
If you want to render a component without having to use a single root element you might want to give vue-fragment a try.

Vue.js - set slot content programmatically

is there any way how can I set/override slot's content from inside the component? Like
Template:
<div>
<slot></slot>
</div>
JS:
export default {
...
mounted() {
this.$slot.render("<button>OK</button>");
}
...
}
I know I can use v-html on my element to dynamically push content into component template, but I mean not just pure HTML I mean HTML with Vue directives. Like:
JS:
export default {
...
mounted() {
this.$slot.default.render('<button #click="submit">OK</button>');
},
methods: {
submit() {
// Here I want to get :)
}
}
...
}
Basically I want Vue to render (like parse and render, not like innerHTML) certain string in scope of my component and put in on certain spot in my component. The reason is I get the new content from server via AJAX.
I'm sorry but I can't still get my head around after 2 days of googling.
Thanks a lot!
According to this you can instantiate a component programmatically and insert slot content as well.
import Button from 'Button.vue'
import Vue from 'vue'
var ComponentClass = Vue.extend(Button)
var instance = new ComponentClass({
propsData: { type: 'primary' }
})
instance.$slots.default = [ 'Click me!' ]
instance.$mount() // pass nothing
this.$refs.container.appendChild(instance.$el)
I think this is your best chance: building your component on the fly.
Here in the example I use a simple placeholder (with v-cloak).
You may obtain a better result using vue-router to add your newly created component during the execution, with router.addRoutes so your app doesn't have to wait to instantiate the whole vue.
function componentFactory(slot) {
return new Promise((resolve, reject) => {
window.setTimeout(() => { // Asynchronous fetching
resolve({ // Return the actual component
template: `<div>
${slot}
</div>`,
methods: {
submit() {
console.log('hello');
}
}
});
}, 1000);
});
}
componentFactory('<button #click="submit">OK</button>') // Build the component
.then(component => {
new Vue({ // Instantiate vue
el: '#app',
components: {
builtComponent: component
}
});
});
[v-cloak], .placeholder {
display: none;
}
[v-cloak] + .placeholder {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<div id='app' v-cloak>
<built-component></built-component>
</div>
<div class="placeholder">
This is a placeholder, my vue app is loading...
</div>

Vue.js - Keep Alive Component - Error next Tick

Description
I'm trying to take advantage of the keep-alive functionality of vue-js 2.3 so my AJAX call is made only once.
Problem
The second time I try to open the popup component I get this error :
Error in nextTick: "TypeError: Cannot read property 'insert' of undefined"
TypeError: Cannot read property 'insert' of undefined
Steps
Click on the button to display the popup
Wait for one second
Close the popup
Click again on the button
https://jsfiddle.net/4fwphqhv/
Minimal reproduction example
<div id="app">
<button #click="showDialog = true">Show Component PopUp</button>
<keep-alive>
<popup v-if="showDialog" :show-dialog.sync="showDialog"></popup>
</keep-alive>
</div>
<template id="popup">
<el-dialog :visible.sync="show" #visible-change="updateShowDialog">{{asyncData}}</el-dialog>
</template>
Vue.component('popup', {
template: '#popup',
props : ['showDialog'],
data(){
return {
show: this.showDialog,
asyncData: "Loading please wait"
}
},
methods: {
updateShowDialog(isVisible) {
if (isVisible) return false;
this.$emit('update:showDialog', false )
}
},
created:function (){
const _this = this
setTimeout(() => _this.asyncData = 'Async Data was loaded' , 1000)
},
});
var vm = new Vue({
el: '#app',
data: {
showDialog: false,
},
});
Real code of the popup component
<template>
<el-dialog title="Order in progress" size="large" :visible.sync="show" #visible-change="updateShowLoadOrder"></el-dialog>
</template>
<script>
let popUpData;
export default {
name: '',
data () {
return {
ordersInProgress: [],
show: this.showLoadOrder
}
},
props: ['showLoadOrder'],
methods: {
updateShowLoadOrder (isVisible) {
if (isVisible) return false;
this.$emit('update:showLoadOrder', false)
}
},
created () {
const _this = this;
if (!popUpData) {
axios.get('api/mtm/apiGetOrdersInProgress').then((response) => {
_this.ordersInProgress = popUpData = response.data;
});
} else {
this.ordersInProgress = popUpData;
}
}
}
</script>
Ok. So your problem here is the wrong life-cycle hook.
If you change created to activated... it should work. It did for me in your JS fiddle.
activated:function (){
setTimeout(() => this.asyncData = 'Async Data was loaded' , 1000)
}
There are two other hooks, activated and deactivated. These are for keep-alive components, a topic that is outside the scope of this article. Suffice it to say that they allow you to detect when a component that is wrapped in a tag is toggled on or off. You might use them to fetch data for your component or handle state changes, effectively behaving as created and beforeDestroy without the need to do a full component rebuild.
SOURCE: here