Personal tools
You are here: Home Documentation How-Tos Understanding viewlets

Understanding viewlets

This How-to applies to: Any version.
This How-to is intended for: Any audience.

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

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/

  1. The 'index' view of the application is automatically used when nothing is specified and it will render the index.pt template.
  2. The index.pt template says it wants to insert whatever is returned by the viewlet manager called 'counters'.
  3. 'counters' is a group of two viewlets and the Wilma viewlet has lower order than Fred so the 'counters' viewlet manager process Wilma first.
  4. 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.

Typo in fred_template.pt

Posted by http://george.wright.myopenid.com/ at Dec 16, 2008 03:09 PM

Gidday I couldn't get this demo to work until I changed the word view in fred_template.pt to viewlet

Fred

It was a guess and it worked! George

Re: Typo in fred_template

Posted by http://george.wright.myopenid.com/ at Dec 17, 2008 12:56 AM

I pasted in the html code and it got interpreted so my message was hard to read. Change this: tal:content="view/counter" to this: tal:content="viewlet/counter"

George