I have some v-if props and currently to show divs with #click="tada = !tada". Instead, I would like the same divs that I'm currently triggering with the #click, to appear when the page finishes loading and occur only once.
I have tried onload, load and other things to know avail. Thanks for any help
EDIT:
I suspected it had to do with mounted but wasn't sure, so thank you for the hint.
Answer:
mounted: function () {
this.tada = true
},
You should use the mounted lifecycle hook in your main vue instance. This function is called when the component is rendered to the document for the first time. You can read more here.
Related
I am having an issue where when I change a component in my app, many unrelated components seem to be rerendering too. When I use the Vue performance timings config, I see something like (all in the span of about 200ms)
I am trying to figure out what causes these components to rerender. I saw a tip about how to tell the cause of a rerender, but when I put this snippet* in all the rerendering components, I don’t get anything logged to the console.
So, how can I find what is causing all these components to rerender?
*The code I actually put looks like
public mounted() {
let oldData = JSON.parse(JSON.stringify(this.$data));
this.$watch(() => this.$data, (newData) => {
console.log(diff(oldData, newData));
oldData = JSON.parse(JSON.stringify(newData));
}, {
deep: true,
});
}
Using the F12 dev tools in Chrome, you can track down what is triggering your component to re-render. Add an updated hook to your component as below:
updated() {
if (!this.updateCnt)
this.updateCnt = 1;
if (this.updateCnt > 1) { // set to desired
debugger;
}
console.log(`Updated ${this.updateCnt++} times`);
}
}
Refresh your page in Chrome with F12 tools open and wait for breakpoint to be hit. In the Sources tab, you will see the call stack on the right, with your updated() function as the current stack frame. Look back up the call stack and eventually you should see the code that caused the update to trigger. In my case, it was reactiveSetter() in the vue runtime, which was triggered by me setting a property in a parent component.
The code you have above will only trigger if a component's own state changes, not a parent.
I need to fire an event when page is done with rendering all the components. I have tried page mounted event but this fires only for the first time, I need to fire an event when the route changes on client side and new component is done rendering.
How about using updated . I used that for data changing state . Hope you get some help from this tips
updated: function () {
this.$nextTick(function () {
// Code that will run only after the
// entire view has been re-rendered
})
}
I have a custom map component, which wraps a Openlayers 4 instance. This component which I am forced to use, is used multiple places across my SPA. The initialization process is quite long, so I would like to keep one instance of the map available, and move it between views when I need to. Problem is that the state doesen´t update within the component when it has moved.
I´ve boiled the problem down to this fiddle: https://jsfiddle.net/j16d4yto/
When moved on the same router-view the state updates fine (click the ‘Change text’ button). But when the router-view changes, and the component is moved with appendChild to the new div, the state freezes, and you can´t update the text variable anymore.
This is how I move the component from one element to another:
this.$root.$on('showMoveableComponent', function(element) {
element.appendChild(thisElement);
this.text = 'Changed text2';
});
I bet I am doing something wrong here, and probably also approaching this problem in the wrong way?
Thanks!
It's not working because of when router-view changed your MoveableComponent has been destroyed only its DOM element still referenced by you. You can test by print something in destroyed lifecycle callback function.
So this mean you can solve this by using built-in keep-alive component:
<keep-alive>
<router-view></router-view>
</keep-alive>
Example
The keep-alive component will cache everything which may not good in some other cases.
In my opinion the better way to solve this is create another Vue instance and move it.
const MoveableComponent = new Vue({
el: '#some-id',
template: `...`,
data: { ... },
methods: {
changeText() {
...
},
moveTo(element) {
element.appendChild(this.$el)
}
}
})
Example
I am creating a tab component that loads its v-tab-item components dynamically, given an array of configuration objects that consist of tabName, id, and tabContent which is a resource location for the component. I have it successfully loading the components. However, they don't actually initialize (or run their created() methods) until I switch tabs. I just get empty tabs with the correct labels. Using the DOM inspector initially shows just <componentId></componentId>, and then when I switch tabs, those tags are replaced with all of the component's content.
How do I get the dynamic components to initialize as soon as they are loaded?
EDIT: I created a CodePen here:
https://codepen.io/sgarfio/project/editor/DKgQON
But as this is my first CodePen, I haven't yet figured out how to reference other files in the project (i.e. what to set tabContent to so that require.js can load them up). I'm seeing "Access is denied" in the console, which makes it sound like it found the files but isn't allowed to access them, which is weird because all the files belong to the same project. So my CodePen doesn't even work as well as my actual project. But maybe it will help someone understand what I'm trying to do.
Also, after poking around a bit more, I found this:
http://michaelnthiessen.com/force-re-render/
that says I should change the key on the component and that will force the component to re-render. I also found this:
https://v2.vuejs.org/v2/guide/components-dynamic-async.html
Which has a pretty good example of what I'm trying to do, but it doesn't force the async component to initialize in the first place. That's what I need the async components to do - they don't initialize until I switch tabs. In fact they don't even show up in the network calls. Vue is simply generating a placeholder for them.
I got it working! What I ended up doing was to emit an event from the code that loads the async components to indicate that that component was loaded. The listener for that event keeps a count of how many components have been loaded (it already knows how many there should be), and as soon as it receives the right number of these events, it changes the value of this.active (v-model value for the v-tabs component, which indicates which tab is currently active) to "0". I tried this because as I noted before, the async components were loading/rendering whenever I switched tabs. I also have prev/next buttons to set this.active, and today I noticed that if I used the "next" button instead of clicking on a tab, it would load the async components but not advance the tab. I had already figured out how to emit an event from the loading code, so all I had to do at that point was capture the number of loaded components and then manipulate this.active.
I might try to update my CodePen to reflect this, and if I do I'll come back and comment accordingly. For now, here's a sample of what I ended up with. I'm still adding things to make it more robust (e.g. in case the configuration object contains a non-existent component URL), but this is the basic gist of it.
created: function() {
this.$on("componentLoaded", () => {
this.numTabsInitialized++;
if(this.numTabsInitialized == this.numTabs) {
// All tabs loaded; update active to force them to load
this.active = "0";
}
})
},
methods: {
loadComponent: function(config) {
var id = config.id;
var compPath = config.tabContent;
var self = this;
require([compPath], function(comp) {
Vue.component(id, comp);
self.$emit("componentLoaded");
});
}
}
I am using a jquery date picker tool. But it is inside a v-if. When I toggle it on and off if I write this code it does not work.
showdatepicker:function(){
this.datepicker= true;
$(".jquery-date-picker").datepicker();
}
Because when $(".jquery-date-picker").datepicker(); runs vue still did not rendered html and added my datepicker input. But if change it to:
showdatepicker:function(){
this.datepicker= true;
setTimeout(function(){$(".jquery-date-picker").datepicker();},0);
}
It works. Because runs it after html render.
My question: is setTimeout a guaranteed way to do it after html render. Is there a proposed way in vuejs to do this right. I couldn't find any answer from my google and stackoverflow searches.
You can use nextTick which will call a function after the next DOM update cycle.
this.datepicker = true;
Vue.nextTick(function () {
$(".jquery-date-picker").datepicker();
})
And here is it's page in the documentation VueJS Docs
Vue features triggers, in your case the mounted() function could be used. This articles describes how to use it and the whole Vue hook timeline : https://alligator.io/vuejs/component-lifecycle/
A stackoverflow explanation : Vue JS mounted()