With Vue and the Nuxt store, how do I fetch from API on build, but not ever by the client? - vue.js

I'm using Vue and Nuxt and want to pull data into my build that is mostly static. Each time we build the site, we want to get the latest data and then never call the API again. The data does not need to be updated dynamically, it just needs to be available for the app and can be built in.
One of the problems is that the call to get the API data is long (>5 seconds) and we don't want the customer waiting.
Our thinking was to
Call an API at some point in the build process to collect the data
Save the data in the store so other components can access it.
Not call the API to get the data again.
How might I do this? I really appreciate any help, I'm pretty new to Vue and especially Nuxt, but really enjoy both.
What I've tried
My understanding is that using fetch() in a component will call both on the server before the initial page is rendered and on the client some time after the component is mounted.
From the documentation on Nuxt
fetch is a hook called during server-side rendering after the
component instance is created, and on the client when navigating. The
fetch hook should return a promise (whether explicitly, or implicitly
using async/await) that will be resolved:
On the server before the initial page is rendered On the client some
time after the component is mounted
I've also tried this approach (and am currently using it) from Stackoverflow
export const actions = {
async nuxtServerInit ({ state }, { req }) {
let response = await axios.get("some/path/...");
state.data = response.data;
}
}
But there is a caveat in the answer:
nuxtServerInit will fire always on first page load no matter on what page you are. So you should navigate first to store/index.js.
Anyway, I could use a hand figuring out how to do this.

Related

How to execute another components code only once the main.ts file execute successfully when we refresh the page in vue 3 composition API

I have call API to get settings data on main.ts file and set that data on store using vuex.
Now I am using the same setting data on my each pages(components)
My issue is when we refresh the page, Latest setting data is stored on vuex store but sometime on mozila firefox my main component is called before the set the setting data on vuex store such that I diden't received the valid setting data.
This issue occured only on firefox. I have used the async and await as well.
I have already set the async await on the API using axios

In Nuxt/VueJs, how can I get SendInBlue Chat Widget to see route changes?

I'm using SendInBlue chat widget on a Nuxt/VueJs website. Through the
SendInBlue Conversations UI,
the widget reports the visitor's page current location (url and title).
However, the location does not change when the internal route changes (no hard browser location change).
I want to see the location changes.
How can I notify the SendInBlue Chat Widget that the route is changing?
The
SendInBlue Chat Widget API
includes a pageView method that can be called to alert the widget to a route change.
SibConversations('pageView')
This Answer about watching a route
provides the basic framework. Note that in my case I added the code to the /layouts/default.vue since it renders most of my pages. (Add to all necessary layouts.)
<script>
export default {
watch: {
$route() {
// on route change, notify SendInBlue Chat Widget so it updates visitor location
if (process.client) {
// delay 0.5 seconds to be sure route has actually changed ($nexttick does show correct page title)
window.setTimeout(() => {
window.SibConversations('pageView')
}, 500)
}
},
},
// ... and data, methods, etc., as needed
}
</script>
So now when the route changes, we notify the widget.
Note: If we trigger window.SibConversations('pageView') without a delay, I found that the title is not correct. I'm assuming the page is not yet rendered. I tried using this.$nexttick, but the title is still not present. So, I use window.setTimeout() to provide a short delay. I found that 100ms works for me, but I used a longer time in case a slower computer took longer. (And we aren't worried about half-second accuracy.)
I also wrapped the call to ensure it's only called on client side. No nasty "windows undefined" errors.

How to prevent the flashing of content in a prerendered Blazor WebAssembly app?

The following code snippet can illustrate the issue present in Blazor applications which are rendered on the server side:
App.Client/Pages/Test.razor
#page "/test"
<p>#text</p>
#code
{
private string text;
protected override async Task OnInitializedAsync()
{
await Task.Delay(1000); // wait 1000 milliseconds
text = "foo";
}
}
When the component is first initailized on the server, the text variable is set to foo and a HTML document containing the string is sent over to the client. However, the client Blazor app isn't aware of the value that the server has assigned to the variable, which becomes null again. OnInitializedAsync is called again on the client and text is set back to foo, but only after a one second period during which there's nothing on the screen - a situation server-side rendering aims to avoid in the first place.
Do you know of any way to send components already populated with data?
Ok -- just being a bit picky -- this is a Blazor page....it isn't a component.
Yes, the pre-render they use isn't great, but assuming you're using Blazor for a SPA it should only happen once. Be careful to avoid a hard reload if you use the Microsoft.AspNetCore.Components.NavigationManager NavigateTo method. A hard re-load triggers pre-rendering because you refresh the SPA.
To avoid the whiplash, you want to avoid needing 1 second to load the text value. So you could use a singleton controller and inject it into the page. On the pre-render pass the value isn't yet known so we need 1 second to load it. Then on the client side pass the data could be accessed via the controller immediately.
Granted this isn't perfect if there is a ton of data to display. But in cases like that I generally show a 'loading' spinner and it gives the customer a feeling of controlled motion.

Tabulator: Guidance on implementing custom sort/paginate/filter/edit behavior

I'm using Tabulator in a Vue.js powered Electron desktop app. My app can query quite large datastores and displays the results in a Tabulator table.
What I want to do is basically the same as the ajax module, but instead of making AJAX calls to fetch new data I want to call a specific API.
I'm starting with sorting. When clicking the header to sort, I want to call the custom api with the sort parameters, then return a sorted slice of data. There doesn't seem to be a 'native' way to do this in the Tabulator sort module api.
Same deal with pagination -- display only ~100 results, if they paginate to the next page, I make an API call.
What's the best way to achieve this?
Can/should I build my own module (drafted from the ajax module), or do sort and paginate integrate with the ajax module directly?
You can use the ajaxRequestFunc callback to replace the existing ajax request mechanic with your own logic. Full details for this can be found in the Loading Data, Ajax Documentation
The example below shows a new function queryRealm being used to replace the built in ajax functionality.
The function will be passed a url and config and params objects, that will contain sorting, filtering and pagination data, and should return a promise that resolves with an array of table data
function queryRealm(url, config, params){
//url - the url of the request
//config - the ajaxConfig object
//params - the ajaxParams object
//return promise
return new Promise(function(resolve, reject){
//do some async data retrieval then pass the array of row data back into Tabulator
resolve(data);
//if there is an error call this function and pass the error message or object into it
reject();
});
}
var table = new Tabulator("#example-table", {
ajaxRequestFunc:queryRealm,
});

node express multer fast-csv pug file upload

I trying to upload a file using pug, multer and express.
The pug form looks like this
form(method='POST' enctype="multipart/form-data")
div.form-group
input#uploaddata.form-control(type='file', name='uploaddata' )
br
button.btn.btn-primary(type='submit' name='uploaddata') Upload
The server code looks like this (taken out of context)
.post('/uploaddata', function(req, res, next) {
upload.single('uploaddata',function(err) {
if(err){
throw err;
} else {
res.json({success : "File upload sucessfully.", status : 200});
}
});
})
My issue is that while the file uploads successfully, the success message is not shown on the same page, ie: a new page is loaded showing
{success : "File upload sucessfully.", status : 200}
As an example for other elements (link clicks) the message is displayed via such javascript:
$("#importdata").on('click', function(){
$.get( "/import", function( data ) {
$("#message").show().html(data['success']);
});
});
I tried doing a pure javascript in order to workaround the default form behaviour but no luck.
Your issue has to do with mixing form submissions and AJAX concepts. To be specific, you are submitting a form then returning a value appropriate to an AJAX API. You need to choose one or the other for this to work properly.
If you choose to submit this as a form you can't use res.json, you need to switch to res.render or res.redirect instead to render the page again. You are seeing exactly what you are telling node/express to do with res.json - JSON output. Rendering or redirecting is what you want to do here.
Here is the MDN primer on forms and also a tutorial specific to express.js.
Alternatively, if you choose to handle this with an AJAX API, you need to use jquery, fetch, axios, or similar in the browser to send the request and handle the response. This won't cause the page to reload, but you do need to handle the response somehow and modify the page, otherwise the user will just sit there wondering what has happened.
MDN has a great primer on AJAX that will help you get started there. If you are going down this path also make sure you read up on restful API design.
Neither one is inherently a better strategy, both methods are used in large-scale production applications. However, you do need to choose one or the other and not mix them as you have above.