This short tutorial will guide you through an example TDI usage scenario. It is a good point to start with, as it introduces main TDI principles. It has absolutely no ambitions to present a complete description. For further information, consider reading:
The tutorial should take only about 5 minutes.
In this tutorial, we will demonstrate TDI principles on an example e-shop that sells animals. The homepage of such shop may look like this:
We will show some examples of what can TDI do with this page. First, a customer sets a filter, then he or she selects an animal to buy. TDI will be responsible to update the page state using AJAX.
The home page contains a filter, which is represented by an HTML element that may look like this:
<form id="filter-form" method="post" action="/basket/setFilter"> . . . <input type="checkbox" id="legs-4" name="legs" value="4"> <label for="legs-4">Four legs</label> . . . </form>
As the first action, the customer sets the filter to show only animals with no legs or more than four legs. After checking the boxes, the filter is submitted:
Under normal circumstances, the filter settings (values of checkboxes) are sent to the server via a POST request:
POST /basket/setFilter HTTP/1.1 Host: ... . . . legs=MORE&legs=0 . . .
The server is expected to generate a new complete HTML page that will look similarly to the previous one, but with the list of animals updated to reflect the filter state.
<form id="filter-form" method="post" class="tdi" action="/basket/setFilter"> . . . <input type="checkbox" id="legs-4" name="legs" value="4"> <label for="legs-4">Four legs</label> . . . </form>
(note the class attribute at the 1st line)
One small change to the page, one giant modification to its behavior. If we submit the form with
tdi class, TDI script automatically intercepts the action and modifies the request sent to the server:
POST /basket/setFilter?_infuse=1&_ts=1380310014837 HTTP/1.1 Host: ... . . . legs=MORE&legs=0 . . .
(note the extra parameters at the 1st line)
What exactly happened and why? TDI added two extra parameters to the request:
_infuse=1- this tells the server that TDI is in action and the response should be modified accordingly. Namely, instead of returning the whole new page, only a list of TDI instructions is expected in the response.
_ts- contains the current timestamp to avoid caching. Do not bother with it now.
The server sees the
_infuse parameter, so it only returns the updated list of products (ugh, animals, of course) satisfying new filter settings. To render the new list, the server typically invokes the very same server-side template that is used to generate the list inside a whole page. The response will have
text/xml content type (instead of
text/html) and it will look like this:
<?xml version="1.0"?> <response> <status>OK</status> <update target="animal-list"> <![CDATA[ . . . <li class="product"> . . . </li> <div id="animal-list-pagination"> . . . </div> . . . ]]> </update> </response>
update instruction, there is an HTML code corresponding to the new list content. The response tells the client to update the corresponding DOM element.
To see a little bit more of TDI features, we will follow our user one more step. Imagine a Buy link is clicked:
If we want to process this action with TDI, we just tag the link with
tdi class again:
<a href="/basket/buy?animalId=PY-42" class="green buy tdi">Buy</a>
And, once again, TDI intercepts the user action and appends its two extra parameters (
_ts) to the request:
GET /basket/buy?_infuse=1&_ts=1380310014837&animalId=PY-42 HTTP/1.1 Host: ... . . .
The server does not generate the whole page because of the
_infuse parameter is present. Instead, it sends necessary updates to the page. In this case, more than one instruction is present, so the logic will have to be a little bit more complicated.
<?xml version="1.0"?> <response> <status>OK</status> <insert target="basket-total-amount" position="before"> <![CDATA[ <li class="one-basket-item">1 Python . . .</li> ]]> </insert> <script id="buy-script" src="js/basket-buy-script.js"></script> <update target="user-profile-info" class-add="with-basket" class-remove="empty" append="true"></update> <update target="basket-value">139</update> . . . </response>
After all of the instructions are performed, the page will be updated.
And that's it! Again, the update is done without the page being reloaded.
The example above was just a quick introduction. TDI can do much more. The concise list of its basic features follows to give you an idea.
To provide a feedback to users, TDI allows to add a visual indication of a request being processed. See Browser-side documentation for details.
If you want to experiment with TDI by yourself you may: