I've trouble finding out why my method logs the step before the actual one. So If I select 1 in a box and then 2, I'll get printed out nothing then 1.
Here is my code :
<b-form-select #input="setCadeauOrReduction(vGiftCard)" #change="calculateNet(vGiftCard)" v-if="this.cadeauOrReduction != 'reduction'" v-model="vGiftCard" id="bonCadeauSoin">
<option></option>
<option v-for="boncadeau in boncadeaus" :key="boncadeau.id" v-bind:value="boncadeau.id">
<p>N° </p>
{{boncadeau.serialNumberProduct}}
<p>|</p>
{{boncadeau.amountOfCard}}
<p>CHF</p>
</option>
</b-form-select>
This basically calls the function #change. It gives me the Gift card's id as parameter. Then the function it calls :
fetchOneBonCadeau(idToFetch)
{
axios.get('/bonCadeaus/' + idToFetch)
.then((res) => {
this.bonCadeauPourAxios = res.data
})
.catch((err) => {
console.log(err);
})
return this.bonCadeauPourAxios;
},
//Calculer montant net
calculateNet(value)
{
console.log(this.fetchOneBonCadeau(value));
if(this.vReasonReduction)
{
this.vCostNet = this.vCostBrut - this.vCostBrut * this.vReasonReduction.reductionAmount;
}
else
{
this.vCostNet = this.vCostBrut;
}
}
The console.log part always lags one step behind. I can't figure why. This is my controller if needed :
public function show($id)
{
$bonCadeau = BonCadeau::where('id', $id)->first();
return $bonCadeau;
}
Edit : normal code using the vModel binding property
fetchOneBonCadeau(idToFetch)
{
axios.get('/bonCadeaus/' + idToFetch)
.then((res) => {
this.bonCadeauPourAxios = res.data
})
.catch((err) => {
console.log(err);
})
},
//Calculer montant net
calculateNet(value)
{
this.fetchOneBonCadeau(value);
console.log(this.bonCadeauPourAxios); //Is one step behind, first value is empty
if(this.vReasonReduction)
{
this.vCostNet = this.vCostBrut - this.vCostBrut * this.vReasonReduction.reductionAmount;
}
else
{
this.vCostNet = this.vCostBrut;
}
}
I feel like vGiftCard is updated after the function "calculateNet" is called
The reason is that the result of the HTTP request returned by Axios is asynchronous, you will not obtain it right away in the fetchOneBonCadeau function.
What you can do however is return the axios promise from fetchOneBonCadeau and use it in calculateNet.
So you can implement fetchOneBonCadeau like this:
fetchOneBonCadeau(idToFetch)
{
return axios.get('/bonCadeaus/' + idToFetch)
.then(res => res.data)
.catch(err => {
console.log(err);
})
},
And calculateNet like this:
calculateNet(value)
{
this.fetchOneBonCadeau(value).then( (bonCadeauPourAxios) => {
console.log(bonCadeauPourAxios);
if(this.vReasonReduction)
{
this.vCostNet = this.vCostBrut - this.vCostBrut * this.vReasonReduction.reductionAmount;
}
else
{
this.vCostNet = this.vCostBrut;
}
});
)
}
Implementing the logic using the bonCadeauPourAxios variable in the "then" callback guaranties that the variable will have been retrieved from the backend.
Related
We have a service api layer. The angular app calls the api to get or post the required information
I have a service function which uses map and mergemap. First to post and then get the data.
I am not sure how to write the test case for that.
This is the code:
saveAndReloadData(refNo: string):Observable<DataResponseModel> {
return this.http.post(this._remoteApiUrl + '/Savedata',this.initialdetails)
.map((res) => {
if(res['hasErrors']){
console.log('Error while saving the data', res);
return throwError(res['resultDescription']);
} else {
return res;
}
}).catch((error: any) => this.handleError(error))
.mergeMap((saveResp) => {
return this.http.get(this._remoteApiUrl + '/GetDetails?refNo=' + refNo)
})
.map((getRes) => {
this.FinalDetails = getRes
return getRes;
}).catch((error: any) => this.handleError(error)); ```
This is how you can test it, please ask any doubts when you write for the other testing branches for this code.
desc("saveAndReloadData method", () => {
it('should set FinalDetails', fakeAsync(() => {
component.FinalDetails = null;
httpServiceMock.post.and.returnValue(of({hasErrors: false}));
httpServiceMock.get.and.returnValue(of({test: 1}));
let output = '';
component.saveAndReloadData.subscribe();
flush();
expect(component.FinalDetails).toEqual({test: 1});
}));
});
In order to implement in app purchase using expo am using https://docs.expo.io/versions/latest/sdk/in-app-purchases.
I implemented as per the document and i tested it in sandbox mode.what i have did is:
1)Set up in app purchase in appstore.
2)implement the functionality accordingly.
3)Validate receipt with cloud function and return the expiry date.
My question here is is there anything to do in our end regarding the billing?in sandbox mode if it is a fake transaction it didn't ask anything about payment.How it work in production is it differently and need we do anything for managing billing?
Any explanation, suggestions and corrections will be awesome.
My code is:
........
if (InAppPurchases.setPurchaseListener) {
InAppPurchases.setPurchaseListener(({ responseCode, results, errorCode }) => {
if (responseCode === InAppPurchases.IAPResponseCode.OK) {
results.forEach(purchase => {
if (!purchase.acknowledged) {
if (purchase.transactionReceipt) {
if (Platform.OS === "ios") {
if (!this.flag) {
this.flag = true;
fetch("url", {
method: "POST",
body: JSON.stringify(purchase),
headers: { "Content-type": "application/json;charset=UTF-8" }
})
.then(response => {
if (response.ok) {
return response.json();
}
})
.then(json => {
if (json && Object.keys(json).length) {
let subscriptionDetails = {};
subscriptionDetails.subscribed = json.isExpired;
subscriptionDetails.expiry = JSON.parse(json.expiryDate);
subscriptionDetails.inTrialPeriod = json.inTrial;
subscriptionDetails.productId = json.id;
SecureStore.setItemAsync(
"Subscription",
JSON.stringify(subscriptionDetails)
)
.then(() => {
console.info("subscription Saved:");
store.dispatch(
setWsData("isSubscriptionExpired", json.isExpired)
);
let expired = json.isExpired;
store.dispatch(setUiData("isCheckAnalyze", true));
store.dispatch(setWsData("firstSubscription", false));
this.setState({ checkExpiry: json.isExpired });
if (!expired) {
InAppPurchases.finishTransactionAsync(purchase, true);
alert("Now you are Subscribed!!");
} else {
alert("Expired");
}
})
.catch(error =>
console.error("Cannot save subscription details:", error)
);
}
})
.catch(err => console.log("error:", err));
}
}
}
}
});
I'm working on a vue SPA project as front-end and Laravel as my back-end. I realized that on every component methods I keep repeating the same code over and over. I would like more advice on how to make a global class that will handle some of the the Http Exception error messages that have been return from the back-end server with or without customized messages Instead of checking it on every method DRY code.
Here is what I have been doing so far:
catch(error => {
if (error.response.status === 422) {
this.serverValidation.setMessages(error.response.data.errors);
} elseif (error.response.status === 403) {
this.error_403 = error.response.data.errors;
} elseif(error.response.status === 402) {
this.error_402 = error.response.data.errors;
}
....
});
I usually make a js/mixins/Errors.js file with all my error methods and then just include the mixin in my vue files.
export const errorsMixin = {
methods: {
errorClass(item, sm = false) {
return { 'form-control': true, 'form-control-sm': sm, 'is-invalid': this.validationErrors.hasOwnProperty(item) }
},
buttonClass() {
return ['btn', 'btn-primary', this.saving ? 'disabled' : '']
},
handleError(error) {
this.saving = false
if (error.response.status == 422) {
this.validationErrors = error.response.data.errors;
} else {
alert(error.response.data.message)
}
},
}
}
In each vue file:
import { errorsMixin } from '../../mixins/Errors.js'
export default {
mixins: [errorsMixin],
......
.catch((err) => {
this.handleError(err)
})
}
I'm trying delete data but I'm getting this error:
this.jobPosts.filter is not a function
PostJobIndex.vue file:
deleteJobPost: async function(jobPost) {
if (!window.confirm('Are you sure you want to delete this Job Post?')) {
return;
}
try {
await employerService.deleteJobPost(jobPost.id);
this.jobPosts = this.jobPosts.filter(obj => {
return obj.id != jobPost.id;
});
console.log(this.jobPosts);
this.$toast.success("Job Post deleted Successfully!");
} catch (error) {
console.log(error);
this.$toast.error(error.response.data.message);
}
},
I had this same issue with my Update method and I beleive it was because I was trying to map through an object or something instead of an array. In the end I used Object.keys(this.jobPosts).map for my update method and it worked:
Object.keys(this.jobPosts).map(jobPost => {
if (jobPost.id == response.data.id) {
for (let key in response.data) {
jobPost[key] = response.data[key];
}
}
});
But when I do this for Update it doesn't work:
this.jobPosts = Object.keys(this.jobPosts).filter(obj => {
return obj.id != jobPost.id;
});
UPDATED
Here is the code for loading the job posts:
loadJobPosts: async function() {
try {
const response = await employerService.loadJobPosts();
this.jobPosts = response.data;
console.log(this.jobPosts);
} catch (error) {
this.$toast.error('Some error occurred, please refresh!');
}
},
Im using Vuex for state management and I'm using services, that simply contain the axios http requests. That's where this line comes from employerService.loadJobPosts() loadJobPosts() is a function inside my employerService.js file.
I'm also using Laravel for my back end. Here is my JobPostsController.php file:
public function index()
{
$jobPosts = JobPost::all()->where('user_id', Auth::user()->id);
return response()->json($jobPosts, 200);
}
From what I've understood from your code,
this should work for removing jobPost from jobPosts
this.jobPosts = this.jobPosts.filter(obj => {
return obj.id != jobPost.id;
});
I don't know what you're expecting this to do, but it won't do anything useful and will either error or return false for everything.
this.jobPosts = Object.keys(this.jobPosts).filter(obj => {
return obj.id != jobPost.id;
});
filter exists on array types, so I would check where it's getting set and make sure it's an array.
I've included a small snippet in case it's any help.
Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
el: "#app",
data: () => {
return {
jobPosts: [],
deleteJobId: 1
};
},
methods: {
getJobPosts() {
this.jobPosts = [{
id: 1
}, {
id: 2
}, {
id: 3
}, {
id: 4
}, {
id: 5
}];
},
deleteJob() {
if (!this.deleteJobId)
return;
this.jobPosts = this.jobPosts.filter(x => x.id !== this.deleteJobId);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button type="button" #click="getJobPosts">Get Jobs</button>
<div>
<button type="button" #click="deleteJob">Delete Job #</button>
<input type="number" v-model.number="deleteJobId" />
</div>
<ul>
<li v-for="jobPost in jobPosts">
Job Post #{{jobPost.id}}
</li>
</ul>
</div>
You have already answered your own question:
in my data() object, I have this jobPosts: [], but in the console it says Object
As for your second question:
I don't know how to return the data as an array
There are similiar topics here on SO.
I am not familiar with Laravel but assuming you have an eloquent model with JobPost in your index-function according to the docs you should use the .toArray-method:
$jobPosts = JobPost::all()->where('user_id', Auth::user()->id).toArray();
When working with plain collections the values method should do the trick of returning an array instead of an object:
$collection = collect([
10 => ['product' => 'Desk', 'price' => 200],
11 => ['product' => 'Desk', 'price' => 200]
]);
$values = $collection->values();
$values->all();
UPDATE
I just realized that your result is just a stringified JSON object that needs to be converted into an array. Just parse it before processing (take out the JSON.parse(...) if you are already taking care of it in your service), return the object properties as an array and you are good to go:)
this.jobPosts = Object.values(JSON.parse(this.jobPosts)).filter(obj => {
return obj.id != jobPost.id;
});
I saw a similar question here which doesnt solve my problem. I am trying to run a cron job every 10 hours that lets me get the categories first and then based on the categories, i find the information for each category. How can I simplify the below Promise. I am NOT using Bluebird or Q, this is the native JS promise. Honestly, the code below looks like the same callback hell Promises were supposed to avoid, any suggestions
flipkart.getAllOffers = function () {
interval(43200, () => {
flipkart.findAllCategories()
.then((categories) => {
flipkart.save('flipkart_categories.json', categories)
if (categories) {
for (let item of categories) {
flipkart.findAllForCategory(item.category, item.top)
.then((items) => {
flipkart.save('flipkart_top_' + item.category + '.json', items)
}).catch((error) => {
console.log(error)
})
}
}
})
.catch((error) => {
console.log(error)
})
})
}
function interval(seconds, callback) {
callback();
return setInterval(callback, seconds * 1000);
}
If you stop using an extra level of indent just for .then(), then you have a pretty simple structure.
One .then() handler that contains
an if() statement
that contains a for loop
that contains another async operation
In this modified version, half your indent comes from your if and for which has nothing to do with promises. The rest seems very logical to me and doesn't at all look like callback hell. It's what is required to implement the logic you show.
flipkart.getAllOffers = function () {
interval(43200, () => {
flipkart.findAllCategories().then((categories) => {
flipkart.save('flipkart_categories.json', categories)
if (categories) {
for (let item of categories) {
flipkart.findAllForCategory(item.category, item.top).then((items) => {
flipkart.save('flipkart_top_' + item.category + '.json', items)
}).catch((error) => {
console.log(error)
throw error; // don't eat error, rethrow it after logging
});
}
}
}).catch((error) => {
console.log(error)
})
})
}
If flipkart.save() is also async and returns a promise, then you probably want to hook those into the promise chain too.
You can always create a helper function that may improve the look also like this:
flipkart.getAllOffers = function () {
interval(43200, () => {
flipkart.findAllCategories().then(iterateCategories).catch((error) => {
console.log(error);
})
})
}
function iterateCategories(categories) {
flipkart.save('flipkart_categories.json', categories);
if (categories) {
for (let item of categories) {
flipkart.findAllForCategory(item.category, item.top).then((items) => {
flipkart.save('flipkart_top_' + item.category + '.json', items);
}).catch((error) => {
console.log(error);
});
}
}
}
If you're trying to collect all the results (something your title implies, but your question doesn't actually mention), then you can do this:
flipkart.getAllOffers = function () {
interval(43200, () => {
flipkart.findAllCategories().then(iterateCategories).then((results) => {
// all results here
}).catch((error) => {
console.log(error);
});
})
}
function iterateCategories(categories) {
flipkart.save('flipkart_categories.json', categories);
let promises = [];
if (categories) {
for (let item of categories) {
let p = flipkart.findAllForCategory(item.category, item.top).then((items) => {
flipkart.save('flipkart_top_' + item.category + '.json', items);
}).catch((error) => {
console.log(error);
});
promises.push(p);
}
}
// return promise here that collects all the other promises
return Promise.all(promises);
}