how can i append an anchor to the url using knp_paginator - symfony

I am using symfony 4.4 to develop an e-commerce website. I have a section with an id="projects" at the centre of the page so you have to scroll down to reach it. This section is built with knp paginator inside my ProductRepository to make it work with the search form, and some parts of the section are links to another page that also has a products section that you have to scroll to. I want to attach #projects to the URLs to scroll the user down to the section, but I don't know how to do this the way that knp paginator builds the page.
I have tried to append a #projects to the path inside twitter_bootstrap_v4_pagination.html.twig (the template that I have defined in the knp_paginator.yaml), but when I do this the paginator doesn't work anymore and #projects is not appended to the url.
{% if pageCount > 1 %}
<nav>
{% set classAlign = (align is not defined) ? '' : align=='center' ? ' justify-content-center' : (align=='right' ? ' justify-content-end' : '') %}
{% set classSize = (size is not defined) ? '' : size=='large' ? ' pagination-lg' : (size=='small' ? ' pagination-sm' : '') %}
<ul class="pagination{{ classAlign }}{{ classSize }}">
{% if previous is defined %}
<li class="page-item">
<a class="page-link" rel="prev" href="{{ path(route, query|merge({(pageParameterName): previous})) }}#projects">« {{ 'label_previous'|trans({}, 'KnpPaginatorBundle') }}</a>
</li>
{% else %}
<li class="page-item disabled">
<span class="page-link">« {{ 'label_previous'|trans({}, 'KnpPaginatorBundle') }}</span>
</li>
{% endif %}
{% if startPage > 1 %}
<li class="page-item">
<a class="page-link" href="{{ path(route, query|merge({(pageParameterName): 1})) }}#projects">1</a>
</li>
{% if startPage == 3 %}
<li class="page-item">
<a class="page-link" href="{{ path(route, query|merge({(pageParameterName): 2})) }}#projects">2</a>
</li>
{% elseif startPage != 2 %}
<li class="page-item disabled">
<span class="page-link">…</span>
</li>
{% endif %}
{% endif %}
{% for page in pagesInRange %}
{% if page != current %}
<li class="page-item">
<a class="page-link" href="{{ path(route, query|merge({(pageParameterName): page})) }}#projects">{{ page }}</a>
</li>
{% else %}
<li class="page-item active">
<span class="page-link">{{ page }}</span>
</li>
{% endif %}
{% endfor %}
{% if pageCount > endPage %}
{% if pageCount > (endPage + 1) %}
{% if pageCount > (endPage + 2) %}
<li class="page-item disabled">
<span class="page-link">…</span>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="{{ path(route, query|merge({(pageParameterName): (pageCount - 1)})) }}#projects">{{ pageCount -1 }}</a>
</li>
{% endif %}
{% endif %}
<li class="page-item">
</li>
{% endif %}
{% if next is defined %}
<li class="page-item">
<a class="page-link" rel="next" href="{{ path(route, query|merge({(pageParameterName): next})) }}#projects">{{ 'label_next'|trans({}, 'KnpPaginatorBundle') }} »</a>
</li>
{% else %}
<li class="page-item disabled">
<span class="page-link">{{ 'label_next'|trans({}, 'KnpPaginatorBundle') }} »</span>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
If I change #projects to another id that doesn't exist inside my index.html.twig, for example #randomId, the paginator works fine and the url is changed "http://127.0.0.1:8000/home?page=2#randomId", but it doesn't solve my problem.
Note: I have also tried to change manually the url to http://127.0.0.1:8000/home?page=2#projects and it worked. I don't know why it wouldn't accept and existing id inside the index.html.twig.
If needed here is the controller :
<?php
namespace App\Controller;
use App\Data\SearchData;
use App\Entity\Contact;
use App\Entity\ContactDevis;
use App\Entity\Evv;
use App\Form\ContactType;
use App\Form\ContactDevisType;
use App\Form\SearchForm;
use App\Repository\ProduitRepository;
use App\Repository\EvvRepository;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
/**
* #Route("/")
*/
class EnoveController extends AbstractController
{
/**
* #Route("/home", name="enove_index", methods={"GET","POST"})
*/
public function index(ProduitRepository $produitRepository, EvvRepository $evvRepository, Request $request , Request $request_contact, Request $request_devis, \Swift_Mailer $mailer)
{
$contact = new Contact();
$contactdevis = new ContactDevis();
$data = new SearchData();
$evv = new Evv();
$data->page = $request->get('page',1);
$form_filter = $this->createForm(SearchForm::class, $data);
$form_filter->handleRequest($request);
//dd($data);
$evv = $evvRepository->findAll();
$produit = $produitRepository->findSearch($data);
$form_contact = $this->createForm(ContactType::class, $contact);
$form_contact->handleRequest($request_contact);
if($form_contact->isSubmitted() && $form_contact->isValid())
{
$contact = $form_contact->getData();
$this->addFlash('success', 'votre email à été acheminer à Enove');
$message = (new \Swift_Message('Nouveau contact'))
// On attribue l'expéditeur
->setFrom($contact->getEmail())
// On attribue le destinataire
->setTo('zwayten111#gmail.com')
// On crée le texte avec la vue
->setBody(
$this->renderView(
'emails/contact.html.twig', compact('contact')
),
'text/html'
)
;
$mailer->send($message);
return $this->redirectToRoute('enove_index' ,
[
'produits' => $produit,
'form_filter' => $form_filter->createView(),
'evvs' =>$evv,
] );
}
$form_devis = $this->createForm(ContactDevisType::class, $contactdevis);
$form_devis->handleRequest($request_devis);
if($form_devis->isSubmitted() && $form_devis->isValid())
{
$contactdevis = $form_devis->getData();
$this->addFlash('success', 'votre email à été acheminer à Enove');
$message2 = (new \Swift_Message('Devis'))
// On attribue l'expéditeur
->setFrom($contactdevis->getEmail())
// On attribue le destinataire
->setTo('zwayten111#gmail.com')
// On crée le texte avec la vue
->setBody(
$this->renderView(
'emails/contact_devis.html.twig', compact('contactdevis')
),
'text/html'
)
;
$mailer->send($message2);
//dd($contactdevis);
return $this->redirectToRoute('enove_index' ,
[
'produits' => $produit,
'form_filter' => $form_filter->createView(),
'evvs' =>$evv,
] );
}
//dump($request->request);
return $this->render(
'FrontEndEnove/index.html.twig',
[
'produits' => $produit,
'form_filter' => $form_filter->createView(),
'form_contact' => $form_contact->createView(),
'form_devis' => $form_devis->createView(),
'evvs' => $evv,
]
);
}
}

Well in my case I changed the ProductRpository with adding this
$query = $query->getQuery();
$pagination = $this->paginator->paginate($query,$search->page,6);
$pagination->setParam('_fragment', 'projects');
return $pagination;
and the problem was still here, guess what I had a problem in template, the jQuery was forcing it to go back to the top I just had to delete it.

Related

Find on which item route from the menu I am

I'm currently working on a Symfony 4.4 web application.
The menu can be changed by the administrators of my app, so there is a table with these properties :
Because I got routes with some parameters (eg: a slug or an id, and the slug can change so it's not a great identifier).
The problem is that I want to know on which menu item I am, to keep the menu opened (to add an active class on < li > items) but I can't find a way to do it properly.
What I tried :
Identify the route with something like that :
<li>{% if app.request.get('_route') == 'foo_products_overview' and app.request.get('slug') in ["entityslug"] %} class="active" {% endif %}></li>
But parameters are not the same for each route of my app (mutliple entites using id or slug to find one).
Here is the way my menu items are displayed :
{% if child2.getMenuItems()|length > 0 %}
<ul class="collapse nav-sub" aria-expanded="false">
{% for child3 in child2.getMenuItems() if child2.getMenuItems()|length > 0 and child3.level == 4 and (is_granted(child3.roles) or child3.roles is empty) %}
<li class="{% if child3.getMenuItems()|length > 0 %}nav-dropdown{% endif %}">
<a class="{% if child3.getMenuItems()|length > 0 %}has-arrow{% endif %}"
href="{% if child3.route is not null %}{% if child3.routeParameters %}{{ path(child3.route, {'id': child3.routeParameters}) }}{% else %}{{ path(child3.route) }}{% endif %}{% else %}#{% endif %}"
aria-expanded="false">
<span>{% if "ROLE_ADMIN" in child3.roles %}<i class="la la-eye-slash text-danger mr-2"></i>{% endif %}{{ child3.name|raw }}</span>
</a>
</li>
{% endfor %}
</ul>
{% endif %}
Have you ever had this problem?
Maybe there's a way with KnpMenu? (https://symfony.com/bundles/KnpMenuBundle/current/index.html) I'm not using it for the moment.
Did you try this : replace "child.id" by your variable name, i think that's "child3.id" but not sure.
class="{% if app.request.attributes.get( '_route' ) starts with 'foo_products_overview' and app.request.attributes.get('id') == child.id %}active{% endif%}"

How to get current page in pages Symfony 5 without duplicate code?

I want get the current page and give an active class without duplicate code in symfony 5.
Here is the code example :
<li class="{{ app.request.get('_route_')=='home' ? 'active':''}}">
Home
</li>
<li class="{{ app.request.get('_route_')=='contact' ? 'active':''}}">
Contact
</li>
</ul>
As an extension of the answer of #DhiaDjobbi
I've you really want to reduce "duplicate" code, I'd go with defining the menu in an array as well
{% set active_page = app.request.get('_route') %}
{% for page in pages %}
<li {% if page == active_page %} class="active" {% endif %} >
{{ page }}
</li>
{% endfor %}
U can create a twig variable in Template its better readable.
{% set page = app.request.get('_route') %}
Then use If Condition to test.
<li {% if page == 'home' %} class="active" {% endif %} >
Home
</li>
<li {% if page == 'contact' %} class="active" {% endif %} >
Contact
</li>

Drupal 8 remove extra divs and add custom classes in menu

Currently the {{page.primary_menu}} created the extra divs and default d8 classes as below:
<div class="region region-primary-menu">
<nav role="navigation" aria-labelledby="block-demo-main-menu-menu" id="block-demo-main-menu">
<h2 class="sr-only" id="block-demo-main-menu-menu">Main navigation</h2>
<ul class="menu menu--main nav navbar-nav">
<li class="first">
Home
</li>
<li>
Home
</li>
<li class="last">
ABOUT US
</li>
</ul>
</nav>
</div>
However, I want to generate the menu structure as like:
<ul id="top-menu" class="nav navbar-nav navbar-right mu-main-nav">
<li>HOME</li>
<li>ABOUT US</li>
<li>MENU</li>
<li>RESERVATION</li>
<li>GALLERY</li>
<li>OUR TEAM</li>
<li>BLOG</li>
<li>CONTACT</li>
</ul>
I've created a file name demo.theme and pasted the code but it did not give me the expected result.
<?php
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Template\Attribute;
/**
* Implements hook_preprocess_HOOK() for HTML document templates.
*
* Adds body classes if certain regions have content.
*/
function demo_menu_tree(&$variables) {
return '<ul id="top-menu" class="nav navbar-nav navbar-right mu-main-nav">' . $variables['tree'] . '</ul>';
}
Any suggestion?
Make sure you have twig debugging enabled, it will make your life a lot easier, by adding comments to your mark up (which you can see inline in the web inspector). Using those comments you can figure out what you should name your theme file.
Create a new custom twig file in the /templates directory of your theme like so themes/[your-theme-name-here]/templates/menu.html.twig. As a starting point I'd suggest either using the default classy theme menu.html.twig template, or clone use the file referenced inline in the markup comments of your site when you have twig debugging enabled.
Edit the menu.html.twig file to meet your needs, something like this:
{% import _self as menus %}
{#
We call a macro which calls itself to render the full tree.
#see http://twig.sensiolabs.org/doc/tags/macro.html
#}
{{ menus.menu_links(items, attributes, 0) }}
{% macro menu_links(items, attributes, menu_level) %}
{% import _self as menus %}
{% if items %}
{% if menu_level == 0 %}
<ul id="top-menu" {{ attributes.addClass('nav navbar-nav navbar-right mu-main-nav') }}>
{% else %}
<ul class="menu">
{% endif %}
{% for item in items %}
{%
set classes = [
'menu-item',
item.is_expanded ? 'menu-item--expanded',
item.is_collapsed ? 'menu-item--collapsed',
item.in_active_trail ? 'menu-item--active-trail',
]
%}
<li{{ item.attributes.addClass(classes) }}>
{{ link(item.title, item.url) }}
{% if item.below %}
{{ menus.menu_links(item.below, attributes, menu_level + 1) }}
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
{% endmacro %}

Flash message in symfony 3.4

I'm trying to set flash message from ContactAction then redirect on Homepage, but on it, I can't see my flash message, maybe my session is reset ? Can I have some help, I'm a beginer on Symfony.
CoreController that contain both index and contact functions :
<?php
namespace OC\CoreBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class CoreController extends Controller
{
public function indexAction()
{
$ServiceAdverts = $this->container->get('oc_core.listAdverts');
$adList = $ServiceAdverts->getListAdverts();
return $this->render("OCCoreBundle:Core:index.html.twig", array(
'listAdverts' => $adList
));
}
public function contactAction()
{
$this->addFlash('info', 'Contact page not ready yet !');
return $this->redirectToRoute('oc_core_homepage');
}
}
Twig template (homepage) :
{% block body %}
<div>
Messages flash :
{% for msg in app.session.flashBag.get('info') %}
<div class="alert alert-success">
{{ msg }}
</div>
{% endfor %}
</div>
<h2>Liste des annonces</h2>
<ul>
{% for advert in listAdverts %}
<li>
<a href="{{ path('oc_platform_view', {'id': advert.id}) }}">
{{ advert.title }}
</a>
par {{ advert.author }},
le {{ advert.date|date('d/m/Y') }}
</li>
{% else %}
<li>Pas (encore !) d'annonces</li>
{% endfor %}
</ul>
Contact
{% endblock %}
Symfony 3.3 made improvements to flash messages so your Twig template should look different. The app.session.flashBag.get() call is now replaced by app.flashes().
So your Twig code would now be:
{% for msg in app.flashes('success') %}
<div class="alert alert-success">
{{ msg }}
</div>
{% endfor %}
Try this, works for me in 3.2 and 3.4
{% for type, flash_messages in app.session.flashBag.all %}
{% for msg in flash_messages %}
<div class="alert alert-{{ type }}">
{{ msg }}
</div>
{% endfor %}
{% endfor %}
Another thing is that once you called the flashBag it turns empty so you can't use it twice. Check your code that it hasn't been called on another page right before a second redirect ...

Django CMS Multi-Level Dropdown Menu

Im kinda new to Django CMS and im trying my best to avoid asking, but this one drives me crazy.
I made a Wiki app with a Topic, and Category model. I hooked it to a Site on my CMS and added it to my Menu. Now i would like to be able to show all Top-Level categories, their Child Categories & Topics, and the Child categories of these, and so on, on my menu.
Menu/Navigation should look like this:
Wiki
Category1
Category1.1
Topic
Category1.2
Topic
Category2
Topic
Category3
...
Right now i can only show the Top categories:
Wiki
Category1
Category2
Category3
I Already created a menu.py to get a Custom SubMenu on my Wiki (the one you see above):
menu.py
class WikiSubMenu(CMSAttachMenu):
name = _("Wiki Sub-Menu")
def get_nodes(self, request):
nodes = []
categories = Category.objects.filter(parent_id__isnull=True)
for c in categories:
node = NavigationNode(
mark_safe(c.name),
c.get_absolute_url(),
c.id,
)
nodes.append(node)
return nodes
menu_pool.register_menu(WikiSubMenu)
My Category Model:
class Category(models.Model):
''' Category model. '''
name = models.CharField(max_length=100)
slug = models.SlugField(unique=True)
description = models.TextField(blank=True)
parent = models.ForeignKey(
'self',
null=True,
blank=True,
related_name='children'
)
sort = models.IntegerField(default=0)
class Meta:
ordering = ['sort', 'name']
def __unicode__(self):
return self.name
#models.permalink
def get_absolute_url(self):
return ('topics:categories_category_detail', (), {'slug': self.slug})
def get_all_children(self):
return Category.objects.filter(parent=self)
Now, is it possible to create a Sub-SubMenu, for all Categories with Childs, and their Childs, and their Childs, and so on?
Thanks for help & sorry for bad english
-- EDIT : --
I just found that:
docs.django-cms.org/en/3.0.6/extending_cms/app_integration.html#integration-modifiers
(Removed direct link to add 2 new Links, sorry for that)
I think that is what im looking for, i was kinda blind that i didn't found it. I'll try it out and Post the Answer if it worked out.
-- EDIT (AGAIN): --
The modifier didn't worked for me, but i got a whole piece further,
i read the Docs again, and found that i can give the NavigationNodes an optional attr dictonary, which i filled with all Categories with parent=c, on that way i had the data i needed, then i found that real nice bootstrap dropdown menu, that does exacly what i wanted. So my code until now looks like that:
menu.py
class TopicsSubMenu(CMSAttachMenu):
name = _("Wiki Sub-Menu")
def get_nodes(self, request):
nodes = []
categories = Category.objects.filter(parent_id__isnull=True)
for c in categories:
node = NavigationNode(
mark_safe(c.name),
c.get_absolute_url(),
c.pk,
attr=dict(
subcategories=Category.objects.filter(parent=c),),
)
nodes.append(node)
return nodes
And my Template:
menu.html
{% for child in children %}
<li>
{% if child.children %}
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
{{ child.get_menu_title }}
<span class="caret">
</span>
</a>
<ul class="dropdown-menu multi-level" role="menu" aria-labelledby="dropdownMenu">
{% for child in child.children %}
{% if child.attr.subcategories.count %}
<li class="dropdown-submenu">
<a tabindex="-1" href="#">{{ child.get_menu_title }}</a>
<ul class="dropdown-menu">
{% for subcategory in child.attr.subcategories %}
<li>
<a tabindex="-1" href="{{ subcategory.get_absolute_url }}">{{ subcategory }}</a>
</li>
{% endfor %}
</ul>
</li>
{% else %}
<li>{{ child.get_menu_title }}</li>
{% endif %}
{% endfor %}
</ul>
{% else %}
<a href="{{ child.get_absolute_url }}">
<span>
{{ child.get_menu_title }}
</span>
</a>
{% endif %}
</li>
{% if class and forloop.last and not forloop.parentloop %}
{% endif %}
{% endfor %}
My next step will be to write the whole "for" loops from the template in a Method, make it recursive with a while loop or something and post the result as Answer.
I hope i can help someone with that stuff :)
WOHO! I finally did it!
base.html
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
{% show_menu 0 100 100 100 "menu.html" %}
</ul>
</div>
menu.html:
{% for child in children %}
<li class="child{% if child.selected %} selected{% endif %}{% if child.ancestor %} ancestor{% endif %}{% if child.sibling %} sibling{% endif %}{% if child.descendant %} descendant{% endif %}{% if child.children %} dropdown{% endif %}">
<a {% if child.children %}class="dropdown-toggle" data-toggle="dropdown"{% endif %} href="{{ child.attr.redirect_url|default:child.get_absolute_url }}">
<span>{{ child.get_menu_title }}</span>{% if child.children|length %}<span class="caret"></span>{% endif %}
</a>
{% if child.children %}
<ul class="dropdown-menu multi-level" role="menu" aria-labelledby="dropdownMenu">
{% show_menu from_level to_level extra_inactive extra_active "dropdownmenu.html" "" "" child %}
</ul>
{% endif %}
</li>
{% if class and forloop.last and not forloop.parentloop %}{% endif %}
{% endfor %}
and my dropdownmenu.html:
(The recursive stuff starts here)
{% load i18n menu_tags cache mptt_tags %}
{% for child in children %}
<li {% if child.children %}class="dropdown-submenu"{% else %} {% endif %}>
<a tabindex="-1" href="{{ child.attr.redirect_url|default:child.get_absolute_url }}">{{ child.get_menu_title }}</a>
{% if child.children %}
<ul class="dropdown-menu">
{% show_menu from_level to_level extra_inactive extra_active "dropdownmenu.html" "" "" child %}
</ul>
{% endif %}
</li>
{% endfor %}
and the most important, menu.py:
class TopicsSubMenu(CMSAttachMenu):
name = _("Wiki Sub-Menu")
def get_nodes(self, request):
nodes = []
categories = Category.objects.all()
for c in categories:
node = NavigationNode(
mark_safe(c.name),
c.get_absolute_url(),
c.pk
)
if c.parent:
node.parent_id = c.parent_id
nodes.append(node)
topics = Topic.objects.all().exclude(category__isnull=True)
for t in topics:
node = NavigationNode(
mark_safe(t.title),
t.get_absolute_url(),
t.pk,
t.category.all()[0].id,
parent_namespace="TopicsSubMenu"
)
nodes.append(node)
return nodes
menu_pool.register_menu(TopicsSubMenu)
And thats it!

Resources