Cancel a previous axios request on new request in Vue Js - vue.js

I am trying to implement a search which loads user data from the backend on every word change using #input and populate in datalist, now for every change a new request is generated while the old request is still processing/pending this causes some problems. I am looking to cancel old request on every new request that will take place.
Html code in vue js
<input type="text" class="form-control" placeholder="Search Name" v-model="forms.name" list="getname" #input="inputData()" required> <datalist id="getInput" > <option v-for="option in options">{{option}}</option> </datalist>
Function to load data
axios.get('Url/GetUser/'+ this.forms.name).then((response) => {if(response.data.error){ this.errorNya = response.data; this.loading2 = false;}else{ this.errorNya.username = ""; this.options = response.data; this.loading2= false; this.disableButton = true; }

I have referred the documentation and other sources for this question, and i found a solution which suited me best.
this.cancelFunc();
//Below line creates a cancel token for this request
let axiosSource = axios.CancelToken.source();
this.request = { cancel: axiosSource.cancel };
//then we pass the token to the request we want to cancel.
axios.get('/Url/GetUser/'+ this.forms.username, {cancelToken: axiosSource.token,}).then((response) => {
if (response.data.error) {
this.errorNya = response.data;
this.loading2 = false;
} else {
this.errorNya.username = "";
this.options = response.data;
this.loading2 = false;
this.disableButton = true;
}
},
cancelFunc() {
if (this.request)
this.request.cancel();
},
i know this will not be the best way to do this, but this solved my problem.

Related

Vue2 Element-UI Datepicker force refresh for dynamic disabledDate

In the codepen below I have a Element-UI datepicker set up to show a dynamic disabled dates based on a random number.
The number of disabled dates change every time the datepicker input comes into focus.
My issue is the datepicker doesn't refresh the disabled dates until you click on a different month. The datepicker also shows the last month you were previously on when when you click off and back in.
Is there a way to force Element-UI Datepicker to refresh? I would like to make the datepicker refresh in the on focus event after the new disabled value is set.
https://codepen.io/anon/pen/rbXjLr
Element-UI Datepicker Documentation
<div id="app">
<template>
<div class="block">
<span class="demonstration">Picker with quick options</span>
<el-date-picker
v-model="value2"
type="date"
placeholder="Enter Date"
#focus="focus()"
:default-value="defaultValue"
:picker-options="pickerOptions">
</el-date-picker>
</div>
</template>
</div>
var is10Days = "";
var Randomizer = (function(){
var is10DaysSetter = function(){
if(is10Days === "") {
is10Days = Math.round(Math.random()) === 1;
}
//console.log("is10Days: " + is10Days);
return is10Days;
}
return {
Is10DaysSetter: is10DaysSetter
}
})()
var Main = {
data() {
return {
defaultValue: "",
pickerOptions: {
disabledDate(time) {
var self = this;
var date = moment()._d;
var mindate = moment().subtract(5,'d')._d;
var maxDate = moment()._d;
var isBeforeMinDate = time.getTime() < mindate;
var isAfterMaxDate = time.getTime() > maxDate;
if(is10Days !== "" && is10Days){
var alternateMinDate = date.setDate(date.getDate() - 10);
isBeforeMinDate = time.getTime() < alternateMinDate;
}
//console.log("disabledDate");
return isBeforeMinDate || isAfterMaxDate;
}
},
value2: '',
};
},
methods:{
focus: function() {
var self = this;
is10Days = "";
self.defaultValue = moment().format("YYYY-MM-DD");
Randomizer.Is10DaysSetter();
console.log("reset is10Days: " + (is10Days ? "10 days" : "5 days"));
}
}
};
var Ctor = Vue.extend(Main)
ELEMENT.locale(ELEMENT.lang.en)
new Ctor().$mount('#app')
I posted this as a feature request on Element UI's git hub and received a response:
https://github.com/ElemeFE/element/issues/15380
<el-date-picker
ref="picker" //Added this
v-model="value2"
type="date"
placeholder="Enter Date"
#focus="focus()"
:picker-options="pickerOptions">
</el-date-picker>
methods:{
focus: function() {
var self = this;
is10Days = "";
Randomizer.Is10DaysSetter();
//Added this
this.$nextTick(_ => {
this.$refs.picker.picker.date = new Date()
})
console.log("reset is10Days: " + (is10Days ? "10 days" : "5 days"));
}
}
Adding a reference to picker allowed me to override the unwanted feature of going back to the previously viewed month and solved my issue. This came with a warning that since this is not part of the public API, it could change in a future version.
Here is a link to a working code pen:
https://codepen.io/steveshore/pen/rbXjLr
I think it is about compomemt render. when your main vue app initialize, <el-date-picker>
rendered completly first.
The problem is when date-picker finished rendering, are the main vue datas ready?
It seems you pass a null into options, but select another month will force update options.
could you try this?
How to Initialize Data Properties with Prop Values
make a v-if="pickerOptions" in attr

Download after completing the request - vue-json-excel

I'm using the vue-json-excel library that helps me download data from a json.
where in the view of the vue I have:
<div class="column is-narrow" #click="btDispatch">
<json-excel
class = "button is-primary"
:data = "routes"
:fields = "json_fields_routes"
:name = "`descarga-rutas.xls`">
<span class="icon"><i class="fa fa-download"></i></span><span>Descargar entregas</span>
</json-excel>
Where:data = "routes" is the json that will be downloaded:
data () {
return {
json_fields_routes: {
ruta_id: 'id',
fecha: 'date',
estado_codigo: 'route_state',
estado: 'estado',
vehículo: 'vehicle',
conductor_codigo: 'worker.id',
conductor_nombre: 'worker.name',
hora_inicio: 'date_start_web',
hora_fin: 'date_end_web',
entregas: 'dispatches_count',
pendientes: 'pendientes',
entregados: 'entregados',
parciales: 'parciales',
no_entregados: 'noEntregados',
},
json_meta: [
[
{
key: 'charset',
value: 'utf-8',
},
],
],
}
}
According to the documentation, I must do this to download Excel and it works correctly. The problem I have is that it is downloaded when there is existing data, but I am working with data that comes from the server and previously loaded the data in the load () but it takes a long time when there is a large amount of data to enter that section of the page, so I prefer that the download button compile the data and then download.
So far I have:
methods: {
btRoute() {
this.axios.post('/routesdownload/filter_route/', this.params)
.then((response) => {
this.routes = response.data.results;
for (let i = 0; i < this.routes.length; i++) {
this.routes[i].pendientes = this.filterByStatus(this.routes[i].dispatches, 1);
this.routes[i].entregados = this.filterByStatus(this.routes[i].dispatches, 2);
this.routes[i].parciales = this.filterByStatus(this.routes[i].dispatches, 3);
this.routes[i].noEntregados = this.filterByStatus(this.routes[i].dispatches, 4);
this.routes[i].date = moment(this.routes[i].date).format('YYYY/MM/DD');
if (this.routes[i].date_start_web && this.routes[i].date_end_web != null) {
this.routes[i].date_start_web
= moment(this.routes[i].date_start_web).format('YYYY/MM/DD HH:mm:ss');
this.routes[i].date_end_web
= moment(this.routes[i].date_end_web).format('YYYY/MM/DD HH:mm:ss');
} else {
this.routes[i].date_start_web = '-';
this.routes[i].date_end_web = '-';
}
if (this.routes[i].route_state === 1) {
this.routes[i].estado = 'Borrador';
} else if (this.routes[i].route_state === 2) {
this.routes[i].estado = 'Publicado';
} else if (this.routes[i].route_state === 3) {
this.routes[i].estado = 'Iniciado';
} else {
this.routes[i].estado = 'Terminado';
}
}
});
},
}
But this simply brings the data and the weapon according to the need, but how could you after completing the application, call the function you download with this library? I could do it with a callback or a promise, but how can I call that download function?
I suposed it's a little late response, but the new version of vue-json-excel support a callback prop to fetch data before download the file.
<json-excel
class = "button is-primary"
fetch = "MyCallbackFetchData"
:fields = "json_fields_routes">
Descargar Archivo
</json-excel>
The callback can run with the async...await option so you can use asyncrounous calls like:
methods:{
async MyCallbackFetchData(){
return await axios.get('myapiurl');
}
}
IMPORTANT: This option only works when the prop data it's undefined. If data it's defined then the file it's generate with that information.
Well, apparently, the library does not have that functionality.
then to the component I put a ref:
<json-excel
ref="droute"
class = "button is-primary"
:data = "routes"
:fields = "json_fields_routes"
:name = "`descarga-rutas.xls`">
<span class="icon"><i class="fa fa-download"></i></span><span>Descargar entregas</span>
</json-excel>
and when the promise ends(has the data loaded):
this.$refs.droute.$el.click();
I call the component and download.
In my case, i'm using two button, one for load data and one for donwload. and also its much easier to implement

jQuery Form plugin submit several forms but wait until previous has ended

Users are abled to add new forms which are all submited with one button click and "jQuery Form plugin". To submit each form I iterate over forms which have a certain class.
As the users can submit images and the server has to do some work with each Image I´d like to wait until the previous submit has finished with a success statusText. Currently (I just do a timeout of 2000 which is nothing more than a "hackish" solution.)
I think I can use success function for this but do not know how I connect my submit loop with the returned success statusText. Here is a fiddle.
Here what I have:
var userform = '<form class="myForm" action="up.php" method="post"> ' +
'Name: <input type="text" name="name" />' +
'file: <input type="file" name="img[]" multiple />' +
'Comment: <textarea name="comment"></textarea>' +
'<input type="submit" value="Submit Comment" />' +
'</form>';
function showResponse(responseText, statusText, xhr, form) {
if (statusText === "success") {
console.log("the submit ended with success");
//submit next form should happen
}
}
var options = {
success: showResponse
};
$('#add').click(function() {
$(userform).appendTo('.append').each(function() {
$('.myForm').ajaxForm(options);
});
});
$("#all").click(function() {
var collection = $('.myForm');
if (collection.length > 0) {
var i = 0;
var fn = function() {
var element = $(collection[i]);
$(element).submit().addClass('done').hide("slow");
if (++i < collection.length) {
setTimeout(fn, 2000);
}
};
fn();
}
});
Thanks!
The submit handler simply does a std POST/GET so you aren't going to get a response back. You are going to want to change your code to use ajax and then have the server return a response of success = true/false or whatever you prefer
https://jsfiddle.net/mj9dbLh1/3/
Change this...
var element = $(collection[i]);
$(element).submit().addClass('done').hide("slow");
if (++i < collection.length) {
setTimeout(fn, 2000);
}
To something like...
var element = $(collection[i]);
$(element).addClass('done').hide("slow");
$.post("ajax/test.html", function( data ) {
fn(); // DO SUCCESS ACTION HERE
});
Keep in mind this will execute on each success SO you may want to first get a count of the number of forms (which gives you the number of ajax calls). Then increment that count for each success action. Once you get your total you can Display ALL SUCCESS.
Take a look at these docs for more clues on how to handle errors and what not.
http://api.jquery.com/jquery.post/

Displaying Bookshelf.js model in hbs view

I'm new to Bookshelf.js and hbs and would appreciate your help with the following:
I want to pre-fill a handlebars.js view form with data from a Bookshelf.js model.
hbs won't let me use the Bookshelf get method to get the desired attribute value: e.g. {{user.get(age)}}
I converted the model to JSON but am not able to query a specific json attribute in hbs e.g. {{user.age}}.
JSON
{"id":1,"fullName":"Mike","password":"password","email":"mike#email.com","age":38,"gender":"male","created_at":1432736718951,"updated_at":1432736718951}
Do I have to create a helper to extract the attribute value from the model?
function getUserModel(req, res, next) {
User.forge({id: req.user})
.fetch()
.then(function(user){
req.model = user;
return next()
})
.catch(function(err){
debug("Error loading userId[%s]", req.user);
return next(err);
});
}
router.use(ensureAuthenticated)
.use(getUserModel);
router.get('/', function handlePhotoUploadGet(req, res, next) {
var callback = "http://" + req.headers.host + "/cloudinary_cors.html";
var params = {return_delete_token: true, callback: callback,
timestamp: cloudinary.utils.timestamp()};
var dataFormData = cloudinary.utils.sign_request(params);
res.render('photos/upload',
{ title: 'Photo upload',
cloudinary: cloudinary,
dataFormData: JSON.stringify(dataFormData),
user: req.model }
);
});
<input type="text" name="age" aria-label="age" value="{{user.age}}" placeholder="age" class="radius {{#if errors.invalidAttributes.fullName}}error{{/if}}" />
<input type="radio" name="gender" value="male" aria-label="Male" id="male" {{#if_equal user.gender 'male'}}checked{{/if_equal}}><label for="male">Male</label>
In order to answer this question you need to provide the server-side code, to see what you push to response, and client side html as well. Please update your question.
Update:
Change this line:
req.model = user; to this: req.model = user.toJSON();

Aurelia Validation validation error detected, but no error message

I have a super simple code I'm trying to validate:
<template>
<form role="form" submit.delegate="submit()" validate.bind="validation">
<div class="form-group">
<label>Test Field</label>
<input type="text" value.bind="testField" class="form-control" validate="Description" placeholder="What needs to be done?" />
<button type="submit">Submit</button>
</div>
</form>
</template>
With the following viewmodel
define(["require", "exports", "../scripts/HttpClient", "aurelia-validation", "aurelia-framework"], function(require, exports, HttpClient) {
var AureliaValidation = require('aurelia-validation').Validation;
var MyViewModel = (function () {
function MyViewModel(httpClient, aureliaValidation, isReadyCallback) {
this.httpClient = httpClient;
var self = this;
self.setupValidation(aureliaValidation);
}
MyViewModel.prototype.activate = function (params, queryString, routeConfig) {
};
MyViewModel.prototype.setupValidation = function (validation) {
this.testField = "";
this.validation = validation.on(this).ensure('testField');
//validation
// .on(this.serviceMetadata.ServiceData[0])
// .ensure('Value');
this.validation = this.validation.notEmpty().maxLength(3);
};
MyViewModel.prototype.submit = function () {
debugger;
if (this.validation.checkAll()) {
//Do Something
}
return null;
};
MyViewModel.inject = [HttpClient, AureliaValidation];
return MyViewModel;
})();
return MyViewModel;
});
Now I got it working for the most part, and the validation is showing false on submit check, the textbox outline color changes etc., however it's not injecting the validation error messages into the DOM. There's no script error message either, how can I troubleshoot this?
Yes, I can see the validation messages in the validationProperties, but they're not written to the UI.
If your browser allows it, find the JSPM packages in the sources and put a breakpoint here, it's the point where the view strategy looks for labels to append error messages to. If you'd have this code in the open, I'd be happy to have a look for you.
Also, what version of aurelia/aurelia-validation are you using?
And finally, did you modify your sample before posting?
`<input value.bind="testField" validate="Description" />`
These two attributes are contradictory. It binds the value to testField, but then you use the validate attribute to explicitly show validation messages for property "Description".