Was wondering why my code below isnt working. Basically I am fetch data from my url to delete something. on delete, it should refresh. however it doesnt seem to let me do that. But what it does is delete the post if i manually refresh the page.
Works when I use Ajax method though which I don't know why.
Fetch method
const deleteBTN = document.querySelectorAll('.deleteBtn');
const update = document.querySelectorAll('.postedNote');
console.log(deleteBTN);
for (let btn of deleteBTN) {
btn.addEventListener('click', (e) => {
console.log("Delete from front end");
console.log(btn[btn])
let id = e.target.dataset.btn;
fetch('http://localhost:3000/api/notes' + '/' + id, {
method: "DELETE",
}).then(() => {
Location: reload()
})
})
}
Ajax method
$(".deleteBtn").click((e) => {
$.ajax({
type: "DELETE",
url: `http://localhost:3000/api/notes/${e.target.dataset.btn}`,
success: function () {
console.log("delete success");
},
}).done(
setTimeout(() => {
window.location.reload();
}, 500)
);
});
We can reload by using window.location.reload as already doing on ajax success.
Kindly find below as code snippet
const deleteBTN = document.querySelectorAll('.deleteBtn');
const update = document.querySelectorAll('.postedNote');
console.log(deleteBTN);
for (let btn of deleteBTN) {
btn.addEventListener('click', (e) => {
console.log("Delete from front end");
console.log(btn[btn])
let id = e.target.dataset.btn;
fetch('http://localhost:3000/api/notes' + '/' + id, {
method: "DELETE",
}).then(() => {
window.location.reload();
})
})
}
Also, a few considerations below
The use of Ajax is defeated here as we are reloading the page.
Either
we should perform some DOM manipulation to delete the deleted post
from the page
Or,
in case we are using React, we can bind posts to state and then
delete the deleted post on API success call, so that component is
re-rendered and we do not need to refresh the page.
I think you should'nt try to reload the page when removing one of the elements,
instead I would have checked the response status and manually update the DOM to make the deleted element disappear if response says it was removed successfully.
Related
A have an 'Add to basket' button which submits a form via Ajax with all products' details. At the moment the module responsible for that operation is loaded straight away when the website is loaded. I would like it to be loaded only when the button is clicked, though. This is what I have so far:
$('form:not(.contact-form__items)').on('submit', event => {
import('./modules/adding-products-to-basket.js')
.then(module => {
module.AddingProductsToBasket.addProductToBasket(event);
});
});
Module's content:
export const AddingProductsToBasket = {
addProductToBasket (event) {
const _this = AddingProductsToBasket;
event.preventDefault();
$.ajax({
url: 'basket',
method: 'POST',
data: $(event.currentTarget).serialize(),
dataType: 'text',
success: function(response) {
_this.openAddedToBasketLightbox();
}
},
});
}
};
I'm not getting any errors in the console but the problem is that
event.preventDefault() inside addProductToBasket doesn't do it's job, so user is taken to the basket page instead of staying on the page where the 'Add to basket' button is.
Thank you both for your help. It's working now.
Loading the module when the form shows:
if ($('form:not(.contact-form__items)').length) {
import('./modules/adding-products-to-basket.js')
.then(module => {
$('form:not(.contact-form__items)').on('submit', event => {
module.AddingProductsToBasket.addProductToBasket(event);
});
});
}
Loading the module not when the form loads but when it is submitted:
(event.preventDefault() in AddingProductsToBasket() can be removed)
$('form:not(.contact-form__items)').on('submit', event => {
event.preventDefault();
import('./modules/adding-products-to-basket.js')
.then((module) => {
module.AddingProductsToBasket.addProductToBasket(event);
});
});
I have a function that gets the form values and send them Flask backend to retrieve info from SQLite database. I'm using jQuery $.ajax() with POST to allow for better error handling.
Because the ajax is async I'm passing a callback to logTable(callback) as suggested here. I need the logTable() to run after I input the form data and click the submit button. I'm using $("#some-id").click() to achieve this.
const logsTable = (callback) => {
const startDate = $("#start-date").val();
const endDate = $("#end-date").val();
const container = $("#programs").val();
const server = window.location.host;
const url = `http://${server}/api/log-info`;
let logs = "";
let dataToSend = {
start_date: startDate,
end_date: endDate,
program: container,
};
$.ajax({
type: "POST",
url: url,
data: dataToSend,
success: (data) => {
callback(data);
},
error: (jqXHR, textStatus, errorThrown) => {
alert(errorThrown);
},
});
};
$("#submit-button").click(() => {
return logsTable((data) => {
$("#logs-div").html(data);
alert("Success");
});
});
I receive the alert with Success, the data briefly appears on the page and disappears. If run the code below directly it, it runs on page reload and posts an empty list to a page because no data was sent to the backend.
logsTable((data) => {
$("#logs-div").html(data);
alert("Success");
});
I need to somehow the function call above to a Submit button. How can I do that?
I'm using PayPal Smart button on my web site, and after each payment is made the user is able to make another new payment with PayPal smart button. The problem is that once I've created my PayPal button I'm unable to set the new createOrder in it with new orderID.
So in my website I have the following function which init the PayPal button if there is yet a pending order or it's called when a new order is made and I get a new orderID.
function initPayPal(orderID, publicKey) {
var paymentID = $("#paypal-button-container").data("payment-id")
var PAYPAL_SCRIPT =
"https://www.paypal.com/sdk/js?client-id=" + publicKey + "¤cy=EUR&intent=capture&commit=false&vault=true";
var script = document.createElement("script");
script.setAttribute("src", PAYPAL_SCRIPT);
script.onload = function () {
paypal
.Buttons({
style: {
shape: "rect",
color: "gold",
layout: "horizontal",
label: "paypal",
tagline: false,
height: 52,
},
createOrder: async function () {
$(".body-payments").hide();
$(".loader-payments").show();
const res = await fetch(
"/api/payment/paypal/" + paymentID + "/" + orderID,
{
method: "post",
headers: {
"content-type": "application/json",
},
credentials: "include",
}
);
const data = await res.json();
return data.id;
},
onApprove: async function (data) {
const res = await fetch(
"/api/payment/paypal/capture/" + paymentID + "/" + data.orderID,
{
method: "post",
headers: {
"content-type": "application/json",
},
credentials: "include",
}
);
if (localStorage.STBOrder) {
localStorage.removeItem("STBOrder");
}
$("#modalPayments").modal("hide");
$("#modalSuccess").modal("show");
$(".body-payments").show();
$(".loader-payments").hide();
},
onCancel: function (data) {
$(".body-payments").show();
$(".loader-payments").hide();
},
})
.render("#paypal-button-container");
};
document.head.appendChild(script);
}
Client id is set dynamically as each user on its own page will get the payment on its own account. The issue here is that the button is initiated the first time all works fine, but if I dismiss the order and I call this function again it will create another button instead of setting new values to existing (already rendered) one.
There should be no need to init the button more than once.
Initialize the button one time (on page load).
Then, inside createOrder, ensure paymentID and orderID reference non-local variables or are replaced with function calls that will return the correct value at the time you want them to, e.g. some kind of getOrderID() of yours, and $("#paypal-button-container").data("payment-id") , in place of your existing local variables
In the unlikely event that you really did need to render the buttons more than once, you could save a reference to myButtons = paypal.Buttons({..}) before calling .render() --- and then, later myButtons.close() before saving a new reference to and rendering a new buttons object. But again, there should be no reason to do that here.
Using the Smart Payment buttons, there is a 3-4 second delay after the payment pop-up window closes. It takes 3-4 seconds after the close of the transaction window to fire the onApproval event which gets the transaction ID needed to process an order.
This causes trouble as the buyer could close the window in the meantime (as nothing seems to happen) and the event is never received, thus the order not processed (although paid for).
Here is the code:
paypal.Buttons({
createOrder: function(data,actions) {
// do some stuff
return fetch('/createOrder', {
method: 'post',
headers: {
'content-type': 'application/json'
}
}).then(function(res) {
return res.json();
}).then(function(data) {
return data.orderID;
});
},
// onApprove will be fired 3-4 second AFTER the popup of transaction closes
onApprove: function(data, actions) {
return fetch('captureOrder', {
method: 'post',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
orderID:data.orderID
})
}).then(function(res) {
return res.json();
}).then(function(details) {
});
}
}).render(selector);
Is there any way to have the popup close AFTER the even is fired? Otherwise the only work-around would be to make an overlay with a spinner (or something similar) that will disappear once the onApproval is received. But that is cumbersome. The pop-up really shouldn't close before the event is fired.
I haven't observed that long of a delay myself, and it shouldn't cause issues as the buyer should wait for their confirmation in any case, but well it is as it is.
You can use the onClick method to trigger a please wait / spinner or whatever if you feel it's necessary, and nuke it within your onApprove's fetch (and also an onError and onCancel function). But you're overcomplicating things.
use this
// Finalize the transaction after payer approval
onApprove: function(data, actions) {
return actions.order.capture().then(function(orderData) {
// Successful capture! For dev/demo purposes:
console.log('Capture result', orderData, JSON.stringify(orderData, null, 2));
var transaction = orderData.purchase_units[0].payments.captures[0];
alert('Transaction '+ transaction.status + ': ' + transaction.id + '\n\nSee console for all available details');
// When ready to go live, remove the alert and show a success message within this page. For example:
// var element = document.getElementById('paypal-button-container');
// element.innerHTML = '';
// element.innerHTML = '<h3>Thank you for your payment!</h3>';
// Or go to another URL: actions.redirect('thank_you.html');
});
}
I need to check if some values in submitted data have expected values. To do this i tried to access and sent data by XMLHttpRequest in Cypress during the request run.
describe('test submitted data', () => {
it('some data is changed', () => {
submitBtn().click({force: true});
//in this case Cypress doesnt get into this debugger point
cy.server({
onAnyRequesty: (props) => {
debugger
}
});
//in this one Cypress go into and stops at the point but
//the data variable doesnt contrain submitedData
cy.route('PUT', `${APP_CONTEXT}/api/model/${modelId}`, (data) => {
debugger;
});
});
});
Data is sent by the way below:
$.ajax({
url: url,
method: "PUT",
data: "{"inputData":"123"}",
contentType: "application/json",
success: () => {},
error: () => {}
});
What am i doing wrong? Thanks
One more thing: and how to make Cypress check if the data condition is met? for example:
it('some data is changed', () => {
submitBtn().click({force: true});
cy.route('PUT', `${APP_CONTEXT}/api/model/${modelId}`, (data) => {
const parsedData = JSON.parse(data);
// the test is passed if the value is equal
expect(parsedData.inputData).to.eq('123');
});
UPDATE
i tried proposed answer from #richard-matsen and different callBack keys but neither were working:
onResponse
onAnyResponse
onRequest
onAnyRequest
But callback function in neither of them didnt run
it("Signature removed from the field and empty value submitted", () => {
cy.server();
submitBtn().click();
//here i check the put url as an url submitting to
cy.log(`${BASE_URL}/api/data/${formId}/${modelId}`);
cy.route({
method: "PUT",
url: `${BASE_URL}/api/data/${formId}/${modelId}`,
onAnyRequest: (data) => {
const signValue = JSON.parse(data)[`${modelId}|sign_2||`];
debugger;
cy.log(signValue);
expect(signValue).to.eq(null)
}
})
})
UPDATE UPDATE
#richard-matsen ,thanks, you were right, I did an error in method options, but I decided to simplify the route options but still the debugger cannot get in neither handler:
it("Submitted data", () => {
cy.server({ whitelist: (xhr) => console.log('custome log: server', xhr) });
submitBtn().click({force: true});
cy.route({
url: /.+/,
onResponse: (data) => {
debugger;
cy.log('onResponse signature value - ' + data);
},
onAnyResponse: (data) => {
debugger;
cy.log('onAnyResponse signature value - ' + data);
},
onRequest: (data) => {
debugger;
cy.log('onRequest signature value - ' + data);
},
onAnyRequest: (data) => {
debugger;
cy.log('onAnyRequest signature value - ' + data);
}
})
})
Also tried to click submission btn right after cy.route, but that wasn't working as well.
I appreciate your help!
The patterns for using cy.route() are
cy.route(url)
cy.route(url, response)
cy.route(method, url)
cy.route(method, url, response)
cy.route(callbackFn)
cy.route(options)
Looks like your command is interpreted as #4, but response is the value used to stub. Never seen it with a function, so is best guess.
To be sure, use the pattern with options and put function in onResponse
cy.route({
method: 'PUT',
url: `${APP_CONTEXT}/api/model/${modelId}`,
onResponse: (data) => {
expect(parsedData.inputData).to.eq('123');
}
})
Also onAnyRequesty: (props) => change to onAnyRequest: (props) =>.
In your latest code,
onAnyRequest: (data) => {,
data is already parsed so JSON.parse(data) causes an error.
In my test, I get a weird error about cross-origin when trying to re-parse within onResponse() (Expecting a message like 'Unexpected token o in JSON at position 1').
In any case, put the debugger up one line to avoid other code problems.
If cy.route() is not matching the url, you can see all calls with (temporary)
cy.server({ whitelist: (xhr) => console.log('server', xhr) }).
Maybe APP_CONTEXT !== BASE_URL?
Submit can be a native event which won't be captured by Cypress.
I think you can test if this is so, see Submit a POST form in Cypress and navigate to the resulting page.
If you do the following instead of submitBtn().click({force: true}) and the cy.route() does pick it up, then you have a native event.
cy.visit({
url: `${BASE_URL}/api/data/${formId}/${modelId}`,
method: "PUT",
form: true,
body: {
inputData :"123"
}
});