By Sebastiaan de Jonge, published on Friday, August 3, 2012 at 09:00

TypoScript can be an extremely powerful tool for developing TYPO3 projects. If you know how and when to use it. The main purpose is of course configuration, but how far can you configure? In this post I will demonstrate that you can create a simple list and detail view with template parsing in just over 100 lines of TypoScript.

The TypoScript "extension"

What I'm going to do is create listing of some address records (tt_address) in the frontend. Of course this can be done with any other database record. Let's start by having a look at the template. I've kept it really simple by just showing some basic stuff, no fancy layouts etcetera.

<!-- ###template_AddressList### begin -->
<ul class="component-addresslist">
    <!-- ###subpart_Address### -->
    <li>
        <a href="###Link###">
            <span class="thumbnail">###Thumbnail###</span>
            <span class="name">###Firstname### ###Lastname###</span>
        </a>
    </li>
    <!-- ###subpart_Address### -->
</ul>
<!-- ###template_AddressList### end -->
<!-- ###template_AddressList_Detail### begin -->
<div class="component-addresslist-detail">
    <a class="back-link" href="###BackLink###">&lt;&lt; Back to the overview</a>
    <div class="photo">###Photo###</div>
    <div class="details">
        <label>Name: </label><span class="name">###Firstname### ###Lastname###</span>
        <label>Date of birth: </label><span class="date-of-birth">###DateOfBirth###</span>
        <label>Description: </label>
        <p class="bodytext">
            ###Description###
        </p>
    </div>
    <div class="clear"></div>
</div>
<!-- ###template_AddressList_Detail### end -->

The template

The template contains two template subparts, one for the list view and one for the detail view. This is just old-fashioned templating, using markers and subparts to get what we want. Now let's have a look at the TypoScript code we use to render the addresses into this template.

# The address list component
lib.shared.components.addresslist = TEMPLATE
lib.shared.components.addresslist {
    # We load the template. Beacause our template has multiple sub-templates, we tell it which subpart we are
    # going to work on right now.
    template = FILE
    template.file = fileadmin/shared/templates/components/addresslist/addresslist.html
    workOnSubpart = template_AddressList
    subparts {
        # Substitute the subpart named 'subpart_Address' with a CONTENT object
        subpart_Address = CONTENT
        subpart_Address {
            table = tt_address
            select {
                orderBy = last_name ASC
                pidInList = 15
            }
            # Again we use a template and assing the required subpart
            renderObj = TEMPLATE
            renderObj {
                template = FILE
                template.file = fileadmin/shared/templates/components/addresslist/addresslist.html
                workOnSubpart = subpart_Address
                # Let's assign some markers!
                marks {
                    Thumbnail = IMAGE
                    Thumbnail.file {
                        import = uploads/pics/
                        import.field = image
                        import.listNum = 0
                        height = 40c
                        width = 40c
                    }
                    Firstname = TEXT
                    Firstname.field = first_name
                    Firstname.htmlSpecialChars = 1
                    Lastname = TEXT
                    Lastname.field = last_name
                    Lastname.htmlSpecialChars = 1
                    # We just generate the link, no A-tag wrap
                    Link = TEXT
                    Link.typolink {
                        parameter.data = TSFE:id
                        additionalParams.dataWrap = &ts_addresslist[showUid]={field:uid}
                        returnLast = url
                        # The cache hash is needed to display the right content, since we are not running as USER_INT
                        useCacheHash = 1
                    }
                }
            }
        }
    }
    # The stdWrap will overwrite the object in case we are viewing a detail (condition at the bottom)
    stdWrap.override.cObject = CONTENT
    stdWrap.override.cObject {
        table = tt_address
        select {
            andWhere.data = GP:ts_addresslist|showUid
            # Make sure there is no SQL injection!
            andWhere.intval = 1
            andWhere.wrap = uid=|
            orderBy = last_name ASC
            pidInList = 15
        }
        # Again we use a template and assing the required subpart
        renderObj = TEMPLATE
        renderObj {
            template = FILE
            template.file = fileadmin/shared/templates/components/addresslist/addresslist.html
            workOnSubpart = template_AddressList_Detail
            # Let's assign some markers!
            marks {
                Photo = IMAGE
                Photo.file {
                    import = uploads/pics/
                    import.field = image
                    import.listNum = 0
                    maxH = 200
                    maxW = 200
                }
                Firstname = TEXT
                Firstname.field = first_name
                Firstname.htmlSpecialChars = 1
                Lastname = TEXT
                Lastname.field = last_name
                Lastname.htmlSpecialChars = 1
                DateOfBirth = TEXT
                DateOfBirth.field = dateofbirth
                DateOfBirth.date = Y-m-d
                Description = TEXT
                Description.field = description
                Description.htmlSpecialChars = 1
                BackLink = TEXT
                BackLink.typolink {
                    parameter.data = TSFE:id
                    returnLast = url
                }
            }
        }
    }
    # Make sure the detail view is only displayed if there is actually a showUid specified
    stdWrap.override.if {
        isTrue.data = GP:ts_addresslist|showUid
        isTrue.intval = 1
    }
}

The TypoScript

I have documented the code actually within the snippet, so I will not go into too much detail here of what does what. But basically, the code looks up the tt_address records with parent ID 15 (the storage folder), and outputs them one by one.

The override section is where the detail view is rendered, of course only if there is an actual item specified by showUid inside the query string. And that's it!

Of course this snippet just creates the component, you will still need to assign it to your page. For example by using the following snippet.

# Assign it directly to the page
page.10 < lib.shared.components.addresslist
# Assign it to a marker within your current template
page.10.marks.CONTENT < lib.shared.components.addresslist

Conclusion

Of course you have to keep in mind that TypoScript might be too limited for some functionalities. But when it comes to stuff like this (simple list and detail views), why bother making an extension and writing all that PHP code to get the same effect. Writing TypoScript is fun, and creating things like this can give you better insight in how TypoScript works and how you can further use it for your projects.

Comments

SirRuddy
SirRuddy - Monday, September 23, 2013 at 09:50

Dear Sebastiaan,

thank you for this nice script. It works perfectly for me, but could you give me a clue how to render the (e.g.) company-field of an address into the header-title? In your case, the page title of the list-view will be used on the detail-page as well. - And that causes an (SEO) error, because you got redundant page-titels in list- and in the single-view.

I'm Looking forward to your answer!

Kind regardsSirRuddy

gh
gh - Tuesday, November 5, 2013 at 17:09

Hi Seb,thanks for the snippet, i need the tt_address_group in the fe related to tt_address. i tried like,Grouplist = CONTENTGrouplist {

   table = tt_address_group
   select {
     selectFields = title
     # pidInList = 46
    join = tt_address_group_mm ON ( tt_address_group.uid = tt_address_group_mm.uid_foreign )
    where = tt_address_group.deleted=0 AND tt_address_group.hidden=0 AND tt_address_group_mm.uid_local = 46
    }
     renderObj = TEXT
     renderObj {
         field = title
         wrap = |
       }

}

But i can not get the tt_address_group.title. Do you have some hint?

Thanks.Gernot