Symfony 3/4 : delete a table row from a database through AJAX - javascript

I am a little bit stuck on my Symfony code.
Let me explain,
I have a todo-list table in my database containing :
An ID called : id
A name field called : todo
And 3 others fields that don't matter : "completed", "created_at", "updated_at".
Before going further : here is my codes,
The concerned Controller :
/**
* #Route("/todos/delete/{id}", name="todo.delete", methods={"POST"})
* #param Todo $todo
* #param ObjectManager $manager
* #param Request $request
* #return \Symfony\Component\HttpFoundation\RedirectResponse
*/
public function delete(Todo $todo, ObjectManager $manager, Request $request)
{
$manager->remove($todo);
$manager->flush();
if ( $request->isXmlHttpRequest()) {
return $this->redirectToRoute('todo.home', [
'id' => $todo->getId()
]);
}
throw $this->createNotFoundException('The todo couldn\'t be deleted');
}
The view :
{% extends 'base.html.twig' %}
{% block title %}Todos{% endblock %}
{% block content %}
<br>
<form action="{{ path('todo.create') }}" method="post">
<input type="hidden" name="token" value="{{ csrf_token('todo-create') }}"/>
<label for="todo">Todo</label>
<input type="text" id="todo" name="todo" class="form-control input-group-lg" placeholder="Create a new todo">
</form><br>
{% for todo in todos %}
{{ todo.todo }}
Update
x
{% if todo.completed %}
Completed !
{% else %}
Mark as completed
{% endif %}
<hr>
{% endfor %}
{% endblock %}
We focus on :
x
The JavaScript :
$(document).ready(function () {
$('.js-delete-todo').on('click', function (e) {
e.preventDefault();
var url = $(this).attr('href');
delTodo(url);
function delTodo(url) {
$.ajax({
type: "POST",
url: url
}).done(function (data) {
$('#id').remove();
}).fail(function () {
alert('Could not be deleted');
});
}
});
});
Actually,
Everything seems to work : it does a POST ajax request, and delete the row in my table in my database.
The only issue is that I have to hit F5 to see it.
How can I make it work without reloading the page nor hitting the F5 hotkey?

In your symfony code you should return JSON format like here.
Wrap your todo in container like this
{% for todo in todos %}
<div id="todo-{{todo.id}}">
// your todo staff here
</div>
{% endfor %}
Then change your javascript to
function delTodo(url) {
$.ajax({
type: "POST",
url: url
}).done(function (data) {
var id = JSON.parse(data).id;
$('#todo-' + id).remove();
}).fail(function ()
alert('Could not be deleted');
});
}

Related

404 error while implementing async function

detail.html
{% if request.user.is_authenticated %}
<form class="like-forms d-inline" data-book-id="{{ book.pk }}" data-review-id="{{ review.pk }}">
{% csrf_token %}
<h4>
{% if request.user in review.like_users.all %}
<button type="submit" id="btn-like-{{ review.pk }}" class="btn-none bi bi-emoji-heart-eyes"></button>
{% else %}
<button type="submit" id="btn-like-{{ review.pk }}" class="btn-none bi bi-emoji-angry"></button>
{% endif %}
</h4>
</form>
{% endif %}
<!-js-->
<script>
const likeForms = document.querySelectorAll('.like-forms')
const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value
likeForms.forEach((form) => {
form.addEventListener('submit', function (event) {
event.preventDefault()
const reviewId = event.target.dataset.reviewId
const bookId = event.target.dataset.bookId
axios({
method: 'post',
url: `/detail/${bookId}/like/${reviewId}/`,
headers: {'X-CSRFToken': csrfToken},
})
.then(response => {
const isLiked = response.data.isLiked
const likeBtn = document.querySelector(`#btn-like-${reviewId}`)
console.log(isLiked)
if (isLiked === true) {
likeBtn.classList.add('bi-emoji-heart-eyes')
likeBtn.classList.remove('bi-emoji-angry')
} else {
likeBtn.classList.add('bi-emoji-angry')
likeBtn.classList.remove('bi-emoji-heart-eyes')
}
})
.catch(error => {
console.log(error)
})
})
})
</script>
urls.py
path("detail/<int:book_pk>", views.detail, name="detail"),
path("detail/<int:book_pk>/like/<int:review_pk>", views.like, name="like"),
.....
views.py
def detail(request, book_pk):
reviews = Review.objects.order_by("-pk")
book = Book.objects.get(pk=book_pk)
context = {
"reviews": reviews,
"book": book,
}
return render(request, "review/detail.html", context)
def like(request, book_pk, review_pk):
review = Review.objects.get(pk=review_pk)
book = Book.objects.get(pk=book_pk)
if review.like_users.filter(pk=request.user.pk).exists():
review.like_users.remove(request.user)
is_liked = False
else:
review.like_users.add(request.user)
is_liked = True
data = {
"isLiked": is_liked,
}
return JsonResponse(data)
I got a 404 not found error while writing code for a "like" async function.
data-book-id="{{ book.pk }}" data-review-id="{{ review.pk }} in the form
I seem to get pk values ​​for books and book reviews, but I don't know what causes the 404 error.
Console error message : POST http://localhost:8000/detail/1/like/2/ 404 (Not Found)
I am running this on localhost (http://localhost:8000/)
Thanks for reading..!

How to create if statement on a redirect to change Django model

I am trying to create a if statement in my Django view that detects when I am redirected to my complete order url. I want to do this because I would like to change my Django model Order 'complete' field to true. My redirect is coming from a javascript function in my paypal intergration.
checkout.html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<h1>Checkout</h1>
<div class='container'>
<div class='row'>
<div class='col-6'>
<form action="" method='post' id='payement-form'>
{% csrf_token %}
<!-- {{ form|crispy }} -->
<div class='col-12' id='paypal-button-container'></div>
</form>
<script
src="https://www.paypal.com/sdk/js?client-id="> // Required. Replace YOUR_CLIENT_ID with your sandbox client ID.
</script>
<script>
function redirect() {
var url = "{% url 'complete-order' %}"
window.location.href = url
}
paypal.Buttons({
createOrder: function (data, actions) {
return actions.order.create({
purchase_units: [{
amount: {
value: '0.01'
}
}]
});
},
onApprove: function (data, actions) {
// This function captures the funds from the transaction.
return actions.order.capture().then(function (details) {
// This function is the redirect
redirect()
alert('Transaction completed by ' + details.payer.name.given_name);
});
}
}).render('#paypal-button-container');
</script>
</div>
{% endblock content %}
views.py
#login_required(login_url='login')
def checkout(request):
order = Order.objects.get(user=request.user, complete=False)
context = {
'order': order
}
return render(request, 'videogames/checkout.html', context)
#login_required(login_url='login')
def paymentComplete(request):
order = Order.objects.get(user=request.user, complete=True)
context = {
'order': order
}
return render(request, 'videogames/complete.html', context)
There are many ways that should be selected according to your project.
before redirection, in the view , call a link with Ajax to change the status
#login_required(login_url='login')
def paymentSetComplete(request):
order = Order.objects.get(id=request.payment_id=,user=request.user, complete=False)
order.complete=True
order.save() # or update directly
return
Change the status when the request to load the complate page was sent to django
I do not know what measures you have taken to secure and prevent the fake purchases
But know that users can repeat requests that come to the server

pass id of foreign key to the form via post

I've created a new field ("responsavel") on my db for this entity ("Multa"), "responsavel" is a foreign key to another table (Usuario) and I want it to be shown on my form as an select with just some objects (that's why the $desligados I'm passing to the front) for the user to choose and then pass it to the back.
I've been able to do it with $.postbut I'm doing other things after the submit is passed to the controller so I've included a $(this).unbind('submit').submit(); but now it's like I'm submitting the form two times, and one of them is not submitting with the "responsavel" value.
This is my form:
class MultaType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('usuario')
->add('departamento')
->add('cliente')
->add('responsavel',null, ['attr'=>['style'=>'display:none;'], 'label'=> false])
->add('razaoSocial', null, ['label'=>'Cliente'])
->add('valor',null, ['label'=>'Valor Pago'])
->add('tipoPagamento', ChoiceType::class, ['choices'=>['Selecionar'=>0,'Integral'=>1,'Somente Encargos'=>2], 'required' => true], ['label' => 'Tipo de Pagamento'])
->add('dtRegistro', DateTimeType::class, ['widget'=>'single_text','input' => 'datetime','html5'=>false, 'label'=>'Data de Registro'])
->add('competencia', null, ['label'=>'Competência'])
->add('motivo', TextareaType::class, ['required'=>true])
->add('dtCiencia', DateTimeType::class, ['widget'=>'single_text','input' => 'datetime','html5'=>false, 'label'=>'Data de Ciência'])
->add('vistoCiencia', CheckboxType::class, ['label'=>'Ciente', 'required'=>false])
->add('nomeCliente', null, ['label'=>'Nome'])
->add('getRegistro', null, ['label'=>'CNPJ/CPF'])
->add('cpfCliente', null, ['label'=>'CPF'])
->add('cnpjCliente', null, ['label'=>'CNPJ'])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Multa::class,
'usuario' => Usuario::class,
]);
}
}
this is what I have on my controller:
/**
* #Route("/novo", name="multa_novo", methods={"GET","POST"})
*/
public function novo(PushNotification $push,
Request $request): Response
{
$multa = new Multa();
$form = $this->createForm(MultaType::class, $multa);
$form->remove('usuario');
$form->remove('departamento');
$form->remove('dtCiencia');
$form->remove('dtRegistro');
$form->remove('razaoSocial');
$form->remove('getRegistro');
if(in_array($this->getUser()->getAcesso(), [1,2,3,4,7,10]))
{
$desligados = $this->getDoctrine()->getRepository(Usuario::class)->findByAtivo(0);
}
else
{
$desligados = [];
}
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager = $this->getDoctrine()->getManager();
$multa->setUsuario($this->getUser());
$entityManager->persist($multa);
$entityManager->flush();
$this->addFlash('success', "Multa registrada com sucesso!");
- "HERE I HAVE OTHER THINGS I'M DOING AFTER THE SUBMIT..." -
return $this->redirectToRoute('multa_index');
}
return $this->render('multa/novo.html.twig', [
'entity' => $multa,
'form' => $form->createView(),
'coordenador' => $coordenador[0], //passando o primeiro objeto usuario encontrado para o front
'desligados' => $desligados
]);
}
what I'm doing on the front:
{% if desligados %}
<div class="col-lg-4 mb-3" data-intro="Nome do coordenador responsável pela ciência da multa." data-step="5">
<label>Responsável <i class=" ml-1 text-info icon-sm mdi mdi-information-outline" title="Caso o responsável pela multa ja tenha sido desligado." data-placement="top" data-toggle="tooltip"></i></label>
<select id="responsavel" name="multa[responsavel]" class="form-control">
<option></option>
{% for responsavel in desligados %}
<option value="{{responsavel.id}}">{{ responsavel.nomeCompleto }}</option>
{% endfor %}
</select>
</div>
{% else %}
...
$(function () {
$("#multaForm").submit(function(e) {
e.preventDefault();
e.stopPropagation();
var form = $("#multaForm").serializeObject(); //Envia todo o formuário
form['multa[responsavel]'] = $('#responsavel').val();
$.post( {% if __rota[1] == 'novo' %} "{{ path('multa_novo') }}" {% elseif __rota[1] == 'editar' %} "{{ path('multa_editar', {'id': entity.id } ) }}" {% else %} "{{ path('multa_aprovacao', {'id': entity.id } ) }}" {% endif %}, form, function( data ) {
}).fail(function(error) {
console.log(error);
});
$(this).unbind('submit').submit();
});
});
A example of one submit on my db:
As Jakumi recommended I used the EntityType::class to create a custom querybuilder, it returned what i wanted and as I'm using the formType to render all the fields I didn't needed to do anything on the frontend to pass it to my controller.

Symfony 3 Infinite Scrolling Ajax

I'm trying to make an infinite Scrolling in Ajax.
I really don't know what is missing.
Html Index:
<div class="container">
<!-- Menu -->
{% include '::announce/menu.html.twig' %}
{% for announce in announces|slice(0, 4) %}
<!-- Announce Preview -->
{% include '::announce/' ~ game ~ '/preview.html.twig' %}
{% endfor %}
</div>
<div id="content"> loop content </div>
<nav id="pagination">
<p>Page 2</p>
</nav>
{% endblock %}
{% block javascripts %}
<script src="{{ asset('js/jquery-ias.min.js') }}"></script>
{% endblock %}
My controller index:
public function indexAction(Request $request, $game)
{
$em = $this->getDoctrine()->getManager();
$announces $em->getRepository('PlatformBundle:Announce')->byGame($game);
return $this->render('announce/index.html.twig', array(
'announces' => $announces,
'game' => $game
));
}
With this i have my index page with 4 announce
Now i show you my code for scrolling and adding more announce
Ajax File:
$(window).scroll(function () {
if($(window).scrollTop() + $(window).height()>= $(document).height()){
getmoredata();
}
})
function getmoredata() {
$.ajax({
type: "GET",
url: "{{ path('announce_page', {'id': '2', 'game': game}) }}",
dataType: "json",
cache: false,
success: function (response) {
$("#content").append(response.classifiedList);
$('#spinner').hide();
console.log(response);
},
error: function (response) {
console.log(response);
}
});
}
And this is the controller for page:
public function pageAction(Request $request, $game)
{
$em = $this->getDoctrine()->getManager();
$announces = $em->getRepository('PlatformBundle:Announce')->byGame($game);
$list = $this->renderView('announce/result.html.twig', array(
'announces' => $announces,
'game' => $game
));
$response = new JsonResponse();
$response->setData(array('classifiedList' => $list));
return $response;
}
Last code, it's the html content for ajax (result.html.twig)
{% for announce in announces|slice(4, 4) %}
<!-- Affichage Annonce -->
{% include '::announce/' ~ game ~ '/preview.html.twig' %}
{% endfor %}
For resume, i have my index with 4 announce, when i scroll in bottom, i have a positive ajax request without error. But nothing appear after the 4 announce.
If i go to announce page 2 directly with pagination, i can see 4 other announce. So my routing is working but something don't works in ajax code i think.
Any idea? :)
Thanks

Cannot pass variable to JS script for PayPal Payments Rest API

The problem is that I cannot pass the paymentID variable that the PayPal script needs from PHP to JS. (Either this or the PHP script never runs).
I am following the steps here: https://developer.paypal.com/docs/integration/direct/express-checkout/integration-jsv4/advanced-integration/#set-up-the-payment
and I'm stuck on step 4.
I've used the code from this tutorial: http://paypal.github.io/PayPal-PHP-SDK/sample/doc/payments/CreatePaymentUsingPayPal.html
Here is the HTML:
{% extends 'layout/master.twig' %}
{% block title %} {{ parent() }}PayPal {% endblock title %}
{% block head %}
<script src="https://www.paypalobjects.com/api/checkout.js"></script>
{% endblock %}
{% block header %} Testing PayPal {% endblock header %}
{% block content %}
<div id="paypal-button"></div>
{% endblock content %}
{% block scripts %}
<script>
paypal.Button.render({
env: 'sandbox', // Optional: specify 'production' environment
payment: function(resolve, reject) {
var CREATE_PAYMENT_URL = 'http://patch-request.app/paypal/payment/create';
paypal.request.get(CREATE_PAYMENT_URL)
.then(function(data) {
alert(data);
console.log(data);
resolve(data.paymentID);
})
.catch(function(err) {
alert(data);
console.log(data);
reject(err);
});
},
onAuthorize: function(data) {
// Note: you can display a confirmation page before executing
var EXECUTE_PAYMENT_URL = 'http://patch-request.com/paypal/execute-payment';
paypal.request.post(EXECUTE_PAYMENT_URL,
{ paymentID: data.paymentID, payerID: data.payerID })
.then(function(data) { /* Go to a success page */ })
.catch(function(err) { /* Go to an error page */ });
}
}, '#paypal-button');
</script>
{% endblock scripts %}
And here is the script I'm trying to run:
public function create_payment ()
{
$payer = new Payer();
$payer->setPaymentMethod("paypal");
$item1 = new Item();
$item1->setName('Ground Coffee 40 oz')
->setCurrency('USD')
->setQuantity(1)
->setSku("123123")// Similar to `item_number` in Classic API
->setPrice(7.5);
$item2 = new Item();
$item2->setName('Granola bars')
->setCurrency('USD')
->setQuantity(5)
->setSku("321321")// Similar to `item_number` in Classic API
->setPrice(2);
$itemList = new ItemList();
$itemList->setItems([$item1, $item2]);
$details = new Details();
$details->setShipping(1.2)
->setTax(1.3)
->setSubtotal(17.50);
$amount = new Amount();
$amount->setCurrency("USD")
->setTotal(20)
->setDetails($details);
$transaction = new Transaction();
$transaction->setAmount($amount)
->setItemList($itemList)
->setDescription("Payment description")
->setInvoiceNumber(uniqid());
// $baseUrl = getBaseUrl();
$baseUrl = "http://patch-request.app";
$redirectUrls = new RedirectUrls();
$redirectUrls->setReturnUrl("$baseUrl/ExecutePayment.php?success=true")
->setCancelUrl("$baseUrl/ExecutePayment.php?success=false");
$payment = new Payment();
$payment->setIntent("sale")
->setPayer($payer)
->setRedirectUrls($redirectUrls)
->setTransactions([$transaction]);
$request = clone $payment;
try
{
$payment->create($this->apiContext); //$payment is a JSON
}
catch (Exception $ex)
{
echo 'Sth went wrong';
}
$approvalUrl = $payment->getApprovalLink();
return json_encode(['paymentID' => $payment->id]);
}
Any ideas?
I've got no idea what templating system you're using but you could try this
{% block head %}
<script src="https://www.paypalobjects.com/api/checkout.js"></script>
// add it here
<script>
window.paymentID = '<?= getPaymentID(); ?>'; // you need to implement this
</script>
{% endblock %}
Now you can access window.paymentID anywhere in you other JS

Categories

Resources