Robin
Robin

Reputation: 3840

Symfony2 - Change Page Content - Like Ajax

I am evaluating an ArrayCollection in my Template like this:

{% for article in articles %}
   <li
      {% if article.new %}
         class="new"
      {% endif %}
   >{{ article.name|e }}</li>
{% endfor %}

Now I want to reload the articles ArrayCollection without reloading the whole page, like you would do in Ajax. Is it possible to reload it and let twig evaluate all the articles in a loop like the above?

I want to use twig to evaluate the content

Upvotes: 1

Views: 1685

Answers (1)

Uriziel
Uriziel

Reputation: 742

It's possible, yes. You just need to make an ajax request to the action that'd return rendered collection. This can be achieved by creating new action (recommended) or adding new paramenters in request that would tell twig which part to render or not (easier to do, harder to maintain).

Edit

Extending my answer because author requested me to.

Lets assume News controller in YourNs\YourBundle Its contents should looks somewhat like this:

class NewsController extends Controller
{

    /**
     * @Route("/articles")
     * @Template()
     */
     public function listAction(){
         $articles = $this->yourMethodToFindArticles();
         return compact('articles');
     }
}

Next thing to do is to render this action by adding YourNs/YourBundle/Resources/views/News/list.html.twig file and filling it up.

Once you have it done you'll need to add functionality to fire up ajax request to fetch refreshed collection of articles. FOSJsRouting might prove useful for that as well.

You can either add new action to controller

    /**
     * @Route("/_api/articles-list")
     * @Template()
     */
     public function apiListAction(){
         $articles = $this->yourMethodToFindArticles();
         return compact('articles');
     }

And make its template render just your collection.

Or parametrize your first action and render template according to that:

{% if app.request.query.get('partial') %}
Template elements
{% endif %}
{% for article in articles %}
<li
  {% if article.new %}
     class="new"
  {% endif %}
>{{ article.name|e }}</li>
{% endfor %}
{% if app.request.query.get('partial') %}
Other template elements
{% endif %}

Second solution is clearly inferior to the first one, especially once you start using esi tags, if you do that your code would look like this:

class NewsController extends Controller
{

    /**
     * @Route("/articles")
     * @Template()
     */
     public function listAction(){
         return [];
     }

    /**
     * @Route("/_api/articles-list")
     * @Template()
     */
     public function apiListAction(){
         $articles = $this->yourMethodToFindArticles();
         return compact('articles');
     }
}

And listAction() template:

Template elements
{{ render_esi(url('yourns_yourbundle_news_apilist' }}
Other template elements

Note that the above snippets are just a simplified solution explaining trivial issue.

Edit2

Example of fetching that uses FOSJsRouting, js code with the api action:

var url = Routing.generate('yourns_yourbundle_news_apilist')
var fetchedCollection = $.get(url);

And example with parametrized template:

var url = Routing.generate('yourns_yourbundle_news_list', {'partial': 'true'})
var fetchedCollection = $.get(url);

Upvotes: 2

Related Questions