jQuery function in TWIG layout doesn't work properly - php

I am trying to create simple "admin" page for my blog. For now I want to create some "dynamic" behaviour which will lock/unlock user. Then I want to replace single table row with another, taken from json. I wrote a simple function but unfortunatelly it is not working properly...
When I use constant value for user id (just for tests) it works, but only for ONE row. Other buttons do nothig. Then I tried to send id to my function as a parameter but now it says it doesn't exist in my TWIG (what is true).
I want to make it work, because reloading all page when you only locked one user or did another single action, is not a good idea.
How can I make my function work in a good way?
SCRIPT
$(document).ready(function(){
$(".LockUserButton").click(function(id){
$(this).closest("tr").toggleClass('locked progress-bar-striped');
$.ajax({
type: 'POST',
url: "{{ path('lock_ajax', {'id': id }) }}",
data: { user_id: "{{ user.id }}" },
dataType: 'json',
success: function () {
$(this).closest("tr").toggleClass('locked progress-bar-striped');
}
});
});
});
TWIG
<div class="table-content">
{% for u in users %}
{% if u.locked %}
<tr id="tableRow" class="locked progress-bar-striped">
{% else %}
<tr id="tableRow" class="">
{% endif %}
{% if u.roles[0] == 'ROLE_SUPER_ADMIN' %}
<td id="roles">
<h4><span class="glyphicon glyphicon-star admin-star" data-toggle="tooltip" data-placement="right" title="{{ u.roles[0] }}"></span></h4>
</td>
<td>{{ u.username }}</td>
<td>{{ u.email }}</td>
<td>
<span class="glyphicon glyphicon-lock admin-lock" data-toggle="tooltip" data-placement="right" title="Cannot modyfi this user!"></span>
</td>
<td>
<span class="glyphicon glyphicon-lock admin-lock" data-toggle="tooltip" data-placement="right" title="Cannot modyfi this user!"></span>
</td>
{% else %}
<td id="roles">
<h4><span class="glyphicon glyphicon-star-empty user-star" data-toggle="tooltip" data-placement="right" title="{{ u.roles[0] }}"></span></h4>
</td>
<td>{{ u.username }}</td>
<td>{{ u.email }}</td>
<td>
<div class="btn btn-custom LockUserButton">LOCK USER WITHOUT RELOADING</div>
</td>
<td>
<a href="/profile/admin/delete_user/{{ u.id }}" onclick="return confirm('{{ 'user.deleting'|trans }}')">
<div class="btn btn-custom hvr-grow">
<span class="glyphicon glyphicon-trash"></span>
</div>
</a>
</td>
{% endif %}
</tr>
{% endfor %}
</div>
CONTROLLER ACTION
/**
* #Route("/profile/ajax/{id}", name="lock_ajax")
*/
public function ajaxLock($id, Request $request)
{
$entityManager = $this->getDoctrine()->getManager();
$user = $entityManager->getRepository('AppBundle:User')->find($id);
if($user->isLocked()){
$user->setLocked(false);
}else{
$user->setLocked(true);
}
$entityManager->persist($user);
$entityManager->flush();
$result = array();
$result[0] = $user;
return new JsonResponse($result);
}

Thanks to Artamiel I have finally figure it out! Here's the solition for my case:
1) I have added data-id="{{ u.id }}" attribute to my button. Now i have access to my entity ID.
2) I have modify a little my script:
$(document).ready(function(){
$(".LockUserButton").click(function(){
//get user id from twig layout
var user = $(this).data("id");
//ajax request
$.ajax({
type: 'POST',
url: "/profile/ajax/"+user,
data: { user_id: "user" },
dataType: 'json',
context: this,
success: function () {
//i've wrote some function to toggle html
$(this).toggleText('{{ 'user.unlocked'|trans }}', '{{ 'user.locked'|trans }}');
//find table row and toggle classes when button clicked and request ok
$(this).closest("tr").toggleClass('locked progress-bar-striped');
},
error: function(){
alert("Error!");
}
});
});
});

Related

symfony jquery he changes me the last element

Hi everyone I come to you because I have a small problem, I create a dynamic comments system in ajax and I would like to edit each comment except that when I do it it changes me the last and not the element clicked
I've missed that things that I think
I have not tried anything yet I do not see how to do it
My code :
js:
$('#edit-comments').hide();
$('#add-comments').on('click', function (e) {
e.preventDefault();
$.ajax({
url: $(this).attr('action'),
type: 'POST',
data: $('#formsComments').serialize(),
dataType: 'json',
success: function (data) {
$('#comments_commentsContent').val('');
$('#content-comments').append(data.content);
},
error: function (data) {
console.log(data);
if(data.status === 500) {
$('#errors-comments').html('<div class="error">Vous n\'avez pas ajouté de commentaires\n</div>')
}
}
});
});
$('.comments-content').on('click', function (e) {
e.preventDefault();
$('#add-comments').hide();
$('#edit-comments').show();
var idEdit = $(this).attr('id');
var idContent = idEdit.split('-');
var res = $('p#comments-content-'+idContent[2]).text();
console.log(idContent);
$('#comments_commentsContent').val(res);
$('#edit-comments').on('click', function (e) {
e.preventDefault();
$.ajax({
url: '/article/commentaires/'+idContent[2]+'/edit/'+idContent[3],
type: 'POST',
data: $('#formsComments').serialize(),
dataType: 'json',
success: function (data) {
console.log(data);
$('#comments_commentsContent').val('');
$('#add-comments').show();
$('#edit-comments').hide();
$('#comments-content-'+idContent[2]).html(data.content.message);
},
error: function (data) {
console.log(data);
}
});
});
});
My view twig :
{% for comment in article.comments %}
<div class="media" id="media">
<div class="media-body">
<div class="media-heading">
<h4>{{ comment.userComments.username }}</h4>
<span class="time">{{ comment.createdAt | date("d/m/Y à H:i") }}</span>
{% if app.user %}
{% if comment.userComments.id == app.user.id %}
<a href="{{ path('front_article_edit_comments', {'id': comment.id, 'user': comment.userComments.id}) }}#comments" class="comments-content" id="edit-comments-{{ comment.id }}-{{ comment.userComments.id }}" >
<i class="fa fa-pencil" aria-hidden="true"></i>
</a>
{% endif %}
{% endif %}
{% if is_granted('ROLE_ADMIN') %}
<a href="{{ path('front_article_delete_comments', {'id': comment.id}) }}#comments" onclick="return confirm('Vous voulez vous vraiment supprimer ce commenaitre ?');">
<i style="padding-left: 10px; color: #CBBBA3;" class="fa fa-times" aria-hidden="true"></i>
</a>
{% endif %}
</div>
<p id="comments-content-{{ comment.id }}">{{ comment.commentsContent|nl2br }}</p>
</div>
</div>
{% endfor %}
new comments :
if($request->isXmlHttpRequest() && $form->isValid()) {
$user = $this->getUser();
$comments->setUserComments($user);
$comments->setArticleComments($articles);
$em->persist($comments);
$em->flush();
$html = $this->renderView('articles/comments.html.twig', ['comment' => $comments]);
return $this->json(['content' => $html]);
}
edit comments :
if($request->isXmlHttpRequest() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->flush();
return $this->json(['content' => [
'message' => $comments->getCommentsContent(),
'user' => $comments->getUserComments()->getId(),
'id-comments' => $comments->getId(),
]]);
}
When I want to edit the first comment or the second it does not work.

Symfony - Ajax Select

I am working on a Symfony project where I have a product entity and I need an Ajax search bar to search for through my products and select some of them. The problem is I have a search bar which gives me live results from the database but if I select the product it should show the data in my table. For some reason I am not able to show the selected results in my table.
js
$('.js-data-example-ajax').select2({
ajax: {
url: '/product/api/search',
dataType: 'json',
}
});
Controller
public function viewActionSearch(Request $request)
{
$query = $request->get('term');
$result = [
'results' => [],
];
if ($query !== null){
$products = $this->productRepository->getSearchList($query);
$result['results'];
foreach ($products as $product) {
$result['results'][] = [
'id' => $product['id'],
'text' => $product['name'],
];
}
} else {
$products = $this->productRepository->getResultList(1);
foreach ($products as $entity) {
$result['results'][] = [
'id' => $entity['id'],
'text' => $entity['name'],
];
}
}
return new JsonResponse($result);
}
ProductList
public function getPage(Request $request)
{
$products = $this->productRepository->getAllProducts($currentPage);
return $this->render(
'#app_bar/Product/productList.twig',
[
'products' => $products,
]
);
}
Twig
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<!-- select2 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/js/select2.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/css/select2.min.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/gh/ttskch/select2-bootstrap4-theme#master/dist/select2-bootstrap4.min.css" rel="stylesheet">
<div class="container mt-5">
<form>
<div class="form-group">
<select class="js-data-example-ajax form-control"></select>
</select>
</div>
</form>
</div>
<table class="table table-hover table-responsive">
<thead>
<tr>
<th>id</th>
<th>Title</th>
<th>SKU</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for product in products %}
<tr>
<td>
{{ product.id }}
</td>
<td>
{{ product.name }}
</td>
<td>
{{ product.sku }}
</td>
<td>
<a href="{{ path('app_product_getproduct', {'id': product.id}) }}" class="btn btn-success btn-sm" >
<span class="glyphicon glyphicon-pencil"></span>
</a>
<a href="{{ path('app_product_delete', {'id': product.id}) }}" class="btn btn-danger btn-sm" onclick="return confirm('Are you sure?')">
<span class="glyphicon glyphicon-trash"></span>
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
If I visit the route /product/api/search/ it's giving my a result back but i am not able to show these selected products in my table.
You missing something here. Symfony does not work like frontend frameworks like vue.js or similar. What you are doing you are rendering serverside request and after that, you just fetch data via AJAX and you do nothing with that data. jQuery needs instructions on what to do with data you get from the server. You can always use Symfony alongside some frontend framework, but you need to understand the difference when serverside renders your twig template and when frontend framework renders it.
http://api.jquery.com/jquery.ajax/
Hint:
$('.js-data-example-ajax').select2({
ajax: {
url: '/product/api/search',
dataType: 'json',
success: function (data) {
$.each(response, function () {
$('#mytable').append('<tr><td>' + this.product_name + '</td><td>' + this.product_price + '</td></tr>');
});
}
}
});
There are different methods of what you can render, you can reload whole table or just rows that you need.

Symfony 2 - Update database on click

I try to update the 'archive' value of the database when I click on a check box. After searching the site and google, I managed to do it.
However, by adding a second article, it only works for the first one. If you ever have ideas, I will be grateful!
Thank you
I have fosjsroutingbundle installed.
Here is my controller :
public function archiveAction($id, Request $request)
{
if ($request->isXmlHttpRequest()) {
$em = $this->getDoctrine()->getManager();
$glasse = $em->getRepository('SosMontagesBundle:Glasse')->find($id);
$glasseArchiveStat = $glasse->getArchive();
if ($glasseArchiveStat == false) {
$glasse->setArchive(true);
$em->flush();
} else {
$glasse->setArchive(false);
$em->flush();
}
return new Response('d');
}
}
My route :
sos_montage_archive:
path: /admin/archive/{id}
defaults: { _controller: SosMontagesBundle:Admin:archive }
requirements:
id: \d+
options:
expose: true
My view :
{% extends '#SosMontages/layout.html.twig' %}
{% block content %}
<div class="col-md-6 col-md-offset-3">
<h2>Liste des lunettes</h2>
<table class="table table-striped">
<thead>
<tr>
<th>Id</th>
<th>Marque - Model</th>
<th>Description</th>
<th>Archive</th>
<th>Ordre</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for article in pagination %}
<tr {% if loop.index is odd %}class="color"{% endif %}>
<td>{{ article.id }}</td>
<td>{{ article.name ~ ' - ' ~ article.brand }}</td>
<td>{{ article.content }}</td>
{% if article.archive == false %}
<td><input type="checkbox" name="{{ article.id }}" id="archive"></td>
{% else %}
<td><input type="checkbox" name="{{ article.id }}" id="archive" checked></td>
{% endif %}
<td></td>
<td><i class="fa fa-pencil fa-2x" aria-hidden="true"></i>
<i class="fa fa-trash-o fa-2x" aria-hidden="true"></i></td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="navigation">
{{ knp_pagination_render(pagination) }}
</div>
</div>
{% endblock %}
{% block javascript %}
<script src="{{ asset('bundles/fosjsrouting/js/router.js') }}"></script>
<script src="{{ path('fos_js_routing_js', { callback: 'fos.Router.setData' }) }}"></script>
<script>
$(document).ready(function () {
$("#archive").click(function () {
var id = $("#archive").attr('name');
var DATA = 'sentValue=' + id;
$.ajax({
type: "POST",
url: Routing.generate('sos_montage_archive', { id: id }),
data: DATA,
cache: false,
success: function (data) {
alert("database has been updated");
}
});
});
});
</script>
{% endblock %}
Your click listenner on your checkbox may not be correct. You should use a change listener while it's a checkbox. Change your click function in js to change:
$('#archive').change(function() {
if($(this).is(":checked")) {
//'checked' event code
return;
}
//'unchecked' event code
});
However you also have two checkboxes and only one id. This might create weird bugs. Changing your ids to #archive1 and #archive2 may fix your code.
You have to fix your HTML and differentiate your #archive id selector.
You can do that by using loop.index for example:
id="archive{{ loop.index }}" //output : archive1, archive2...
Twig doc :
http://twig.sensiolabs.org/doc/2.x/tags/for.html#the-loop-variable

How to Use the Jquery Number Spinner to Update Quantity in DB?

I’m new to JQuery/JavaScript/Ajax as well as Symfony2 & PHP.
I’m building a simple Shopping Cart and I want to the users to be able to control the quantity of a product they added in their cart using the JQuery Spinner (https://jqueryui.com/spinner/).
Being new, I could really use some help with how to do this.
All of my attempts have failed and I’m just struggling.
HTML/Twig:
<tbody>
{% for key, product in quantity %}
<tr>
{{ dump(key) }}
<td>{{ product.product }}</td> <!--Product-->
<td>
<input class="spinner" value="{{ product.quantity }}" style="width:30px">
</td> <!--Quantity-->
<td>${{ product.product.price|default('') }}</td> <!--Price-->
<td>
<a href="{{ path('product_remove', {'id': key }) }}">
<button name="REMOVE" type="button" class="btn btn-danger" id="removeButton">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</button>
</a>
</td><!--Remove-->
</tr>
{% endfor %}
</tbody>
</table> <!--top table-->
<script type="text/javascript">
$(".spinner").spinner();
</script>
Product Controller (Where I set Quantity…):
$quantity = new Quantity();
if (is_null($cart) || $cart->getSubmitted(true)) {
$cart = new UserCart();
}
$cart->setTimestamp(new \DateTime()); // Set Time Product was Added
$quantity->setQuantity(1); // Set Quantity Purchased
$cart->setSubmitted(false); // Set Submitted
$cart->setUser($this->getUser()); // Sets the User ONCE
$cart->addQuantity($quantity); // Add Quantity ONCE
$quantity->setUserCart($cart); // Create a UserCart ONCE
$quantity->setProduct($product); // Sets the Product to Quantity Association ONCE
$em->persist($product);
$em->persist($cart);
$em->persist($quantity);
$em->flush();
$this->addFlash('notice', 'The product: '.$product->getName().' has been added to the cart!');
Use jQuery to handle the change event on the spinner. When it's updated, fire off a request to the database to update it.
Replace the url below with your URL.
$('input.spinner').on('change', function(){
var $this = $(this);
$.ajax({
url: '/path/to/update/my/product/quantity',
method: 'POST',
data : {
quantity: $this.val()
}
}).done(function(resp){
console.log('success', resp);
}).error(function(err){
console.log('error', resp);
});
});
Handle the product quantity coming over in $_POST['quantity'] manually and update the cart accordingly.
The logic to handle this inside of your Symphony controller is out of the scope because it's too broad and there's not enough information to give definitive directions.

How to implement Ajax in Symfony2

I have a basic but functional search mechanism in my Symfony2 project.This will query and display back to the user the data using Doctrine2 LIKE expression.But I want to make more 'dynamic' and more 'user-friendly' by adding Ajax functionality.I added some Ajax code in my controller, but I don't know how to make it work.The image loader is just 'spinning' without displaying the results.
//controller
public function searcAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$query = $this->getRequest()->get('query');
if(!$query) {
if(!$request->isXmlHttpRequest()) {
return $this->redirect($this->generateUrl('voters_list'));
} else {
return new Response('No results.');
}
}
$city = $em->getRepository('DuterteBundle:City')->findCity($query);
if($request->isXmlHttpRequest()) {
if('*' == $query || !$city || $query == '') {
return new Response('No results.');
}
//display a another page
return $this->render('DuterteBundle:City:list1.html.twig', array('city' => $city));
}
return $this->render('DuterteBundle:City:search.html.twig', array('city' => $city));
}
// routing
search:
path: /search
defaults: { _controller:DuterteBundle:City:Searc }
requirements:
//search.html.twig
{% extends '::base.html.twig' %}
{% block body %}
<div id="city">
{% include 'DuterteBundle:City:list1.html.twig' with {'city': city} %}
</div>
{% endblock %}
//list1.html.twig
{% block body %}
<div class="page-header">
<h4>City/Municipality/Town and Its Corresponding Numbers of Voters</h4>
</div>
<table class="table table-hover table-bordered table-condensed">
<thead>
<tr>
<th>City</th>
<th>Votes</th>
<th>Percent</th>
</tr>
</thead>
<tbody>
{% for city in city %}
<tr>
<td>{{ city }}</td>
<td>{{ number_votes_city(city.id) }}</td>
<td></td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
My search form is embedded in navbar in the main layout.
<div class="col-sm-3 col-md-3" id="search">
<form class="navbar-form" role="search" action ="{{ path('search')}}" method ="post">
<div class="input-group">
<input type="text" class="form-control" placeholder="Search city/town" name="query" value="{{ app.request.get('query') }}" id="search_keywords">
<div class="input-group-btn">
<button class="btn btn-default" type="submit"><i class="fa fa-search"></i></button>
<img id="loader" src="{{ asset('bundles/duterte/images/loader.gif') }}" style="vertical-align: middle; display: none" />
</div>
</div>
</form>
//repository
public function findCity($city)
{
return $this
->createQueryBuilder('c')
->select('c')
->where('c.name LIKE :name_city')
->setParameter('name_city', '%'.$city.'%')
->orderBy('c.name', 'ASC')
->getQuery()
->getResult()
;
}
and finally the js file
$(document).ready(function()
{
$('.search input[type="submit"]').hide();
$('#search_keywords').keyup(function(key)
{
if(this.value.length >= 3 || this.value == '') {
$('#loader').show();
$('#city').load(
$(this).parent('form').attr('action'),
{ query: this.value ? this.value + '*' : this.value },
function() {
$('#loader').hide();
}
);
}
});
});
Any help is appreciated
The same functionality, but a different approach. Listen to the keyup event on the search box
and then make ajax calls to a controller that returns the list of matched results as json. Check the response and
based on the status of the response, hide the existing listing and replace its contents with the markup returned in the
json response for the AJAX call.
Here, the example is for search in user listing.
Table markup on the twig file
<div id="user-list-div">
<table class="records_list" id="user-list">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Username</th>
<th>Password</th>
<th>Salt</th>
<th>Email</th>
<th>Isactive</th>
<th>Createdat</th>
<th>Updatedat</th>
<th>Isbillableuser</th>
<th>Isdeleted</th>
<th>Actions</th>
</tr>
</thead>
<tbody id = "user-table">
{% for entity in entities %}
<tr>
<td>{{ entity.id }}</td>
<td>{{ entity.name }}</td>
<td>{{ entity.username }}</td>
<td>{{ entity.password }}</td>
<td>{{ entity.salt }}</td>
<td>{{ entity.email }}</td>
<td>{{ entity.isActive }}</td>
<td>{% if entity.createdAt %}{{ entity.createdAt|date('Y-m-d H:i:s') }}{% endif %}</td>
<td>{% if entity.updatedAt %}{{ entity.updatedAt|date('Y-m-d H:i:s') }}{% endif %}</td>
<td>{{ entity.isBillableUser }}</td>
<td>{{ entity.isDeleted }}</td>
<td>
<ul>
<li>
show
</li>
<li>
edit
</li>
</ul>
</td>
</tr>
{% endfor %}
</tbody>
Search form markup
<div class="col-lg-6">
<div class="input-group">
<input type="text" class="form-control" id="search-field">
<span class="input-group-btn">
<button class="btn btn-default" type="button">Go!</button>
</span>
</div>
</div>
javascript part
<script>
$(function(){
console.log('desperate for');
var searchField = $('#search-field');
var userTable = $('#user-table');
var userListDiv = $('#user-list-div');
searchField.keyup(function(evt){
console.log($(this).val());
$.ajax({
url: '{{ path('admin_user_search') }}',
method: "POST",
data: "id=" + $(this).val() ,
dataType: 'html',
success: function(result, request) {
var parsedData =JSON.parse(result);
console.log(parsedData);
if(parsedData.status ==='success'){
console.log('hete');
userListDiv.empty();
userListDiv.html(parsedData.data);
}else{
//handle no result case
}
}
});
});
});
</script>
ajax_template.html.twig file
The same table markup as given above
controller action
public function searchuserAction(){
$em = $this->getDoctrine()->getManager();
$request = $this->get('request');
$searchParameter = $request->request->get('id');
//call repository function
$entities = $em->getRepository('LBCoreBundle:User')->findUsersForname($searchParameter);
$status = 'error';
$html = '';
if($entities){
$data = $this->render('LBCoreBundle:User:ajax_template.html.twig', array(
'entities' => $entities,
));
$status = 'success';
$html = $data->getContent();
}
$jsonArray = array(
'status' => $status,
'data' => $html,
);
$response = new Response(json_encode($jsonArray));
$response->headers->set('Content-Type', 'application/json; charset=utf-8');
return $response;
}
Respository function
public function findUsersForname($name){
$em = $this->getEntityManager();
$query = $em->createQuery("SELECT e FROM LBCoreBundle:User e
WHERE e.username LIKE '%$name%'");
$entities = $query->getResult();
return $entities;
}

Categories