This page is part of a static HTML representation of the TiddlyWiki at https://tiddlywiki.com/dev/

Widget refresh tutorial part II

17th February 2019 at 1:43am

This example is like Widget refresh tutorial part I except the widget output will be automatically refreshed when the tiddler field changes.

tiddlerfield.js is the same as tiddlerfield-norefresh.js, except this refresh method is added:

/*
A widget with optimized performance will selectively refresh, but here we refresh always
*/
MyWidget.prototype.refresh = function(changedTiddlers) {
	// Regenerate and rerender the widget and
	// replace the existing DOM node
	this.refreshSelf();
	return true;
};

The refreshSelf method called above is implemented by the core widget class and it takes care of cleaning the old dom node and calling the render function.

Here is the result (Widget refresh demo II):

[ { "title": "$:/DefaultTiddlers", "text": "[[tiddler field widget]]" } ] [ { "title": "test", "text": "type new text here" } ] [ { "title": "tiddlerfield.js", "text": "/*\\\n\nHello, World widget\n\n\\*/\n(function() {\n\n/*jslint node: true, browser: true */\n/*global $tw: false */\n\"use strict\";\n\nvar Widget = require(\"$:/core/modules/widgets/widget.js\").widget;\n\nvar MyWidget = function(parseTreeNode, options) {\n\tthis.initialise(parseTreeNode, options);\n};\n\n/*\nInherit from the base widget class\n*/\nMyWidget.prototype = new Widget();\n\n/*\nRender this widget into the DOM\n*/\nMyWidget.prototype.render = function(parent, nextSibling) {\n\tthis.parentDomNode = parent;\n\tvar text = this.wiki.getTiddlerText(\"test\", \"<empty>\")\n\tvar textNode = this.document.createTextNode(text);\n\tparent.insertBefore(textNode, nextSibling);\n\tthis.domNodes.push(textNode);\n};\n\n/*\nA widget with optimized performance will selectively refresh, but here we refresh always\n*/\nMyWidget.prototype.refresh = function(changedTiddlers) {\n\t// Regenerate and rerender the widget and\n\t// replace the existing DOM node\n\tthis.refreshSelf();\n\treturn true;\n};\n\nexports.tiddlerfield = MyWidget;\n\n})();\n", "created": "20190202032530728", "modified": "20190202032700995", "module-type": "widget", "tags": "", "type": "application/javascript" } ] [ { "title": "tiddler field widget", "text": "\n<$edit-text focus=yes tiddler=test tag=input/>\n \n<div>\n<div style=\"display:inline-block;width: 49%;vertical-align: text-top;word-wrap: break-word;}\">\n\n```\n<$tiddlerfield/>\n```\n\nRenders as:\n\n<$tiddlerfield/>\n</div>\n<div style=\"display:inline-block;width: 49%;vertical-align: text-top;word-wrap: break-word;}\">\n\n```\n<$view tiddler=\"test\"/>\n```\n\nRenders as:\n\n<$view tiddler=\"test\"/>\n</div>\n" } ]

And now any typing into the input box will cause both the tiddlerfield and the view widget output to refresh immediately.

Note this is a naive version of refresh. It unconditionally refreshes itself. This is far from optimal since the refresh method for all visible widgets is called every time the tiddler store changes. But the way we've defined our widget, the output ONLY depends on the tiddler titled text.

In tiddlywiki the tiddler store is used for everything and almost any interaction will result in an update to the store. This means almost any interaction will cause the refresh method to be called. If you type into the search box, for example, the tiddlerfield widget will be refreshed with every keystroke.

Adding and removing dom elements is a relatively expensive operation, so if someone has used the list widget to create a few hundred instances of this widget, then such tiddlywiki interactions might gain a noticable lag. Therefore, it usually makes sense to avoid modifying the dom when possible by writing a smarter refresh method.

Exercise - change the refresh method above to only call refreshSelf when the changedTiddlers input array contains test as one of its entries (Hint: see the refresh method in $:/core/modules/widgets/view.js for an example).