Simple dynamic ajax content replacing with snippets
- paolo
- Member | 15
In my blog homepage I have, by default, a list of articles, rended by template Article/list.latte, with summaries and a link to the full article:
Homepage/default.latte:
.....
<div id="articles" class="content">
{includeblock '../Articles/list.latte'}
</div>
.....
Articles/list.latte:
{block #content}
<div class="article-list">
{foreach $articles as $article}
<div class="article-list-item">
<a title="Go to article" n:href="Articles:view, $article->id">
<div class="article-header">
<span class="article-title">{$article->title}</span>
<span class="article-author">{$article->user->username}</span>
<span class="article-datetime">{$article->creation_time|italianDate}</span>
</div>
<div class="article-subtitle">{$article->subtitle}</div>
<div class="article-summary">{$article->summary}</div>
</a>
</div>
{/foreach}
</div>
{/block}
Now I want to ajaxify the link to the article, and make it load the content
of the article inside the “articles” DIV, replacing the list.
How can I do it using snippets (and possibly jquery.nette.js or
nette.ajax.js)?
- paolo
- Member | 15
petr.pavel wrote:
Have you read the docs? If you did, what isn't clear to you?
Of course I read them. And I've seen the Fifteen example, at which the docs
refer. But this example use a component. The snippets in the template refer
explicitly to the control rendering ({control fifteen}
) or to some
of its properties ({$presenter['fifteen']->round + 1}
). This way
it is rather simple.
But in my case I want to replace the contents of the snippet with the
contents of another presenter template.
As a test, I tried this (with jquery.nette.js):
default.latte:
<a n:href="view, 1" class="ajax">Article #1</a>
.....
{snippet articles}
{ifset #content}
{include #content}
{/ifset}
{/snippet}
view.latte:
{block #content}
.......
{/block}
HomepagePresenter.php:
public function actionView($id = 0)
{
if ($this->isAjax())
$this->invalidateControl('articles');
}
While the non-ajax version (without class="ajax"
) displays the
article in another page as expected, with the ajax version, I only see the
spinner for a few seconds, but nothing gets displayed.
Maybe I'm missing something very basic which for you is fairly obvious…
A very simple working example may help me very much.
Thank you for your attention.
Paolo
Last edited by paolo (2012-09-04 14:10)
- Vojtěch Dobeš
- Gold Partner | 1316
I guess the problem is, that you want both templates to be used without
clear connection between them. actionView
will use
view.latte
, but won't use default.latte
(how should
know to use it?). And default.latte
shows {#content}
only if set (if the shown template is complete, I suppose the snippet is
empty?).
- Vojtěch Dobeš
- Gold Partner | 1316
I believe the best-practice is to have {include #content}
in
@layout.latte
. Then every view template contains
{block #content}
with appropriate content. If you wrap the
{include}
in snippet and invalidate it e.g. in
beforeRender()
method, it should work pretty well with
ajaxification.
- paolo
- Member | 15
vojtech.dobes wrote:
I guess the problem is, that you want both templates to be used without clear connection between
them.actionView
will useview.latte
, but won't usedefault.latte
(how should know to use it?)
Thank you for your hints.
In fact what I was missing was to declare view.latte
as an
extension of default.latte
. I also followed your advice to put the
invalidation code in BeforeRender
, and now it works as
expected.
I read again the docs, and realized that maybe the best thing to do is to build
the application without ajax until all pages look and work as planned, then
ajaxify it by adding snippets and class="ajax"
to the links. This
also grants that all pages look the same if loaded without ajax (e.g. by
pressing the reload button in the browser). Very simple and very good!
The only other things to take care of, are to explicitly declare
{include '@layout.latte'}
in the homepage, to assure that the base
template is included in “child” templates too and, if you have ajax links
inside some snippet, to provide some javascript to ajaxify the links loaded by
ajax (using a different selection mechanism other than the ajax
class, to avoid affecting the already ajaxified links).
Last edited by paolo (2012-09-06 19:00)
- Vojtěch Dobeš
- Gold Partner | 1316
As you say, that's great feature of Nette, that you can write application without AJAX, and then easily ajaxify it by few extra simple lines of code.
Ajaxifying the links loaded via AJAX is handled by nette.ajax.js
,
you might wanna try that one. It's no problem to have all links with CSS class
ajax
– it makes sure that links have only ajaxifying callback
attached.
- paolo
- Member | 15
Now I'm using nette.ajax.js
and it works very well. No need to
care about ajax links loaded via ajax. Thanks.
Only, I modified the spinner extension to be displayed at the center of the
document:
createSpinner: function () {
return $('<div>').attr({
id: 'ajax-spinner'
}).css({
display: 'none',
position: 'fixed',
left: '50%',
top: '50%'
});
},
Note that setting the style attribute instead of using css() does not
work.
One question: what is the scrollTo
extension?
- Vojtěch Dobeš
- Gold Partner | 1316
Yeah, I have to fix that.
scrollTo
adds behavior, that page scrolls to first invalidated
snippet.