Symfony twig + reactJS - symfony

I would like to render a reactJS component from twig template. Is it possible?
I tried:
<div class="top-line">
<h1>{{ username }}</h1>
{% verbatim %}
<script type="text/html" id="follow-button">
<FriendshipButton user={{ app.user }} />
</script>
{% endverbatim %}
<div id="follow-button-mp"></div>
</div>
And in JS side:
React.render(
React.createElement(document.getElementById('follow-button').innerHTML),
document.getElementById('follow-button-mp')
);
Getting an error:
Uncaught Error: Invariant Violation: Invalid tag:
<FriendshipButton user={{ app.user }} />

Twig:
<script type="text/javascript">
// you might have to serialise user to JSON here if you
// want a more complete user object
var user = '{{ app.user.id }}';
</script>
Javascript component (using JSX)
React.render(
<FriendshipButton user={user} />,
document.getElementById('follow-button-mp')
);

Related

Symfony/vue - how to passe data from controller to vue

I'm using Symfony 5 / twig with webpack.encore and vue.js.
I passing datas (translation texts) to the used twig-template like this:
Controller:
class HomepageController extends AbstractController
{
const PAGE_ID = 2; // constants PageId
/**
* #Route("{_locale}/homepage", name="app_homepage")
*
*/
public function index(Request $request,SpracheRepository $spracheRepository)
{
$arrTrans = $spracheRepository->findAllOfSpecificPage(self::PAGE_ID,$request->getLocale());
return $this->render('core/homepage/homepage.html.twig', [
'headline' => $arrTrans['lb_overview'],
'pageId' => self::PAGE_ID,
'arrTrans' => $arrTrans
]);
}
}
...and I'd like to access the datas "arrTrans" in the vue file.
The html.twig is looking like:
{% block content %}
<div id="app"></div>
{% endblock %}
{% block stylesheets %}
{{ parent() }}
{{ encore_entry_link_tags('homepage') }}
{% endblock %}
{% block javascripts %}
{{ parent() }}
{{ encore_entry_script_tags('homepage') }}
{% endblock %}
The corsponding .js file:
import Vue from 'vue';
import App from '../vue/homepage'
new Vue({
render: (h) => h(App),
}).$mount('#app');
...and the vue file themselfe: (I'd like to use the arrTrans in the div of the "button-overview-lable")
<template>
<div class="button-overview">
<div class="button-overview-lable">{{ arrTrans['lb_planning'] }}</div>
</a>
</div>
</template>
<script>
export default {
name: "Homepage",
}
</script>
<style lang="scss">
#import "../../../core/app/css/helper/variables";
#import "../css/homepage";
</style>
If you need to pass data from your template file to a javascript file you can use data attribute.
<div id="app" data-trans="{{ arrTrans | json_encode() }}"></div>
new Vue({
el: '#app',
data: {
trans: null
},
mounted: function() {
this.trans = this.$el.getAttribute('data-trans');
}
});
You can create a JS variable in twig template and pass json-encoded array. Like this (also we disable automatic html-escaping using raw filter):
{% block content %}
<script>
const arrTrans = JSON.parse('{{ arrTrans|json_encode()|raw }}')
</script>
<div id="app"></div>
{% endblock %}
But you have to deal with ' character in your locale strings because it will cause JS syntax error. Replace raw filter with escape('js').
So, the final twig template is:
{% block content %}
<script>
const arrTrans = JSON.parse('{{ arrTrans|json_encode()|escape('js') }}')
</script>
<div id="app"></div>
{% endblock %}
Then in vue app you will just use this variable in data:
<template>
<div class="button-overview">
<div class="button-overview-lable">{{ arrTrans.lb_planning }}</div>
</a>
</div>
</template>
<script>
export default {
name: 'Homepage',
data() {
return {
arrTrans,
};
},
};
</script>
<style lang="scss">
#import "../../../core/app/css/helper/variables";
#import "../css/homepage";
</style>
Thanks for the answers, but I had some problems to implement them. What's now working for me was:
Homepage.html.twig
<div ref="translation" data-translation="{{ arrTrans|json_encode() }}"></div>
Homepage.js
new Vue({
el: '#app',
render: (h) => h(App),
})
homepage.vue
<template>
<div>
<div>{{ trans }}</div>
<div>{{ trans['lb_planning'] }}</div>
</div>
</template>
export default {
name: 'HomePage',
data() {
return {
trans: {}
};
},
mounted() {
let elTrans = document.querySelector("div[data-translation]");
let myTrans = JSON.parse(elTrans.dataset.translation);
this.trans= myTrans;
}
}

Symfony3 - fullcalendar.js events not displaying

I'm using fullcalendar.js with Symfony 3.4 (as all the bundles are deprecated since version 3). The calendar itself is showing, when I hardcoded in js the events they're showing. But when i send my events with JSON they don't show themselves and the calendar is blank. However, the json source is in the correct format and indeed catched by my page (http 200 response). Here's my controller who got the data and send a JSON:
/**
* #Route("/calendrierFeed", name="calendrierFeed", methods={"GET"})
*/
public function feedAction()
{
$em = $this->getDoctrine()->getManager();
$aquariums = $em->getRepository('AppBundle\Entity\Aquarium')
->findBy(
array('user' => $this->getUser()->getId())
);
$events = $em->getRepository('AppBundle\Entity\Calendrier')
->findBy(array(
'aquarium' => $aquariums
));
$calendrier = array();
foreach ($events as $event) {
$e = array();
$e['id'] = $event->getId();
$e['title'] = $event->getTypeEntretiens() . " pour l'aquarium " . $event->getAquarium()->getNom();
$e['start'] = $event->getDateEntretiens();
if ($event->getRealise()) {
$e['color'] = 'green';
} else {
$e['color'] = 'red';
}
$e['allDay'] = true;
array_push($calendrier, $e);
}
return $this->json($calendrier);
}
Here's my twig template:
{% block stylesheets %}
{{ parent() }}
<link rel="stylesheet" href="{{ asset('css/membre/fullcalendar.min.css') }}">
{% endblock %}
{% block body %}
<div id='calendar'></div>
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script src="{{ asset('js/membre/moment.min.js') }}"></script>
<script src="{{ asset('js/membre/jquery.min.js') }}"></script>
<script src="{{ asset('js/membre/fullcalendar.min.js') }}"></script>
<script src="{{ asset('js/membre/fr.js') }}"></script>
<script type="text/javascript">
$(document).ready(function() {
$('#calendar').fullCalendar({
events: '/calendrierFeed',
defaultView: 'month',
selectable:true,
selectHelper:true,
editable:true
});
});
</script>
{% endblock %}
And here's my JSON feed
[{"id":2,"title":"oui pour l\u0027aquarium 200L","start":{"date":"2018-02-12 00:00:00.000000","timezone_type":3,"timezone":"UTC"},"color":"red","allDay":true}]
Your date should be a string, not an object.
I checked in my json feed in my personnal project, I got it this way:
"start":"2018-02-13"
From the doc
The date/time an event begins. Required.
A Moment-ish input, like an ISO8601 string. Throughout the API this
will become a real Moment object.
This mean you should format your date
$e['start'] = $event->getDateEntretiens()->format('Y-m-d');

handlebars template can't fill with data

I need to output data and fill my template throught custum function
this is my imports
<script src="{{ asset('bundles/.../handlebars/handlebars.js') }}"></script>
<script src="{{ asset('bundles/.../handlebars_helpers.js') }}"></script>
this is my template into twig page
<script id="di_template" type="text/x-handlebars-template">
{% verbatim %}
<h1>Title </h1>
Invoice {{ invoice.invoice_number }}
{% endverbatim %}
</script>
this my build Template Function
function buildTemplate(){
context = {
invoice: {
invoice_number: 'val1',
invoice_date: 'val2',
invoice_due_date: 'val3',
invoice_from_company: 'val4'
}
};
template = $('#di_template').html();
template_compiled = Handlebars.compile(template);
theCompiledHtml = template_compiled(context);
$invoice_preview.html(theCompiledHtml);
}
this my result

How to pass twig variables to a js file included using <script src="...">

For a twig template file, I want to separate the js content from my HTML content, so I have created a .js file
with this content:
{% if form.vars.data is not null %}
function downloadInvoice() {
window.location = '{{ path('ziiweb_billing_bill', {'id': form.vars.data.id}) }}';
}
{% endif %}
function updateTotals() {
$('#service_download_pdf').css("pointer-events", "none");
$('#service_download_pdf').attr("disabled", "true");
that Im adding using this line:
<script type="text/javascript" src="/bundles/ziiwebbilling/js/service_form.js"></script>
but get this error:
SyntaxError: expected expression, got '%' {% if form.vars.data is not
null %}
You cannot put twig into your js files. However to pass twig variables to js files, you need to do have a script inside your twig file like this:
twig file
<script>
//var data = {{ form.vars.data|default('') }};
// I think it's better to pass the url directly
{% if form.vars.data is not null %}
var url = '{{ path('ziiweb_billing_bill', {'id': form.vars.data.id}) }}';
{% endif %}
</script>
<script type="text/javascript" src="/bundles/ziiwebbilling/js/service_form.js"></script>
service_form.js
if (typeof url === 'undefined') {
// If the url exists
}
Furthermore, there is a bundle that exposes routes https://github.com/FriendsOfSymfony/FOSJsRoutingBundle
At the end, you should not define a js function if a test is valid, however you should check when running the function

add calendar in FOSUseBundle's form

I have some problem. I need add in registration template in FOSUserBundle calendar which allows choose birthday user's - the standard html tag date doesn't fit. To order to do this I used datepicker of jQuery:
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<link rel="stylesheet" href="/resources/demos/style.css">
<script>
$(function () {
$("#fos_user_registration_form_birthday").datepicker({
changeMonth: true,
changeYear: true,
yearRange: '1950:2010',
});
});
</script>
<form action="{{ path('fos_user_registration_register') }}" {{ form_enctype(form) }} method="POST" class="fos_user_registration_register">
{{ form_errors(form) }}
<ol>
[.........]
<li>
{{ form_label(form.birthday) }}
{{ form_widget(form.birthday) }}
{{ form_errors(form.birthday) }}
{{ form_rest(form) }}
</li>
<input type="submit" value="{{ 'registration.submit'|trans }}" />
</li>
</ol>
[.........]
</form>
It's working fine, but if I override the template and add:
{%extends 'MyBlogBundle::layout.html.twig'%}
{% block content %}
[ form registration]
{% endblock%}
It doesn't work.
So, what am I doing wrong?
And I have one more than question - how to add or change class, id in registration form? I tried it in template
{{ form_widget(form.birthday {'attr': {'class': 'task_field'}}) }}
and in RegistrarionFormType:
->add('birthday','text',array('attr'=>array('id'=>'text_field')))
But id doesn't change.
Hi I'm kinda new to this domain but I believe you should include
{% block fos_user_content %}
in your main template or overwrite them totaly in your own bundle (your bundle class should then contain getParent() method)
I believe the main template lives in (if your bundle is named UserBundle)
UserBundle\Resources\views\layout.html.twig
the most basic overwrite would then be
{# UserBundle\Resources\views\layout.html.twig #}
{% extends '::base.html.twig' %}
{% block body %}
{{ block('fos_user_content') }}
{% endblock %}
// UserBundle\UserBundle.php
namespace UserBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class UserBundle extends Bundle
{
public function getParent()
{
return "FOSUserBundle";
}
}
After that you can copy the templates you want to overload to corresponding bundle folder eg
UserBundle\Resources\views\Registration\xx.html.twig
from the FOSUserBundle.
After changing the "include strategy" in your project you must clear your cache also in DEV mode otherwise you wil not see the changes. Changes applied to the content do not need a clearing of your cache.

Resources