controllerindepth.html   [plain text]


<?xml version="1.0"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><title>Twisted Documentation: Controllers in Depth</title><link href="../howto/stylesheet.css" type="text/css" rel="stylesheet" /></head><body bgcolor="white"><h1 class="title">Controllers in Depth</h1><div class="toc"><ol><li><a href="#auto0">Main Concepts</a></li><li><a href="#auto1">Controller factories</a></li><li><a href="#auto2">Handle</a></li><li><a href="#auto3">InputHandlers</a></li><li><a href="#auto4">Event handlers</a></li></ol></div><div class="content"><div class="note"><strong>Note: </strong><p>
This HOWTO documents the Controller objects, part of the Woven framework. The Woven framework should not be used for new projects. The newer <a href="http://www.divmod.org/Home/Projects/Nevow/">Nevow</a> framework, available as part of the <a href="http://www.divmod.org/Quotient/">Quotient</a> project, is a simpler framework with consistent semantics and better testing and is strongly recommended over Woven.
</p><p>
The Woven documentation below is maintained only for users with an existing Woven codebase.
</p></div><span></span><img src="../img/controller.png" alt="Controller" title="Controller in Relation to View and Model" /><p>Controller objects are a way to generalize and reuse input handling logic. In
Twisted Web, form input is passed to a Resource instance in request.args. You
can create controller classes to encapsulate generic request.args handling, and
perform validation and Model updating tasks.</p><h2>Main Concepts<a name="auto0"></a></h2><ul><li><a href="#controllerfactories">Controller factories</a> provide the glue
  from a DOM node with a 'controller=' directive to an instance of a Controller
  class.</li><li><a href="#handle">handle</a> is the method which is called on the
  Controller instance to handle a node.</li><li><a href="#inputhandlers">InputHandlers</a> are Controllers which have
  (somewhat) convenient syntax for handling a node.</li><li><a href="#eventhandlers">Event handlers</a>, when used with <a href="livepage.html">LivePage</a>, are a brain-exploding way of handling
  JavaScript events in your pages with server-side Python code.</li></ul><h2>Controller factories<a name="auto1"></a></h2><a name="controllerfactories"></a><p>Controller factories provide the glue between a <code>controller=</code>
directive on a DOM node and a Controller instance. When a DOM node with a
<code>controller=</code> directive is encountered, Woven looks for a
corresponding <code>wcfactory_</code> method on your Page instance. A Controller
factory is required to return an object which implements the interface <code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.web.woven.interfaces.IController.html" title="twisted.web.woven.interfaces.IController">IController</a></code>.</p><pre class="python">
<span class="py-src-keyword">class</span> <span class="py-src-identifier">MyController</span><span class="py-src-op">(</span><span class="py-src-parameter">controller</span><span class="py-src-op">.</span><span class="py-src-parameter">Controller</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-keyword">pass</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span>    <span class="py-src-dedent"></span><span class="py-src-keyword">class</span> <span class="py-src-identifier">MyPage</span><span class="py-src-op">(</span><span class="py-src-parameter">page</span><span class="py-src-op">.</span><span class="py-src-parameter">Page</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">      </span><span class="py-src-keyword">def</span> <span class="py-src-identifier">wcfactory_foo</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">,</span> <span class="py-src-parameter">request</span><span class="py-src-op">,</span> <span class="py-src-parameter">node</span><span class="py-src-op">,</span> <span class="py-src-parameter">model</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-keyword">return</span> <span class="py-src-variable">MyController</span><span class="py-src-op">(</span><span class="py-src-variable">model</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-dedent"></span><span class="py-src-dedent"></span><span class="py-src-endmarker"></span></pre><h2>Handle<a name="auto2"></a></h2><a name="handle"></a><p>Handle is the API your controller must implement to handle a node. It's
return value may be a Deferred if you wish to pause the rendering of the View
until some data is ready, or it may be None</p><pre class="python">
<span class="py-src-keyword">class</span> <span class="py-src-identifier">MyController</span><span class="py-src-op">(</span><span class="py-src-parameter">controller</span><span class="py-src-op">.</span><span class="py-src-parameter">Controller</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">      </span><span class="py-src-keyword">def</span> <span class="py-src-identifier">handle</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">,</span> <span class="py-src-parameter">request</span><span class="py-src-op">,</span> <span class="py-src-parameter">node</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-variable">name</span> <span class="py-src-op">=</span> <span class="py-src-variable">request</span><span class="py-src-op">.</span><span class="py-src-variable">args</span><span class="py-src-op">.</span><span class="py-src-variable">get</span><span class="py-src-op">(</span><span class="py-src-string">&quot;name&quot;</span><span class="py-src-op">,</span> <span class="py-src-op">[</span><span class="py-src-variable">None</span><span class="py-src-op">]</span><span class="py-src-op">)</span><span class="py-src-op">[</span><span class="py-src-number">0</span><span class="py-src-op">]</span><span class="py-src-newline">
</span>        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;HOORJ! YOUR NAME IS %s&quot;</span> <span class="py-src-op">%</span> <span class="py-src-variable">name</span><span class="py-src-newline">
</span><span class="py-src-dedent"></span><span class="py-src-dedent"></span><span class="py-src-endmarker"></span></pre><h2>InputHandlers<a name="auto3"></a></h2><a name="inputhandlers"></a><p>InputHandlers are defined in <code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.web.woven.input.html" title="twisted.web.woven.input">woven.input</a></code>.  They were an early attempt to create a
class which made it easy to create new input validators and input committers. It
is usable in its current state, although the API is a bit baroque. Subclasses of
<code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.web.woven.input.InputHandler.html" title="twisted.web.woven.input.InputHandler">input.InputHandler</a></code> can
override the following methods to decide what to do with data</p><dl><dt><code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.web.woven.input.InputHandler.initialize().html" title="twisted.web.woven.input.InputHandler.initialize()">initialize()</a></code></dt><dd>initialize this Controller. This is most useful for registering event
  handlers on the View with <a href="#eventhandlers">addEventHandler</a>,
  discussed below.</dd><dt><code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.web.woven.input.InputHandler.getInput.html" title="twisted.web.woven.input.InputHandler.getInput">getInput</a></code><code>(self,
  request)</code></dt><dd>get input from the request and return it. Return None to indicate no data
  was available for this InputHandler to handle.</dd><dt><code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.web.woven.input.InputHandler.check.html" title="twisted.web.woven.input.InputHandler.check">check</a></code><code>(self,
  request, data)</code></dt><dd>Check the input returned from getInput and return:
    <ul><li>None if no data was submitted (data was None), or</li><li>True if the data that was submitted was valid, or</li><li>False if the data that was submitted was not valid.</li></ul></dd><dt><code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.web.woven.input.InputHandler.handleValid.html" title="twisted.web.woven.input.InputHandler.handleValid">handleValid</a></code><code>(self,
  request, data)</code></dt><dd>handle the valid submission of some data. By default this calls
  <code>self.parent.aggregateValid</code>.</dd><dt><code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.web.woven.input.InputHandler.aggregateValid.html" title="twisted.web.woven.input.InputHandler.aggregateValid">aggregateValid</a></code><code>(self,
  request, inputhandler, data)</code></dt><dd>Some input was validated by a child Controller. This is generally
  implemented on a controller which is placed on a <code>&lt;form&gt;</code> to gather input
  from controllers placed on <code>&lt;input&gt;</code> nodes.</dd><dt><code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.web.woven.input.InputHandler.handleInvalid.html" title="twisted.web.woven.input.InputHandler.handleInvalid">handleInvalid</a></code><code>(self,
  request, data)</code></dt><dd>handle the invalid submission of some data. By default this calls
  <code>self.parent.aggregateInvalid</code>.</dd><dt><code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.web.woven.input.InputHandler.aggregateInvalid.html" title="twisted.web.woven.input.InputHandler.aggregateInvalid">aggregateInvalid</a></code><code>(self,
  request, inputhandler, data)</code></dt><dd>Some input was declared invalid by a child Controller. This is generally
  implemented on a controller which is placed on a <code>&lt;form&gt;</code> to gather input
  from controllers placed on <code>&lt;input&gt;</code> nodes.</dd><dt><code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.web.woven.input.InputHandler.commit.html" title="twisted.web.woven.input.InputHandler.commit">commit</a></code><code>(self,
  request, node, data)</code></dt><dd>Enough valid input was gathered to allow us to change the Model.</dd></dl><p>InputHandlers have been parameterized enough so you may simply use a generic
InputHandler rather than subclassing and overriding:</p><pre class="python">
<span class="py-src-keyword">class</span> <span class="py-src-identifier">MyPage</span><span class="py-src-op">(</span><span class="py-src-parameter">page</span><span class="py-src-op">.</span><span class="py-src-parameter">Page</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">    </span><span class="py-src-keyword">def</span> <span class="py-src-identifier">checkName</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">,</span> <span class="py-src-parameter">request</span><span class="py-src-op">,</span> <span class="py-src-parameter">name</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">      </span><span class="py-src-keyword">if</span> <span class="py-src-variable">name</span> <span class="py-src-keyword">is</span> <span class="py-src-variable">None</span><span class="py-src-op">:</span> <span class="py-src-keyword">return</span> <span class="py-src-variable">None</span><span class="py-src-newline">
</span>      <span class="py-src-comment"># No fred allowed
</span>      <span class="py-src-keyword">if</span> <span class="py-src-variable">name</span> <span class="py-src-op">==</span> <span class="py-src-string">'fred'</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-keyword">return</span> <span class="py-src-variable">False</span><span class="py-src-newline">
</span>      <span class="py-src-dedent"></span><span class="py-src-keyword">return</span> <span class="py-src-variable">True</span><span class="py-src-newline">
</span>    <span class="py-src-nl">
</span>    <span class="py-src-dedent"></span><span class="py-src-keyword">def</span> <span class="py-src-identifier">commitName</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">,</span> <span class="py-src-parameter">request</span><span class="py-src-op">,</span> <span class="py-src-parameter">name</span><span class="py-src-op">=</span><span class="py-src-string">&quot;&quot;</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">      </span><span class="py-src-variable">ctx</span> <span class="py-src-op">=</span> <span class="py-src-variable">getContext</span><span class="py-src-op">(</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>      <span class="py-src-variable">ctx</span><span class="py-src-op">.</span><span class="py-src-variable">execute</span><span class="py-src-op">(</span><span class="py-src-string">&quot;insert into people (name) values %s&quot;</span><span class="py-src-op">,</span> <span class="py-src-variable">name</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span>    <span class="py-src-dedent"></span><span class="py-src-keyword">def</span> <span class="py-src-identifier">wcfactory_addPerson</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">,</span> <span class="py-src-parameter">request</span><span class="py-src-op">,</span> <span class="py-src-parameter">node</span><span class="py-src-op">,</span> <span class="py-src-parameter">model</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-keyword">return</span> <span class="py-src-variable">input</span><span class="py-src-op">.</span><span class="py-src-variable">InputHandler</span><span class="py-src-op">(</span><span class="py-src-nl">
</span>            <span class="py-src-variable">model</span><span class="py-src-op">,</span> <span class="py-src-nl">
</span>            <span class="py-src-variable">name</span><span class="py-src-op">=</span><span class="py-src-string">&quot;name&quot;</span><span class="py-src-op">,</span> <span class="py-src-comment"># The name of the argument in the request to check</span><span class="py-src-nl">
</span>            <span class="py-src-variable">check</span><span class="py-src-op">=</span><span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">checkName</span><span class="py-src-op">,</span> <span class="py-src-nl">
</span>            <span class="py-src-variable">commit</span><span class="py-src-op">=</span><span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">commitName</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-dedent"></span><span class="py-src-dedent"></span><span class="py-src-endmarker"></span></pre><h2>Event handlers<a name="auto4"></a></h2><a name="eventhandlers"></a><div class="note"><strong>Note: </strong><p>In order for Event Handlers to work, you must be using <a href="livepage.html">LivePage</a>, and include the webConduitGlue View in your HTML
template.</p></div><p>Event handlers give you the powerful ability to respond to in-browser
JavaScript event handlers with server-side Python code. Event handlers are
registered on the View instance; in some cases, it may make most sense for your
View instances to implement their own event handlers. However, in order to
support good separation of concerns and code reuse, you may want to consider
implementing your event handlers on a Controller instance.</p><p>The easiest way to achieve this is to subclass <code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.web.woven.input.Anything.html" title="twisted.web.woven.input.Anything">input.Anything</a></code> (XXX: this
should just be controller.Controller) and override <code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.web.woven.input.Anything.initialize.html" title="twisted.web.woven.input.Anything.initialize">initialize</a></code> (XXX: this should
be setUp):</p><pre class="python">
<span class="py-src-keyword">class</span> <span class="py-src-identifier">MyEventHandler</span><span class="py-src-op">(</span><span class="py-src-parameter">input</span><span class="py-src-op">.</span><span class="py-src-parameter">Anything</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">    </span><span class="py-src-keyword">def</span> <span class="py-src-identifier">initialize</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">view</span><span class="py-src-op">.</span><span class="py-src-variable">addEventHandler</span><span class="py-src-op">(</span><span class="py-src-string">&quot;onclick&quot;</span><span class="py-src-op">,</span> <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">onClick</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>        <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">view</span><span class="py-src-op">.</span><span class="py-src-variable">addEventHandler</span><span class="py-src-op">(</span><span class="py-src-string">&quot;onmouseover&quot;</span><span class="py-src-op">,</span> <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">onMouseOver</span><span class="py-src-op">,</span> <span class="py-src-string">&quot;'HELLO'&quot;</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>    <span class="py-src-nl">
</span>    <span class="py-src-dedent"></span><span class="py-src-keyword">def</span> <span class="py-src-identifier">onClick</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">,</span> <span class="py-src-parameter">request</span><span class="py-src-op">,</span> <span class="py-src-parameter">widget</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-keyword">print</span> <span class="py-src-variable">self</span><span class="py-src-op">,</span> <span class="py-src-string">&quot;CLICKED!!!&quot;</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span>    <span class="py-src-dedent"></span><span class="py-src-keyword">def</span> <span class="py-src-identifier">onMouseOver</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">,</span> <span class="py-src-parameter">request</span><span class="py-src-op">,</span> <span class="py-src-parameter">widget</span><span class="py-src-op">,</span> <span class="py-src-parameter">argument</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-keyword">print</span> <span class="py-src-variable">self</span><span class="py-src-op">,</span> <span class="py-src-string">&quot;MOUSE OVER!!!&quot;</span><span class="py-src-op">,</span> <span class="py-src-variable">argument</span><span class="py-src-newline">
</span><span class="py-src-dedent"></span><span class="py-src-dedent"></span><span class="py-src-endmarker"></span></pre><p>Note that the first argument to addEventHandler is the JavaScript event name,
and the second argument is the python function or method which will handle this
event. You may also pass any additional arguments you desire. These arguments
must be valid JavaScript, and will be evaluated in the browser context. The
results of these JavaScript expressions will be passed to your Python event
handler.</p><p>Note that when we passed an extra argument when adding an
<code>onmouseover</code> event handler, we passed a string enclosed in two sets
of quotes. This is because the result of evaluating <code>&quot;'HELLO'&quot;</code> as
JavaScript in the browser is the string <code>'HELLO'</code>, which is then
passed to the Python event handler. If we had simply passed <code>&quot;HELLO&quot;</code>
to addEventHandler, Woven would have evaluated <code>&quot;HELLO&quot;</code> in the
browser context, resulting in an error because the variable <code>HELLO</code>
is not defined.</p><p>Any normal client-side JavaScript object may be accessed, such as
<code>document</code> and <code>window</code>. Also, the JavaScript variable
<code>node</code> is defined as the DOM node on which the event handler is
operating. This is useful for examining the current value of an
<code>&lt;input&gt;</code> node.</p><p>Here are some examples of useful Event handlers:</p><pre class="python">
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Redirect</span><span class="py-src-op">(</span><span class="py-src-parameter">input</span><span class="py-src-op">.</span><span class="py-src-parameter">Anything</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">    </span><span class="py-src-keyword">def</span> <span class="py-src-identifier">initialize</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">view</span><span class="py-src-op">.</span><span class="py-src-variable">addEventHandler</span><span class="py-src-op">(</span><span class="py-src-nl">
</span>            <span class="py-src-string">&quot;onclick&quot;</span><span class="py-src-op">,</span> <span class="py-src-nl">
</span>            <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">onClick</span><span class="py-src-op">,</span> <span class="py-src-nl">
</span>            <span class="py-src-string">&quot;window.location = 'http://www.google.com'&quot;</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span>    <span class="py-src-dedent"></span><span class="py-src-keyword">def</span> <span class="py-src-identifier">onClick</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">,</span> <span class="py-src-parameter">request</span><span class="py-src-op">,</span> <span class="py-src-parameter">widget</span><span class="py-src-op">,</span> <span class="py-src-parameter">arg</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-keyword">print</span> <span class="py-src-string">&quot;The window was redirected.&quot;</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span>  <span class="py-src-dedent"></span><span class="py-src-dedent"></span><span class="py-src-keyword">class</span> <span class="py-src-identifier">OnChanger</span><span class="py-src-op">(</span><span class="py-src-parameter">input</span><span class="py-src-op">.</span><span class="py-src-parameter">Anything</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">    </span><span class="py-src-keyword">def</span> <span class="py-src-identifier">initialize</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">view</span><span class="py-src-op">.</span><span class="py-src-variable">addEventHandler</span><span class="py-src-op">(</span><span class="py-src-nl">
</span>            <span class="py-src-string">&quot;onchange&quot;</span><span class="py-src-op">,</span><span class="py-src-nl">
</span>            <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">changed</span><span class="py-src-op">,</span><span class="py-src-nl">
</span>            <span class="py-src-string">&quot;node.value&quot;</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>    <span class="py-src-nl">
</span>    <span class="py-src-dedent"></span><span class="py-src-keyword">def</span> <span class="py-src-identifier">changed</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">,</span> <span class="py-src-parameter">request</span><span class="py-src-op">,</span> <span class="py-src-parameter">widget</span><span class="py-src-op">,</span> <span class="py-src-parameter">newValue</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-keyword">print</span> <span class="py-src-string">&quot;The input box changed to&quot;</span><span class="py-src-op">,</span> <span class="py-src-variable">newValue</span><span class="py-src-newline">
</span><span class="py-src-dedent"></span><span class="py-src-dedent"></span><span class="py-src-endmarker"></span></pre></div><p><a href="../howto/index.html">Index</a></p><span class="version">Version: 1.3.0</span></body></html>