I am trying to create an AJAX script that will pull data via an API and display it on a page as HTML. Everything using the route below seem to work fine in Postman, but I can't get it to translate in my JS file.
I know I'm calling the URL incorrectly and I'm pretty sure it's because of the :id. I'm not sure how to correct it. I feel like I've tried every URL iteration, but I'm missing something.
// router.REST_VERB('EXPRESS_ROUTE', api.ACTION)
router.get('/', api.list);
router.post('/', api.create);
router.get('/:id', api.read);
router.put('/:id', api.update);
router.get('/delete/:id', api.delete);
Here are my update and delete:
/ AJAX PUT - Update Reminder
function updateReminder(id) {
$.ajax({
type: 'PUT',
url: '/api/',
data: JSON.stringify({
'id': $('#editId').val(),
'name': $('#name').val(),
'occasion': $('#occasion').val(),
'lastgift': $('#lastgift').val()
}),
success: (item) => {
document.location.href="/";
},
contentType: "application/json",
dataType: 'json'
});
}
// AJAX DELETE request - Delete Reminder
function deleteReminder(id) {
$.ajax({
type: 'DELETE',
url: '/api',
data: JSON.stringify({
'id': id
}),
success: (item) => {
document.location.href="/delete";
},
contentType: "application/json",
dataType: 'json'
});
}
EDIT
Here is the controller code for update and delete:
ApiController.update = (req, res) => {
reminderService.update(
req.params.id,
{
name: req.body.name,
occasion: req.body.occasion,
lastgift: req.body.lastgift,
prefgift: req.body.prefgift
},
{new: true}
)
.then((item) => {
res.json(item);
})
.catch((err) => {
if (err) console.log(err);
});
};
ApiController.delete = (req, res) => {
reminderService.delete(req.params.id)
.then((item) => {
res.json(item);
})
.catch((err) => {
if (err) {
res.end("Didn't delete")
}
});
};
and here is the service code:
ReminderService.update = (id, reminderObj) => {
return Reminder.findByIdAndUpdate(
id,
{
$set: reminderObj
},
{
new: true
}
)
.then((item) => {
return item;
})
.catch((err) => {
if (err) {
res.end("You're in reminderService!")
}
});
};
ReminderService.delete = (reminderId) => {
return Reminder.deleteOne({ '_id': reminderId })
.then((item) => {
return item;
})
.catch((err) => {
throw err;
});
};
Your route for delete is wrong, you should use delete instead of get.
router.get('/', api.list);
router.post('/', api.create);
router.get('/:id', api.read);
router.put('/:id', api.update);
router.delete('/:id', api.delete);
In your ajax requests, your url is missing the ids
// AJAX PUT - Update Reminder
function updateReminder(id) {
$.ajax({
type: 'PUT',
url: '/'+id,
data: JSON.stringify({
'id': $('#editId').val(),
'name': $('#name').val(),
'occasion': $('#occasion').val(),
'lastgift': $('#lastgift').val()
}),
success: (item) => {
document.location.href="/";
},
contentType: "application/json",
dataType: 'json'
});
}
// AJAX DELETE request - Delete Reminder
function deleteReminder(id) {
$.ajax({
type: 'DELETE',
url: '/'+id,
data: JSON.stringify({
'id': id
}),
success: (item) => {
document.location.href="/delete";
},
contentType: "application/json",
dataType: 'json'
});
}
One thing I'm skeptical about is that you use JSON.stringify on your data. Does your API specifically require JSON or did you do just do that to try to get it t work?
Related
I have a Cypress test:
describe('Create a session ', () => {
it('creates a session', () => {
cy.request({
method: 'POST',
url: `${Cypress.env('apiURL')}/api/v1/user/login/`,
form: true,
body: {
email: Cypress.env('email'),
password: Cypress.env('password'),
},
}).then((response) => {
expect(response.status).to.eq(200);
cy.task('setKey', response.body.data.key);
});
});
});
This POST returns some session data needed to create a dummy account:
describe('Create a company ', () => {
it('creates a company', () => {
cy.task('getKey')
.then((data: Key) => {
key = data;
})
.then(() => {
createNonce();
cy.request({
method: 'POST',
url: `${Cypress.env('apiURL')}/api/v1/cli/`,
headers: {
'X-Auth-Timestamp': epochTime(),
'X-Auth-Key': key.key,
'X-Auth-Nonce': nonce,
'X-Auth-Signature': createSignature(),
},
body: {
args: ['seeder', 'create', 'abc1'],
},
}).then((response) => {
expect(response.status).to.eq(200);
// TODO: we need some REST endpoints to return a JSON object instead of a string
data = JSON.parse(response.body.substring(response.body.indexOf('{')));
cy.task('setCompany', data);
});
});
});
});
I'm not sure I need these functions to be tests since they don't test anything, but just do a POST request. Is it possible to maybe move the functionality into a cypress task?
You can add the post request in your commands file:
function postRequest() {
cy.request({
method: 'POST',
url: `${Cypress.env('apiURL')}/api/v1/cli/`,
headers: {
'X-Auth-Timestamp': epochTime(),
'X-Auth-Key': key.key,
'X-Auth-Nonce': nonce,
'X-Auth-Signature': createSignature(),
},
body: {
args: ['seeder', 'create', 'abc1'],
},
})
}
Cypress.Commands.add('postRequest', postRequest)
An assuming all the rest of your code is fine, and you want only to abstract the logic; then in your test you can invoke that command:
describe('Create a company ', () => {
it('creates a company', () => {
cy.task('getKey')
.then((data: Key) => {
key = data;
})
.then(() => {
createNonce();
cy.postRequest().then((response) => {
expect(response.status).to.eq(200);
data = JSON.parse(response.body.substring(response.body.indexOf('{')));
cy.task('setCompany', data);
});
});
});
});
You can move these into before() or beforeEach() so they will be separate from your tests.
describe('Create a company ', () => {
before(() => {
cy.task('getKey')
.then((data: Key) => {
key = data;
})
.then(() => {
createNonce();
cy.request({
method: 'POST',
url: `${Cypress.env('apiURL')}/api/v1/cli/`,
headers: {
'X-Auth-Timestamp': epochTime(),
'X-Auth-Key': key.key,
'X-Auth-Nonce': nonce,
'X-Auth-Signature': createSignature(),
},
body: {
args: ['seeder', 'create', 'abc1'],
},
}).then((response) => {
expect(response.status).to.eq(200);
// TODO: we need some REST endpoints to return a JSON object instead of a string
data = JSON.parse(response.body.substring(response.body.indexOf('{')));
cy.task('setCompany', data);
});
});
})
it('creates a company', () => {
//test code
});
});
img1:
https://t44-post-cover.s3.eu-central-1.amazonaws.com/gpcm
img2:
https://t44-post-cover.s3.eu-central-1.amazonaws.com/h5fy
I can download only img2, but not img1. Why? For both first url was presigned, then uploaded like this:
return axios({
method: 'put',
url: res.data,
data: propsAndFile.file,
withCredentials: false,
headers: { 'x-amz-acl': 'public-read' },
}).then((res2) => {
if (propsAndFile.andThen) {
return propsAndFile.andThen()
} else {
return res2
}
})
Trying to use Uppy JS lib to upload file throug Laravel. Setted up simple upload form with there params:
const options = {
endpoint: '/parts/image-upload',
headers: {
'X-XSRF-TOKEN': $('meta[name="csrf-token"]').attr('content'),
},
};
uppyDashboard.use(XHRUpload, options);
And on the backend I'm getting
Illuminate\Contracts\Encryption\DecryptException: The payload is invalid. in file /Users/rd/Projects/xxx/vendor/laravel/framework/src/Illuminate/Encryption/Encrypter.php on line 195
It's like Laravel trying to decrypt something what is already decrypted, anyway I'm in dead end.
You can this code
var uppy = new Uppy.Core({
// debug: (...args) => console.debug(`[Uppy] [${getTimeStamp()}]`, ...args),
// warn: (...args) => console.warn(`[Uppy] [${getTimeStamp()}]`, ...args),
// error: (...args) => console.error(`[Uppy] [${getTimeStamp()}]`, ...args),
autoProceed: true,
restrictions: {
maxFileSize: 2000000,
maxNumberOfFiles: 10,
minNumberOfFiles: 1,
allowedFileTypes: ['image/*']
}
});
uppy.use(Uppy.Dashboard, {
target: ".UppyDragDrop",
inline: true,
showLinkToFileUploadResult: false,
showProgressDetails: true,
hideCancelButton: true,
hidePauseResumeButton: true,
hideUploadButton: true,
proudlyDisplayPoweredByUppy: false,
locale: {} });
Here's how I implemented it
<script type="text/javascript">
$(document).ready(function() {
$('[id*=drag-drop-area]').each(function(){
var listing_id = $(this).attr('class');
var uppy = new Uppy.Core({
allowMultipleUploadBatches: true,
restrictions: {
maxFileSize: 100000000,
// maxNumberOfFiles: 8,
minNumberOfFiles: 1,
allowedFileTypes: ['image/*', '.jpg', '.jpeg', '.png']
}
})
.use(Uppy.Dashboard, {
inline: true,
target: "#"+$(this).attr('id')+""
})
.use(Uppy.XHRUpload, {
endpoint: 'upload',
formData: true,
bundle: true,
headers: {
'X-CSRF-Token': " {{ csrf_token() }} "
},
});
uppy.on('upload-success', (file, response) => {
response.body.data.forEach(function (item, index) {
console.log(listing_id);
var token =
$('meta[name="csrftoken"]').attr('content');
$.ajax({
url: 'attach',
type: 'POST',
data: { '_token' : token, item, listing_id},
success: function(response)
{
console.log('Updated');
},
error:function (e) {
console.log(e);
}
});
});
window.location.reload();
});
});
});
</script>
You create the endpoint which is the route name and attach at
endpoint: ""
Then you return a response which you grab and do whatever on the last section.
uppy.on('upload-success', (file, response) => {
response.body.data.forEach(function (item, index) {
console.log(listing_id);
var token =
$('meta[name="csrftoken"]').attr('content');
$.ajax({
url: 'attach',
type: 'POST',
data: { '_token' : token, item, listing_id},
success: function(response)
{
console.log('Updated');
},
error:function (e) {
console.log(e);
}
});
});
window.location.reload();
});
I hope this helps
I have created ajax method in one class in my js file. Below is enclosed for the reference
var ajaxcall =
{
SitePath: '',
data: '',
url: '',
callbackfunction: '',
fileElementId: '',
AjaxRequest: false,
callback: true,
async: false,
folder: '',
filename: '',
Call: function () {
if (ajaxcall.AjaxRequest == true) {
alert(ajaxcall.AjaxRequest);
return;
}
else {
try {
ajaxcall.AjaxRequest == true;
alert('b');
$.ajax({
type: "POST",
url: ajaxcall.url,
data: ajaxcall.data,
contentType: "application/json; Characterset=utf-8",
dataType: "json",
async: false,
success: function (data) {
if (ajaxcall.callback == true) {
ajaxcall.callbackfunction(data);
}
},
error: function (request, status, error) {
//alert("Exception Handling : \n" + request.responseText);
alert('Unable to process the request at this moment! Please try again later.');
},
complete: function () {
ajaxcall.AjaxRequest = false;
}
});
}
catch (e) {
ajaxcall.AjaxRequest == false;
// alert("Error Catch : " + e.Description + '\n' + 'Message: ' + e.Message);
}
}
},
AjaxFileUpload: function () {
$.ajaxFileUpload({
type: "POST",
url: "../GenericHandlers/FileUploader.ashx?path=" + ajaxcall.folder,
dataType: 'json',
async: false,
secureuri: false,
fileElementClass: ajaxcall.fileElementClass,
success: function (data) {
var data = data.toString();
ajaxcall.filename = data.substring(6, data.length - 7);
alert(ajaxcall.filename);
return true;
}
});
}
};
Now i want to show a div when ajax call starts and hide after finish.
So for that i have used
$(document).ready(function(
$('#Loading').ajaxStart(function () {
alert('a');
$('#Loading').show();
}).ajaxStop(function () {
$('#Loading').hide();
});
});
But when i call the ajax method (defined above in the class), control goes into ajax method first then in ajaxStart.
I don't know why it is happening. Please help.
Use the recommended global for these:
$.ajaxStart(function() {
$("#Loading").show();
});
$.ajaxComplete(function() {
$("#Loading").hide();
});
Try it this way attached to your Loading id element:
$("#Loading").ajaxStart(function() {
$(this).show();
});
$("#Loading").ajaxComplete(function() {
$(this).hide();
});
AjaxStart called when the http request start, not when the ajax method executes.
I'm trying to use the ajax blockmanager plugin to manage my jquery ajax requests, but I'm not sure how to implement it...
// Follow button click event
$('#loginBtn').click(function () {
var that = this;
var request = {
'username': $('#txtUsername').val(),
'password': $('#txtPassword').val()
};
var params = $.toJSON(request);
ajaxManager.add($.ajax({
type: "POST",
url: "ajax/Login.aspx/Login",
data: params,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (result) {
if (result.d === true) {
window.location = "dashboard.aspx";
}
else {
$('#errorMessage').slideDown();
}
}
}));
I know it's a bit outdated question... But if anyone comes across this issue:
You are passing the already created/started request as a parameter to the manager.
You should only pass its options. The request will be created and handled by the manager.
ajaxManager.add({
type: "POST",
url: "ajax/Login.aspx/Login",
data: params,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (result) {
if (result.d === true) {
window.location = "dashboard.aspx";
}
else {
$('#errorMessage').slideDown();
}
}
});
Do you have ajaxManager instantiated?
//create an ajaxmanager named cacheQueue
var ajaxManager = $.manageAjax.create('cacheQueue', {
queue: true,
cacheResponse: true
});
You first create the manager
this.ajaxManager = $.manageAjax.create("aiapi", {
queue: true,
cacheResponse: true,
maxRequests: 3,
abort: this.abortCallback
});
where the queue of calls is active, max concurrent requests are 3, and the caching is enabled. The common abortCallback is like
this.abortCallback = function (response) {
Logger.log("APIManager.abortCallback " + Utils.toString(response));
};
It's convenient to add the common ajaxSetup setup like
$.ajaxSetup({
cache: true,
timeout: 10 * 1000
});
Here you can see the response timeout in msec set to 10 sec.
You then do a GET like
this.DoGet = function (url, method, timeout) {
return new Promise((resolve, reject) => {
var options = {
type: 'GET',
url: url + method,
contentType: "application/json",
timeout: (15 * 1000) // sets timeout to 60 seconds
};
if (timeout) options.timeout = timeout;
const errorCallback = function (error) {
console.error(error);
return reject(error);
};
const successCallback = function (data) {
return resolve(data);
};
const completeCallback = function (data) {
return resolve(data);
};
options.error = errorCallback;
options.success = successCallback;
//options.complete= completeCallback;
$.manageAjax.add("default-queue", options);
/*$.ajax(options)
.done(function (data) {
return resolve(data);
})
.fail(function (error) {
console.error(error);
return reject(error);
})
.always(function () {
// called after done or fail
});*/
});
You can see in the comment the version without the ajax manager. And it the same way to POST is like
this.DoPost = function (url, method, body, timeout) {
try {
body = JSON.stringify(body);
} catch (error) {
console.error(body);
return reject(error);
}
return new Promise((resolve, reject) => {
var options = {
type: 'POST',
url: url + method,
data: body,
contentType: "application/json",
dataType: 'json',
timeout: (15 * 1000) // sets timeout to 60 seconds
};
if (timeout) options.timeout = timeout;
const errorCallback = function (error) {
console.error(error);
return reject(error);
};
const successCallback = function (data) {
return resolve(data);
};
options.error = errorCallback;
options.success = successCallback;
$.manageAjax.add("default-queue", options);
/*$.ajax(options)
.done(function (data) {
return resolve(data);
})
.fail(function (error) {
console.error(error);
return reject(error);
})
.always(function () {
// called after done or fail
});*/
});
}//DoPost
The important thing here is the name of the ajax queue when adding a new GET / POST request via the api
$.manageAjax.add("default-queue", options);
This means basically that you can have one or more queues, that improves your requests parallelism.