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');
Related
Im trying to use the OpenLayers library in my symfony application. Im using Webpack encore for managing my assets. I've used npm to download the OpenLayers library.
When im trying to use it inside a js file, only the first 'ol' class is available, the classes underneath it are not. In browser the ol.layer.Tile class is not recognised and throws an exception(Uncaught type error).
// map.js
require('../css/map.css');
const ol = require('ol');
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center: ol.proj.fromLonLat([37.41, 8.82]),
zoom: 4
})
});
//map.html.twig
{% extends '::base.html.twig' %}
{# STYLESHEETS-------------------------------------------------- #}
{% block stylesheets %}
{{ parent() }}
<link href="{{ asset('build/map.css') }}" rel="stylesheet" />
{#<link href="https://openlayers.org/en/v4.6.5/css/ol.css" rel="stylesheet" type="text/css"/>#}
{% endblock %}
{# JAVASCRIPTS-------------------------------------------------- #}
{% block javascript %}
{{ parent() }}
{#<script src="https://openlayers.org/en/v4.6.5/build/ol.js" type="text/javascript"></script>#}
<script src="{{ asset('build/map.js') }}"></script>
{% endblock %}
{# PAGE CONTENT-------------------------------------------------- #}
{% block title %}OpenLayers example{% endblock %}
{% block body %}
<body>
<h2>My Map</h2>
<div id="map" class="map"></div>
</body>
{% endblock %}
No need to add script tag if you are using require
`{#<script src="https://openlayers.org/en/v4.6.5/build/ol.js" type="text/javascript"></script>#}`
You should require also Tile, View
var ol_Map = require('ol/map').default;
var ol_layer_Tile = require('ol/layer/tile').default;
var ol_source_OSM = require('ol/source/osm').default;
var ol_View = require('ol/view').default;
var map = new ol_Map({
target: 'map',
layers: [
new ol_layer_Tile({
source: new ol_source_OSM()
})
],
view: new ol_View({
center: ol.proj.fromLonLat([37.41, 8.82]),
zoom: 4
})
});
See the document from OpenLayers http://openlayers.org/en/latest/doc/tutorials/browserify.html
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
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
so I've been working on a simple website and have a simple question, I guess. I have my base template named template.html and I'm using it on every html page I have. My question is, can a base template have a data from a database? Because it isn't being rendered right? For example I have here my 404 page (I'm using slim framework btw).
$app->notFound(function () use ($app) {
$app->render('404.html');
});
And what is inside looks like this:
As you can see in the image, there is the part <!-- Loaded data from the base template.html -->. Can a base template have a data from a database? If so, how? Thank you!
You can use inheritance.
Simple method
Your route definition:
<?php
/**
* Not found.
*/
$app->notFound(function () use ($app) {
//Your amazing business to get data
$books = array(
"The Hobbit",
"Leaf by Niggle",
"The Lay of Aotrou and Itroun",
"Farmer Giles of Ham",
"The Homecoming of Beorhtnoth Beorhthelm's Son"
);
$app->render('404.html', array(
'books' => $books
));
});
Your template.html:
<!DOCTYPE html>
<html>
<head>
{% block head %}
<link rel="stylesheet" href="style.css" />
<title>{% block title %}{% endblock %} - My Webpage</title>
{% endblock %}
</head>
<body>
<div id="content">
{% block content %}
{% block books %}
<h3>My magic books</h3>
<ul class="books">
{% for book in books %}
<li>{{ book }}</li>
{% endfor %}
</ul>
{% endblock %}
{% endblock %}
</div>
</body>
</html>
Your 404.html:
{% extends "template.html" %}
{% block title %}404{% endblock %}
{% block content %}
{% block books %}
<div id="">
{{ parent() }}
</div>
{% endblock %}
{% endblock %}
Hook method
If you need it everywhere, you could use a hook.
$app->hook('slim.before.router', function() use ($app) {
//Your amazing business to get data
$books = array(
"The Hobbit",
"Leaf by Niggle",
"The Lay of Aotrou and Itroun",
"Farmer Giles of Ham",
"The Homecoming of Beorhtnoth Beorhthelm's Son"
);
$app->view()->setData('books', $books);
});
//And let your notFound handler be light
$app->notFound(function () use ($app) {
$app->render('404.html');
});
Yes, a base template can display a DB content:
you have to retrieve the data you want, render it to specific template to display and then, in your base template, you use the render(controller) method, something like
public function xyzAction(){
$data=$this->getDoctrine .... ;
return $this->render('XYZYourBundle:test.html.twig',array('data'=>$data));
}
in test.html.twig:
{℅ for d in data %}
// do your stuff
{% endfor ℅}
and in where you want to add this to your base template:
{{ render(controller('XYZYourBundle:Controller_name:xyz'))}}
you can pass arguments to the controller action too, this would be helpful.
In Slim 3 you can use Middleware instead hooks.
BooksMiddleware.php
class BooksMiddleware{
protected $container;
public function __construct($container) {
$this->container = $container;
}
public function __invoke($request, $response, $next){
$sql = "SELECT * FROM books";
$stmt = $this->container->db->prepare($sql);
$stmt->execute();
$books= $stmt->fetchAll(PDO::FETCH_OBJ);
$request = $request->withAttribute('books', $books);
$response = $next($request, $response);
return $response;
}
}
routes.php
$app->get('/home', '\HomeController:home')->add(BooksMiddleware::class);
$app->get('/about', '\AboutController:about')->add(BooksMiddleware::class);
HomeController.php
class HomeController{
protected $container;
public function __construct($container) {
$this->container = $container;
}
public function home($request, $response) {
return $this->container->view->render($response, 'home.html', [
'books' => $request->getAttribute('books')
]);
}
AboutController.php
class AboutController{
protected $container;
public function __construct($container) {
$this->container = $container;
}
public function about($request, $response) {
return $this->container->view->render($response, 'about.html', [
'books' => $request->getAttribute('books')
]);
}
}
Lets say i have a one to many relation:
A company can own several pictures
I have company entity and image entity
Now, I want to display all pictures of a company within a template. And i also want to make theese pictures directly editable. I thought of adding a form to each Entity of the DoctrineArrayCollection and pass them to the template. In Template if somebody clicks on a picture the corresponding should be fade in, the should be able to edit the pictures description and pass it through ajax to a controller.
In my entity I added a field without annotations:
private $form;
public function setForm(MyPictureForm $form)
{
$this->form = $form;
}
public function getForm()
{
return $this->form;
}
Now in my controller I add a form instance to every picture of the company:
//office images with forms
$officeImages = array();
foreach($company->getOfficeImages() as $image)
{
$form = $this->get('companybundle.imagedescription.form.factory')->createForm();
$form->setData($image);
$image->setForm($form->createView());
array_push($officeImages, $image);
}
return $this->render('CompanyBundle:Company:Show/show.html.twig', array(
'company' => $company,
'officeImages' => $officeImages
));
}
And in my template i render it like this way:
{% for image in officeImages %}
<a href="#" title="{% if image.description %}{{ company.description }}{% else %}CLICK HERE FOR EDIT{% endif %}">
{% if image.image %}
<img src="{{ vich_uploader_asset(image, 'image') | imagine_filter('company_office_image_thumb') }}"
alt="{% if image.description %}{{ company.description }}{% endif %}"/>
{% else %}
{% image '#UserBundle/Resources/public/img/nopic_logo.jpg' output='/images/nopic_logo.jpg' %}
<img src="{{ asset_url }}" alt="Joblogo"/>
{% endimage %}
{% endif %}
</a>
{{ form(image.form) }}
{% else %}
<p>Es sind noch keine Images vorhanden</p>
{% endfor %}
At the end there is a lot if javascript stuff which handels the fade in / fade out of the form and their submitting.
Is this the correct way to handle my case? I think not cause passing a form for every picture seems like overhead?
The reason why I am working with forms instead of simply passing data out of a manual added input field is csrf protection and the smart usage of the form component.
As you said keeping form object in entity isn't a good idea. It should represents model data.
I've got two solutions for this:
I. Pass array of forms with image id as a key
$officeImages = array();
$imageForms = array();
foreach($company->getOfficeImages() as $image)
{
$form = $this->get('companybundle.imagedescription.form.factory')->createForm();
$form->setData($image);
$imageForms[$image->getId()] = $form->createView();
}
return $this->render('CompanyBundle:Company:Show/show.html.twig', array(
'company' => $company,
'officeImages' => $officeImages,
'imageForms' => imageForms
));
and in show.html.twig
{% for image in officeImages %}
{# your image display code #}
{{ form(imageForms[image.id]) }}
{% endfor %}
II. render partial for single image
in controller
public function showAndEditImageAction(Image $image)
{
$form = $this->get('companybundle.imagedescription.form.factory')->createForm();
$form->setData($image);
return $this->render(
'CompanyBundle:Company:Show/showAndEditImage.html.twig', array(
'image' => $image,
'imageForm' => $form->createView()
));
}
in twigs
{# CompanyBundle:Company:Show/showAndEditImage.html.twig #}
{# your image display code #}
{{ form(imageform) }}
{# CompanyBundle:Company:Show/show.html.twig #}
{% for image in officeImages %}
{{ render(controller('CompanyBundle:Company:showAndEditImage',
{ 'image': image })) }}
{% endfor %}