VueJS nexttick and IE11 - vue.js

Recently $nexttick appears to have broken on IE 11, in particular regarding input bound variable. This is causing forms with dynamic content to submit missing the required data
<form id="something" action="/" method="post">
<input type="hidden" name="token" :value="token" />
</form>
// js code
promise.then(function() {
self.$nextTick(function () {
document.getElementById('something').submit();
});
});
We have found that using the setTimeout for 1 second around the form submission allows enough time for the DOM to be updated so the token can be included in the form submission.
Has there been any changes to nexttick / IE11 that we need to account for?

nextTick allows you to do something after you have changed the data and VueJS has updated the DOM based on your data change, but before the browser has rendered those changed on the page. If you want to explicitly re-render the DOM, use requestAnimationFrame or setTimeout.
You could check this thread.

Related

Freeze UI during backend calls Vuejs

I have a application, where during a first backend call to axios is still not finished, but the user can also make a second backend call or even multiple backend calls if he is fast enough to give so many inputs as he could.
I am wondering now how I can achieve a situation where after every single backend call, the User Interface will be frozen until that backend call is finished in Vuejs.
Any advices would be much appreciated !!
I don't know how your UI looks but first though that came is just to disable input (or button?) while the first request is still in progress.
You can also show some loader instead of input while the request is still in progress.
<form>
<input />
<button :disabled="loading" >Submit</button>
</form>
OR
<form v-if="!loading">
<input />
<button>Submit</button>
</form>
<loader-component v-else />
Update:
In case of drag/drop handler
I suppose you are doing that backend call in #change event handler. So as I suggested before add loading property to your component. Set it to true on first change event and after backend call is over set it to false.
eventHandler () {
if (!this.loading) {
this.loading = true
// backend call
this.loading = false
}
}

undefined data error on page reload Nuxt.js

I'm currently developing a universal app using Nuxt.js, the data on most of the pages is retrieved from an API using a fetch hook as well as vuex store. I started noticing errors on page reload/refresh and sometimes when I visit a page from the navbar. The page error is:
TypeError: Cannot read property 'data' of undefined
where data is an object retrieved from an API. I have searched around the internet for this and found it has something to do with data not being loaded or page rendering whilst the data is not fully retrieved. i have found a work around by using a v-if on my template to check if the data is set then display the contents. my question is if there is a way to achieve this, i have tried using the async/await keywords but it doesn't help and i feel like the v-if method is not the best way to handle it.
edit: solved by using $fetchState.pending when using fetch()
If in your template you display right away the data you retrieve from the API, then indeed using the v-if is the right way to do.
If you are using the new fetch() hook, then in your template you can use $fetchState.pending to check if the loading has finished, for example:
<div v-if="$fetchState.pending">
<p> Content is loading... </p>
</div>
<div v-else>
<p> Content has loaded! {{data}}</p>
</div>
<script>
export default{
data(){
return{
data: null
}
}
async fetch(){
this.data = await getSomeAPI
}
}
</script>

Vue.js showing content that should be hidden by a v-if tag when user refreshes page

I have a Vue.js app that loads content in the created() method. I use a v-if tag to hide all of my UI until that content is loaded and ready to go. It works fine on the initial load, but if a user were to hit refresh in Chrome then the app displays (flashes momentarily) content that would not otherwise be displayed (based on the data being loaded in created).
From what I understand using the v-if tag, with a flag from my vuex store that indicates when the load has completed, is the proper way to hide content until I am ready to display it.
How can I avoid having the content flash on the refresh?
Vue.JS has solved this using the v-cloak directive. (see docs)
You add the v-cloak directive to your application's root element:
<div id="app" v-cloak>
...
</div>
Then add this CSS rule to your application's stylesheet:
[v-cloak] {
display: none;
}
Everything within the app div will then be hidden until Vue has initialized.

Vue prerender flickering

I have the following solution now:
<template>
<section id="prod-main">
<prod-preview v-for="prod in products" :id="prod.id" :key="prod.id"/>
</section>
</template>
export default {
...
computed: {
products: function () {
return this.$store.getters['products/getPreview']
}
}
...
}
Vuex store will receive info after some delay from my backend. So at first call it will be empty. Now I want to use vue spa prerender and here I see a flickering.
As I understood it works like:
1. Browser loads HTML with products
2. Execute js that replace products with nothing because the store is empty.
3. After some delay shows it again with backend info.
How can I fix it? I should left prerender for indexing and I can't hardcode the backend reply.
You can use the setting captureAfterTime to wait for your async call to complete, before saving the html of the page.
Other settings are available :
// NOTE: Unless you are relying on asynchronously rendered content,
// such as after an Ajax request, none of these options should be
// necessary. All synchronous scripts are already executed before
// capturing the page content.
// Wait until a specific event is fired on the document.
captureAfterDocumentEvent: 'custom-post-render-event',
// This is how you would trigger this example event:
// document.dispatchEvent(new Event('custom-post-render-event'))
// Wait until a specific element is detected with
// document.querySelector.
captureAfterElementExists: '#content',
// Wait until a number of milliseconds has passed after scripts
// have been executed. It's important to note that this may
// produce unreliable results when relying on network
// communication or other operations with highly variable timing.
captureAfterTime: 5000,
Another issue can be related to how the prerendered HTMl gets hydrated, i've openned an issue on github, but they still haven't addressed it (and are not willing to ?)
https://github.com/chrisvfritz/prerender-spa-plugin/issues/131
The solution is to add data-server-rendered="true" to your vuejs parent node in the prerendered html, like this:
<div id="root" data-server-rendered="true">...
You can use the option postProcessHtml to do so.
I don't know if I understand your problem here but have you tried to add a v-if to avoid flickering:
<template>
<section id="prod-main">
<prod-preview
v-if="products.length > 0"
v-for="prod in products"
:id="prod.id"
:key="prod.id"/>
</section>
</template>

Dijit combobox not rendering in custom widget

I am trying to use the combobox provided by Dijit inside of a custom-made widget. I have been using Dojo's tutorial on comboboxes to guide me.
When I implement a stand-alone webpage similar to their tutorial examples, everything worked fine; but when I ported the code into my custom-made widget, it just renders the combobox as a plain HTML text box.
Here's what my custom widget's template looks like:
<div class='customWidget'>
...
<div dojoAttachPoint="mainDiv" class="mainDiv">
<div dojoType="dojo.data.ItemFileReadStore" jsId="stateStore" url="states.txt"></div>
<input dojoType="dijit.form.ComboBox"
store="stateStore"
value="California"
searchAttr="name"
name="state2" />
<button dojoAttachEvent="onclick:chooseState">OK</button>
</div>
...
</div>
In the widget code, I require the combobox and read store:
dojo.require("dijit.form.ComboBox");
dojo.require("dojo.data.ItemFileReadStore");
I also tried putting these includes in a <script/> within the custom widget (similar to the way they do it in the tutorial), but it didn't work (in fact, it appears as if the script tag wasn't even evaluated, since I couldn't reference a function I declared inside of it!)
Do you have widgetsInTemplate in your widget declaration?
dojo.declare('my.widget.Cool',[ dijit._Widget, dijit._Templated ], {
widgetsInTemplate: true,
// rest of widget JS here
});
Here's an article about including other widgets in your template.
Have you tried adding:
<script type="text/javascript">
dojo.require("dojo.parser");
dojo.addOnLoad(function(){
dojo.parser.parse();
});
</script>
(from Dojocampus) to ensure Dojo is parsing the page? Are there any errors in your Javascript console? Is the page rendering any normal Dojo widgets?