Call a method function inside an async Method Function - vuejs2

I have two methods:
method_1 and aysnc method_2;
I would like to call method_1 inside the aysnc method_2 (after retrieving some Data);
(aysnc method_2 catches Data and pass it into method_1 and executes it.)
I use this.method_1 inside the aysnc method_2 to call it, but nothing happens.
method_1 (data) {
console.log( 'I need it here', data );
} ,
triggerByUser () {
this.method_1( 'just a test' );
async function method_2 () {
let code = await fileRetriever( 'songs' );
console.log( 'this code retrieved: ' , code );
this.method_1( code );
console.log( 'the code has been sent!' );
} ;
method_2 ( ) ;
},
result:
JS: 'I need it here' 'just a test'
JS: 'response From fileRetriever:' 58
JS: 'this code retrieved: ' 58
( Project is written on NativeScript + Vue )

it seems that I need to pass it as a callback;
triggerByUser () {
this.method_1( 'just a test' );
async function method_2 ( callback ) {
let code = await fileRetriever( 'songs' );
console.log( 'this code retrieved: ' , code );
callback( code );
console.log( 'the code has been sent!' );
} ;
method_2 ( this.method_1 ) ;
},
result:
JS: 'I need it here' 'just a test'
JS: 'response From fileRetriever:' 58
JS: 'this code retrieved: ' 58
JS: 'I need it here' 58
JS: 'the code has been sent!'
Is there any better approach?! (since using async + callback seems a bit dirty to me )

I don't know Nativescript but as I can read from the intro seems that Vue Component is the same of the classic Vue.
You have nested method_2 inside the triggerByUser if you move it outside , into the methods, and call it with await all function correctly
methods:{
method_1 (data) {
console.log( 'I need it here', data );
},
async triggerByUser () {
this.method_1( 'just a test' );
await this.method_2();
},
async method_2 () {
let code = await fileRetriever( 'songs' );
console.log( 'this code retrieved: ' , code );
this.method_1( code );
console.log( 'the code has been sent!' );
}
}

Well very simple..
create two methods and call them in a third async method
For example, you have to run two ajax calls when user clicks on an anchor tag then you will do it like this.
<template>
<div>
<a #click="getDataFromTwoOtherMethods()">Click here</a>
</div>
</template>
<script>
export default{
...
methods:{
method1(){},
method2(){},
async getDataFromTwoOtherMethods(){
await this.method1();
this.method2();
//this method will wait for method1 to execute
//and get response and then call second method
}
},
</script>

Related

Item inside <nuxeo-data-table-column> component passed to a function as an argument yields empty object

<nuxeo-data-table-column>
[[item.title]]
</nuxeo-data-table-column>
This works. Here 'item.title' renders title.
<nuxeo-data-table-column>
[[_callme(item)]]
</nuxeo-data-table-column>
_callme: function (item) {
console.log(item);
}
This doesn't work. Here 'item' is an empty object
Where my I wrong ?
I end up fetching page provider manually and fed to 'items' property to 'nuxeo-data-table' which then works.
Template
<nuxeo-page-provider id="nxProvider">
<nuxeo-data-table items="[[data.entries]]">
<nuxeo-data-table-column>
[[_callme(item)]]
</nuxeo-data-table-column>
</nuxeo-data-table>
</nuxeo-page-provider>
Script
setIntialValue:function(){
this.$.nxProvider.fetch().then(data=>{
this.data = Object.assign({}, data);
})
}
_callme: function (item) { console.log(item); } ->works

Able to display the result of a promise but length of the result appears as undefined

I'm new to vue/promise and I am struggling to understand why when I try to display the result of a promise I end up with the expected data but when I try to find out its length, it says undefined
When I try to display the alerts from displayAlerts() , I can see a list of alerts, 2 in total. However in computed within the title function ${this.displayAlerts.length} appears as undefined, I was expecting to see 2.
Does it have something to do with displayAlerts() resulting in a promise? How do I fix the code such that I get 2 instead of undefined?
The code is below:
<template>
<div>
{{displayAlerts}}
<li v-for="alert in alerts" class="alert">
{{alert['name']}}
</li>
</div>
</template>
export default {
data () {
return {
alerts: null,
alert: new Alert(),
updatedAlert: new Alert(),
deletedAlert: new Alert(),
};
},
computed: {
...mapGetters("authentication",['token']),
...mapGetters("user",['profile']),
displayAlerts() {
return getUserAlert({
user_id: this.profile.user_id,
token: this.token
}).then(response => (this.alerts = response.data)).catch(
error => console.log(error)
)
},
title () {
return `My Alerts (${this.displayAlerts.length})`
},
test2() {
return [1,2,3]
},
}
};
</script>
Something like this should work:
<template>
<div v-if="alerts">
<h4>{{ title }}</h4>
<li v-for="alert in alerts" class="alert">
{{ alert.name }}
</li>
</div>
</template>
export default {
data () {
return {
alerts: null
}
},
computed: {
...mapGetters('authentication', ['token']),
...mapGetters('user', ['profile']),
title () {
// Handle the null case
const alerts = this.alerts || []
return `My Alerts (${alerts.length})`
}
},
methods: {
// This needs to be in the methods, not a computed property
displayAlerts () {
return getUserAlert({
user_id: this.profile.user_id,
token: this.token
}).then(response => (this.alerts = response.data)).catch(
error => console.log(error)
)
}
},
// Initiate loading in a hook, not via the template
created () {
this.displayAlerts()
}
}
</script>
Notes:
Computed properties shouldn't have side-effects. Anything asynchronous falls into that category. I've moved displayAlerts to a method instead.
Templates shouldn't have side-effects. The call to load the data should be in a hook such as created or mounted instead.
title needs to access this.alerts rather than trying to manipulate the promise.
While the data is loading the value of alerts will be null. You need to handle that in some way. I've included a v-if in the template and some extra handling in title. You may choose to handle it differently.
I've added title to the template but that's just for demonstration purposes. You can, of course, do whatever you want with it.
I've assumed that your original displayAlerts function was working correctly and successfully populates alerts. You may want to rename it to something more appropriate, like loadAlerts.

Cypress hangs in loop when running custom Chai assertion

I have been trying to create my own custom chai assertion (based on the Cypress recipe template: https://github.com/cypress-io/cypress-example-recipes/blob/master/examples/extending-cypress__chai-assertions/cypress/support/index.js).
What I have found with the code below is that when it is run I end up with a constant loop of WRAP, if I swap this.obj with element it then results in a constant stream of GET. I do not seem to ever progress further than getRect(first).then((actual)
If anyone could help me out I'd be very grateful.
cypress/integration/test.js
describe('testing custom chai', () => {
it('uses a custom chai helper', () => {
cy.visit('https://www.bbc.co.uk/news');
cy.get('#orb-modules > header').should('be.leftAligned', '#orb-header');
});
});
cypress/support/index.js
function getRect(selector) {
if (selector === '&document') {
return cy.document().then(doc => doc.documentElement.getBoundingClientRect());
} if (typeof selector === 'string') {
return cy.get(selector).then($elem => $elem[0].getBoundingClientRect());
}
return cy.wrap(selector).then(elem => Cypress.$(elem)[0].getBoundingClientRect());
}
function getRects(first, second) {
return getRect(first).then((actual) => {
getRect(second).then(expected => [actual, expected]);
});
}
const aligned = (_chai, utils) => {
function leftAligned(element) {
getRects(element,this.obj).then((rects) => {
this.assert(
rects[0].left === rects[1].left,
'expected #{this} to be equal',
'expected #{this} to not be equal',
this._obj,
);
});
}
_chai.Assertion.addMethod('leftAligned', leftAligned);
};
chai.use(aligned);
The basic problem is that the async commands cy.get(), cy.wrap(), cy.document() can't be used in the custom assertion. My best guess is that the auto-retry mechanism is going bananas and giving you the constant loop.
Instead, you can use Cypress.$() which is the synchronous version (essentially jquery exposed on the Cypress object).
The following seems to work ok. (I renamed getRects() param to subject, as sometimes it's a selector and sometimes it's the object passed in to .should()).
Note also this._obj instead of this.obj.
function getRect(subject) {
if (subject === '&document') {
return Cypress.$(document).context.documentElement.getBoundingClientRect();
}
if (typeof subject === 'string') { // the selector passed in to assertion
return Cypress.$(subject)[0].getBoundingClientRect();
}
if (typeof subject === 'object') { // the element from cy.get() i.e this._obj
return subject[0].getBoundingClientRect();
}
return null; // something unkown
}
function getRects(first, second) {
const actual = getRect(first)
const expected = getRect(second)
return [actual, expected];
}
const aligned = (_chai, utils) => {
function leftAligned(element) {
const rects = getRects(element, this._obj)
this.assert(
rects[0].left === rects[1].left,
'expected #{this} to be equal',
'expected #{this} to not be equal',
this._obj,
);
}
_chai.Assertion.addMethod('leftAligned', leftAligned);
};
chai.use(aligned);
I was unable to test your BBC page directly, as there's a cross-origin problem occurring
Refused to display 'https://www.bbc.com/news' in a frame because it set 'X-Frame-Options' to 'sameorigin'
but it does work with a mockup page
cypress/app/bbc-sim.html
<div id="orb-modules">
<header>
<h1>Brexit: Boris Johnson's second attempt to trigger election fails</h1>
</header>
</div>
and testing like so
it('uses a custom chai helper', () => {
cy.visit('app/bbc-sim.html')
cy.get('#orb-modules > header').should('be.leftAligned', '#orb-modules');
});

API call occurs duplicate contents

I use VueJS for a project and Axios for API call. I don't know how to execute this code once. When I go in my home page this code is executed, I go to another page, I go back and this code is executed again. How to cancel execution ?
mounted () {
axios
.get( config.API.projects )
.then(response => {
this.SET_PROJECTS( response.data );
const projects = this.$store.getters["projects/projects"];
projects.forEach( project => {
this.SET_SKILLS( project.skills )
});
this.SET_SHOW_LOADER( false );
})
.catch( ( error ) => {
console.log( error );
alert( "Une erreur est survenue, merci de contacter par mail l'administrateur de ce site" )
});
},
Assuming Your VUEX getter "projects/projects" is an array, and is not populated before the call, you can just do a check to see if it has any data. If it is empty (length equal to zero) you want to get the data and populate it with it. Next time you enter this view, the check will fail, since the store is already populated with the results. (length of projects is greater than 0)
mounted () {
const projects = this.$store.getters["projects/projects"];
if (projects.length === 0) {
axios.get( config.API.projects ).then(response => {
this.SET_PROJECTS( response.data );
projects.forEach( project => {
this.SET_SKILLS( project.skills )
});
this.SET_SHOW_LOADER( false );
})
.catch( ( error ) => {
console.log( error );
alert( "Une erreur est survenue, merci de contacter par mail l'administrateur de ce site" )
});
}
},
Bonus tip: Be carefull with using .catch. I assume you want to "catch" only if there is any errors with getting the data with axios. What you are also doing, it actually catching/silencing every error from the line axios.get(... to the line .catch. This means that if let's say you get an error inside the .then function, eg: "SET_PROJECTS" is not an function and your app breaks, you will not get it in the console
In your case, you will. But only because you console.log the error parameter from the .catch. If you did not do this, you would never know there was any errors.
To fix this, simply change .catch to the 2nd parameter of the .then function:
if (projects.length === 0) {
axios.get( config.API.projects ).then(response => {
this.SET_PROJECTS( response.data );
projects.forEach( project => {
this.SET_SKILLS( project.skills )
});
this.SET_SHOW_LOADER( false );
}, error => {
console.log( error );
alert( "Une erreur est survenue, merci de contacter par mail l'administrateur de ce site" )
})
}

Vue and data from REST API

While playing around with vue.js I noticed some strange behavior while trying to display on a page data from an API, but here's the strange thing :
using vue 2.0.0, i can see the "Title", but I have an error in dev console [see printscreen]
using the latest vue version, i can't see the "Title" [and I have the same error in the printscreen]
Is it normal, or?
Source code :
template:
'<div>'+
'Form with id = {{id}}'+
'<br/>'+
'has title = {{item.details.Title}}'+
'</div>',
data: function(){
return {
id: '',
item: {}
}
},
created: function() {
this.get()
},
methods: {
get: function() {
var self = this
id = window.location.hash
id = id.replace('#/whatever/','')
axiosInstance.get('/thebackendresource/'+id) // <--- make http calls etc
.then(function (response) {
self.id = id
self.item = response.data
console.log(self.item)
}).catch(function (error) {
console.log(error)
}
);
}
}
You are getting this error, because when you are fetching data from axiosinstance, that time item.details is null, and when it tries to render it throws this error.
Once the api call is completed, it updates the the DOM and in turn re-renders the DOM, so you can see item.details.Title rendered.
You need to add a null check to prevent this error, which can be easily done using v-if, like follwoing:
template:
'<div>'+
'Form with id = {{id}}'+
'<br/>'+
'<span v-if="item.details"> has title = {{item.details.Title}}'+
'</span>' +
'</div>',