Sometimes http api call takes long time to load data. In this case, if we move on another component, it still keeps executing (we can see it in browser console). So, is there any way by which we can cancel or kill http api call when we move on another component?
You can "kill" it by using unsubscribe() method in OnDestroy lifecycle event, under assumption you are using subscriptions, for example:
mySubscription: any;
ngOnInit() {
this.mySubscription = this.myHttpCall().subscribe...
}
ngOnDestroy() {
this.mySubscription.unsubscribe();
}
You can use the takeWhile() function from rxjs to unsubscribe all the subscriptions: Example:
http://brianflove.com/2016/12/11/anguar-2-unsubscribe-observables/
Related
I am trying to make a simple chat app using vuejs and socketio.
I would like to broadcast a message from one user to all the others.
I have the following code on the server side to do that:
io.on('connection', socket => {
socket.on('send-message', message => {
console.log('message sent: ' + message)
socket.broadcast.emit('receive-message', message)
})
})
On the client side, I am listening to that action in this method:
this.socket.on('receive-message', message => {
this.createMessageHtmlElement(message)
})
I am having a hard time knowing where to place that method. putting in mounted() or created() will make it get called over and over again. I only want to call it when the server actually sends a message.
What is the correct way to place server action listeners in a vuejs project?
putting in mounted() or created() will make it get called over and
over again.
this.socket.on is a "socket version" of document.addEventListener (docs) so, you will set a function (callback) that will be executed when a certain event occurs (receive-message in your case). Depending on what createMessageHtmlElement actually does, you can put this.socket.on in either created() or mounted().
Assuming you have a simple app, probably the best place to do that is App.vue since the listener is going to be registered when the App.vue is registered (Vue lifecycle)
I have a Vue app which does a little localStorage and server check on app load, to determine where to initially route the user.
This is in the App's main entry component, in the created() hook
My problem is that the default / route's Component visibly loads first, then the server call and everything happens which causes the user the route to their correct location
How can I delay the rendering of the initial component until my app's main component created() method completes, and then purposely navigates the user to the correct route?
I had this problem before and I firmly believe that you must have the initial files for your routes and your router configuration.
In the configuration, you could handle the permission and router before each route and with next() . In the router file, you can set your params and check them in the index.js file(router configuration)
you could also use your localStorage data in Router.beforeeach
EDIT: I just saw you used the created method... like mentioned below use beforeRouteEnter instead with the next() parameter it provides
First of all I wouldn't recommend using a delay but instead a variable that keeps track if the API call is done or not. You can achieve this using the mounted method:
data() {
return {
loaded: false,
}
}
async mounted() {
await yourAPICALL()
if (checkIfTokenIsOkay) {
return this.loaded = true;
}
// do something here when token is false
}
Now in your html only show it when loaded it true:
<div v-if="loaded">
// html
</div>
An better approuch is using the beforeRouteEnter method which allows you to not even load the page instead of not showing it: https://router.vuejs.org/guide/advanced/navigation-guards.html
We have a vue firebase service worker that needs to call back to the main vue app. According to my research you can do this with the postMessage() function like so:
// firebase-messaging-sw.js
addEventListener('fetch', event => {
event.waitUntil(
(async function() {
// Exit early if we don't have access to the client.
// Eg, if it's cross-origin.
if (!event.clientId) return
// Get the client.
const client = await clients.get(event.clientId)
// Exit early if we don't get the client.
// Eg, if it closed.
if (!client) return
// Send a message to the client.
client.postMessage({
msg: 'Hey I just got a fetch from you!',
url: event.request.url
})
})()
)
})
You handle the message in the main app so:
// main.js
navigator.serviceWorker.addEventListener('message', event => {
console.log('Url', event.data.url)
console.log('msg', event.data.msg)
})
The problem is that postMessage() needs to be called on a client object and you get the client object on the fetch event, but vue does not seem to fetch anything as it is a single page application.
So how can I get the client?
and how do I message the main app?
The client does not need to make a fetch request in order to allow the Service Worker to communicate with it. You can use the Clients API inside the Service Worker. You can also initiate a completely separate postMessage message from the client in the beginning after the app has started.
Clients API: https://developer.mozilla.org/en-US/docs/Web/API/Clients
I also suggest you check out this example: https://serviceworke.rs/message-relay.html
I have an nuxt.js app that a user can log in to. Whenever the user is authenticated using the nuxt/auth module. I want the app to fetch some data using the nuxtServerInit.
Currently I have this in my nuxtServerInit:
export const actions = {
async nuxtServerInit({ dispatch }) {
if (this.$auth.loggedIn) {
await dispatch('products/getProducts')
...
}
}
}
This works well if I'm authenticated and the page is refreshed. The problem seems to be whenever I'm redirected after authentication, these actions are never called, thus not populating the store.
I have tried to use the fetch method instead, but in only works on the page with the fetch statement, not every page in my application. Also I don't want the http calls to be made with every page change.
I use Ember mirage in my tests. I need to check the state of my tested component after a request has been send but before the respond has been received.
How it is possible to configure my test to avoid the mirage server responds automatically and trigger the response programmatically?
I used to do that with sinonjs but I do not find the way to manage this use case with Ember mirage. It is possible?
http://www.ember-cli-mirage.com/docs/v0.3.x/route-handlers/
You can add a handler like this inside your test:
server.get('/users/:id', function(db, request) {
console.log(request) // to debug request/response
return db.users.find(request.params.id);
});
If I understand your question correctly, you are trying to test a situation on the page (acceptance test) when data were sent to the server but the response still did not arrive.
It is possible to access server instance in your test, so it is not that complicated to create your own method that will pause/resume responding but the simpler option (that I use as well) is just to postpone response from mirage using timing option (http://www.ember-cli-mirage.com/docs/v0.3.x/configuration/#timing). Then, when you do your tests before andThen() you should be in a situation that you wish to test.
you can access the underlying pretender instance and the fact that mirage just passes the timing parameter straight through to the pretender request.
https://github.com/pretenderjs/pretender#timing-parameter
Unfortunately pretender doesn't have docs for requestReferences and requiresManualResolution(verb, path), but this helper function will process all outstanding manual requests
function resolveManualPretenderRequests(pretender) {
pretender.requestReferences.forEach((ref) => {
if (pretender.requiresManualResolution(ref.request.method, ref.request.url)) {
pretender.resolve(ref.request);
}
});
}
Then you can just use mirage to register a manual request handler
server.get('/models:id', { timing: true });
so in an example test, you can use the ember test helper waitFor() to do something like
test('button is disabled while loading', async function(assert) {
assert.expect(2);
// passing true to timing tells the underlying pretender handler wait for the request to be manually processed
server.get('/models/:id', { timing: true });
// await render will wait for promises to settle, but we actually don't want that
const renderPromise = render(hbs`<MyComponent />`);
// the waitFor() helper instead will allow us to just wait for our button to render
await waitFor('button');
const button = this.element.querySelector('button');
// since the request has not resolved yet, the button is disabled
assert.strictEqual(button.disabled, true);
// then we manually resolve the request
resolveManualPretenderRequests(server.pretender);
// now we can await the render so that we get our updated button state
await renderPromise;
// with the request resolved, now the button is no longer disabled
assert.strictEqual(button.disabled, false);
});