Feb 19, 2015 Tags: JQuery, Fluid, TYPO3, Javascript
How do you hand over data from the server to the Javascript of an HTML5 document? Here’s what I found out. Currently I’m talking about TYPO3 6.2, Extbase/Fluid and JQuery 1.11.2.
Let’s say we have a form in an html5 page and we want to do advanced clientside validation. And we have a matrix of possible combinations that we want to validate against.
How to we best transmit that data?
Think of this example: We want to create a form with two choices: fruit and color. The point is that what color you can choose depends on what fruit you have chosen. And the form cannot know in advance since the fruits may be different in the next run. How do we best tell the form what choices are valid?
Try this example to understand what the form is supposed to do:
In our example we first have to choose the fruit: It’s either apple or pear. After that we choose the color to find the result. For apple the possible colors are green and red. And for pear they are green and yellow. As a result we get one of the outcomes sweet, sour, tasty or hard. Let’s see how we can accomplish that.
(1) We first prepare a data matrix. (2) Then we convert to Json format and (3) hand the data over to a Fluid view:
<?php
// (1) define matrix
$matrix = array(
// choice 1: fruit, choice 2: color, result
array('apple', 'red', 'sweet'),
array('apple', 'green', 'sour'),
array('pear', 'yellow', 'tasty'),
array('pear', 'green', 'hard')
);
// (2) rewrite as json
// [["apple","red","sweet"],["apple","green","sour"],
// ["pear","yellow","tasty"],["pear","green","hard"]]
$matrixJson = json_encode($matrix);
// (3) in TYPO3 Extbase controller: assign to view
$this->view->assign('matrixJson', $matrixJson);
?>
Now the tricky part: What syntax is appropriate in the Fluid template?
Let’s say we want to provide the data in a data
attribute of an html tag.
The following works for me:
<html xmlns:f="http://typo3.org/ns/TYPO3/Fluid/ViewHelpers"
f:schemaLocation="https://fluidtypo3.org/schemas/fluid-master.xsd">
</f:form>
<!-- (a) html -->
<input id="abc" name="abc" data-matrix="{matrixJson}" />
<!-- (b) tag usage of Fluid viewhelper f:form.hidden -->
<f:form.hidden name="bcd" id="bcd"
additionalAttributes="{data-matrix:'{matrixJson}'}" />
<!-- (c) inline usage of Fluid viewhelper f:form.hidden -->
{f:form.hidden(name:"cde", id:"cde",
additionalAttributes:{ data-matrix:'{matrixJson}' }) }
</f:form>
Three different ways are shown:
<input />
tag literally and Fluid only renders the data-matrix
attributef:form.hidden
Fluid viewhelper
which by itself contains {matrixJson}
as another Fluid inline element.f:form.hidden
Fluid viewhelper. And again there is
the nested {matrixJson}
Fluid inline element.Why does this work? The “trick” is that the rendering of {matrixJson}
automatically does a
htmlspecialchars()
conversion including conversion of double quotes.
This makes sure that <,&,>,"
become <, & >, "
.
So the Json data doesn’t interfere with normal html tag notation.
What happens clientside? When we use JQuery some magic is happening automatically.
JQuery attaches an unique key to the tag. And it reads the data of data-matrix
from the input tag. JQuery automatically tries a decode from Json
which is successful in our case.
As a result we get the matrix as an object (a list of lists).
JQuery then stores this object in a cache owned by JQuery. Schematically this
looks like jQuery.cache[uniqueTagKey]['matrix'] = matrix;
.
From that on JQuery doesn’t touch the tag’s data
attribute any more but always uses its
own cache for .data()
operations.
We now can easily access the Javascript matrix object:
<script type="text/javascript">
(function ($) {
$(document).ready(function(){
var matrix = $('#abc').data('matrix');
// show just one row to prove we have
// an object: apple,red,sweet
alert(matrix[0]);
})}(jQuery));
</script>
Note: Due to JQuery’s magic the conversion vom Json to object has happened automatically. If JQuery doesn’t succeed with that JSONdecode it simply returns a string.
Attention: I’m just starting with Extbase & Fluid and I have no idea whether what I’m writing is a recommended way of doing it.
What do you think?