Creating URL Links
Creation of links belongs to the strongest features of Nette Framework. Thanks to two-way routing you don't have to hardcode your URLs or nastily assemble them. You can just refer to actions of presenters, and pass them parameters and the framework will generate URLs by itself. Creating links is as easy as calling a function. You will really like it!
When programming and coding templates, we don't have to care about URLs design, we will refer directly to action of presenter,
that's for example the already mentioned Product:show
.
Links in templates
Most often we create links in templates. To make it as easy as possible the framework offers three macros. The smartest of them
is n:href
<a n:href="Product:show $productId">product detail</a>
Note, that instead of the HTML attribute href
we've used n:macro n:href
. Its value isn't a URL, as you are used
to with the href
attribute, but directly an action of a presenter. The syntax is
[Presenter:]action [,] [arg1] [, arg2] [, ...]
After clicking on the link, method ProductPresenter::renderShow()
will get its word and as parameter
$id
will get the value of $productId
. We can pass even more parameters in the same way, just like we
call a method. Could it get any easier?
Best practise is to write the presenter with a capital letter and the action without. The separator is a colon.
Besides that, it's even possible to pass named parameters. The next link passes the parameter lang
with value
cs
:
<a n:href="Product:show $productId, lang => cs">product detail</a>
Although the method renderShow
doesn't have $lang
in its declaration, it can read the value of this
parameter by calling $lang = $this->getParameter('lang')
.
If we have all parameters in an array, we can expand them with (expand)
operator:
{var $args = [$productId, lang => cs]}
<a n:href="Product:show (expand) $args">product detail</a>
If the template, in which we are creating links, is part of the Product
presenter, we can omit the name of the
presenter and write directly n:href="show $productId"
. Similarly, if a link leads to the an action named
default
, you can skip that and write n:href="Product: $id"
(don't forget the colon).
Links can even refer to other modules. Here we distinguish, if it's referring “relatively” to a
submodule, or “absolutely” to a different module – then the path begins with a colon. Let's assume that the actual
presenter is part of module Front
, then we will write:
<a n:href="Shop:Product:show">link for Front:Shop:Product:show</a>
<a n:href=":Admin:Product:show">link for Admin:Product:show</a>
A special case is linking to itself. Here we'll write this
as the target.
The generated link is in absolute path format. When you want to generate an absolute link including the domain, for example
http://example.com
, simply supply two slashes at the beginning n:href="//show $productId"
. If we set the
property $absoluteUrls in presenter to
TRUE
, all the links will be absolute by default.
We can refer to specific parts on the page using so called fragments, or anchors, with the hash #
symbol:
<a n:href="show#comments">link to Product:show and fragment #comments</a>
The macro n:href
is really handy if we are creating an HTML tag <a>
. When we want to have this
link elsewhere, for example in the text of the template, we can use the {link}
macro with the same internal
syntax:
The address is: {link Product:show $productId}
{ifCurrent $link}...{/ifCurrent}
is a conditional statement. If the link is referring to the current page, the
block inside the tags is executed; otherwise it is discarded. Typical use case is adding CSS classes to the active link.
<!-- use cases -->
<a href="{link edit, 10}">edit</a>
<ul class="menu">
<li><a href="{link Default:default}">...</a></li>
<li><a href="{link}">...</a></li>
...
<li {ifCurrent Default:default}class="active"{/ifCurrent}><a href="{link Default:default}">...</a></li>
<!-- scope expanding -->
<li {ifCurrent Default:*}class="active"{/ifCurrent}><a href="{link Default:default}">...</a></li>
</ul>
<!-- negation -->
{ifCurrent Admin:login}{else}<a href="{link Admin:login}">Sign in!</a>{/ifCurrent}
Read more details about the syntax of Latte templates.
Linking in presenter
Presenter and a component have the method
link
, which can be used to create links just like in a template. The first argument is presenters target action,
followed by passed arguments:
$url = $this->link(destination [,arg [,arg ...]]);
They can also be passed using an array. Examples:
$url = $this->link('Product:show', $productId);
$url = $this->link('Product:show', array($productId, 'lang' => 'en'));
If you pass FALSE
as method parameter when generating a link, it won't be added to the link at
all. The solution is to define this parameter with default value TRUE
or FALSE
. Nette will then
understand that its type is boolean, and it will be passed to the url as 1 or 0, and converted back to boolean when processed by
a presenter.
Invalid links
It may happen that we create an invalid link – either because it refers to a non-existing presenter, or because it passes
more parameters that the target method receives in its definition, or when there can't be a generated URL for the targeted action.
What to do with invalid links is determined by the static variable Presenter::$invalidLinkMode
. It can have one of
these values (constants):
Presenter::INVALID_LINK_SILENT
– silent mode, returns symbol#
as URLPresenter::INVALID_LINK_WARNING
– visual warningPresenter::INVALID_LINK_EXCEPTION
– there will be thrown an exception InvalidLinkException
Default setup in production mode is INVALID_LINK_SILENT
and in development mode it's
INVALID_LINK_WARNING
. When setup to INVALID_LINK_WARNING
, presenter and components returns error message
as URL which stars with #error:
. To make such links visible, we will add CSS rule to our stylesheet:
a[href^="#error:"] {
background: red;
color: white;
}