Understanding viewlets

Author:Unknown

Viewlets is a flexible way to compound html
snippets. Learn what they are and how they work.

Introduction

A viewlet is a component that represents an HTML snippet. It has basically the same purpose as a macro, but is more clean, powerful and flexible. Viewlets in Grok are synonymous to viewlets in Zope 3. It’s only how to create and register them that is different, but they work exactly the same way.

Viewlets are typically used for the layout of the web site. Often all the pages of the site has the same layout with header, one or two columns, the main content area and a footer.

Viewlets are grouped by adding them to viewlet managers. Viewlets can have a certain order within a group. The viewlet manager has a name and that is what you refer to in a page template when you want to use viewlets. When you ask the viewlet manager to be rendered or inserted into your page template, what will happen is that update() of each viewlet is called. After that render() of each viewlet will be called and the return values of each render() is added to the output. You can provide your own render() method if you want or you can provide a template and that will be called.

Example

This is an example of how you can use viewlets. Two viewlets (Fred and Wilma) are ordered in a viewlet manager. To try this out, create a new project with “grokproject viewlettest” and add these three files:

#
# app.py
#
import grok

class Counter(grok.Model):
    def __init__(self):
        self.count = 0

class GrokExample(grok.Application, grok.Container):
    def __init__(self):
        grok.Application.__init__(self)
        grok.Container.__init__(self)
        self.fred = Counter()
        self.wilma = Counter()

class Index(grok.View):
    grok.context(GrokExample)

class CountersManager(grok.ViewletManager):
    grok.name('counters')
    grok.context(GrokExample)

class Fred(grok.Viewlet):
    grok.viewletmanager(CountersManager)
    grok.context(GrokExample)
    grok.template('fred_template')
    grok.order(2)

    def update(self):
        self.context.fred.count += 1
        self.counter = self.context.fred.count

class Wilma(grok.Viewlet):
    grok.viewletmanager(CountersManager)
    grok.context(GrokExample)
    grok.order(1)

    def update(self):
        self.context.wilma.count += 1

    def render(self):
        return """<div style='float: left; width:200px; height:200px'>
                  <h1>Wilma</h1>
                  <div style='font-size:200%%'>%d</div>
                  </div>""" % self.context.wilma.count

Page templates:

#
# app_templates/fred_template.pt
#
<div style="float: left; width:200px; height:200px">
    <h1>Fred</h1>
    <div style="font-size: 200%;" tal:content="view/counter" />
</div>

#
# app_templates/index.pt
#
<html>
    <body>
        <h1>Grok viewlets</h1>
        <div style="width: 400px" tal:content="structure provider:counters" />
    </body>
</html>

What happens when you visit http://localhost:8080/exampleapp/

  • The ‘index’ view of the application is automatically used when nothing is specified and it will render the index.pt template.
  • The index.pt template says it wants to insert whatever is returned by the viewlet manager called ‘counters’.
  • ‘counters’ is a group of two viewlets and the Wilma viewlet has lower order than Fred so the ‘counters’ viewlet manager process Wilma first.
  • The viewlet manager will call update() on the Wilma viewlet first and update Wilma’s counter. The manager will then call update() on the Fred viewlet which will cause an increment of Fred’s counter.