riot-typescript v1.0.10
RiotTS
Use Muut's Riot.js minimalistic framework from TypeScript.
Table of contents
- Installation
- How to write elements
- Writing a basic element
- The @template decorator
- Lifecycle events shortcuts
- How to create elements programmatically
- Observables
- Router
- Examples
- Precompiled tags
- Contributing
- Changelog
Installation
Install via npm:
npm install --save riot-typescriptUse as a <script> (global namespace)
In your main .html file add in the header section:
<head>
   <!-- loads riot and riot-ts -->
   <script type="text/javascript" src="node_modules/riot/riot+compiler.js"></script>
   <script type="text/javascript" src="node_modules/riot-typescript/riot-ts.globals.js"></script>
</head>   Somewhere in your TypeScript files add the references:
/// <reference types="riot-typescript" />
/// <reference path="node_modules/riot-typescript/riot.global.d.ts" />- RiotTS can be referenced with the global name Riot
- riot can be referenced with the global name riot
Use as a module
In your TypeScript files:
import * as Riot from "riot-typescript";When mounting you will also need to reference to riot (for riot.mount):
Put a declaration somewhere:
declare module "riot/riot+compiler";and then import riot:
import * as riot from "riot/riot+compiler";
...
riot.mount("*");How to write elements
Differently from pure Riot.js, in RiotTS elements are written 
as TypeScript classes extending the base type Riot.Element. 
There are no external .tag files, HTML templates are defined as pure strings or are loaded from .html files.
In brief:
- Write elements as TypeScript classes
- Extend the Riot.Elementclass
- Use @Riot.templateto define the template string or load it from URL
- create instances of the element programmatically with className.createElement().
A class-element:
- can have private properties/fields
- can have getter/setter properties
- can use inherited properties and methods
- can use TypeScript Mixins
- optionsare passed to the class constructor
Writing a basic element
In your element TypeScript code (e.g. elements/my-element.ts):
@Riot.template("my-element.html")
class MyElement extends Riot.Element
{
   // ...
}In elements/my-element.html:
<my-element>
   <div>
      This is a my custom element
   </div>
</my-element>In your main application file:
riot.mount('*');The @template decorator
@Riot.template(param)Sets the template for the element. The template parameter can be either:
- a literal string e.g. "<my-hello><div>hello</div></my-hello>"
- an external file (usually a .html) to be loaded via HTTP.
- a tag name (works on with precompiled tags).
Example of an element <my-hello>:
@Riot.template("<my-hello><div>hello</div></my-hello>")
class MyHello extends Riot.Element
{
}or
@Riot.template("elements/my-hello.html")
class MyHello extends Riot.Element
{
}<my-hello>
   <div>hello</div>
</my-hello>External tag files are loaded via HTTP requests, which can slow down the startup of very large applications. To avoid this, tags can be precompiled and concatenated into a single javascript file to be loaded more quickly. See how to setup a grunt task that does this.
Precompiled files can also be set to index tags by their tag names rather than their path, making it possible to use a shorter syntax:
@Riot.template("my-hello")
// instead of @template("elements/my-hello.html")Lifecycle events shortcuts
Lifecycle events can be listened via this.on() or by defining the following methods in the class:
- mounted()for the- mountevent
- unmounted()for the- unmountevent
- updating()for the- updateevent
- updated()for the- updatedevent
Note: names ending in "-ed" have been choosen to not clash with already methods on the Riot.Element interface.
Example:
@Riot.template("<myel><span></span></myel>")
class MyEl extends Riot.Element {
   constructor(opts) {      
      super();
      
      // first way to listen to unmount event
      this.on("unmount",()=>
      {         
      });
   }
      
   // alternated shorter way 
   unmounted()   
   {               
   }
}How to create elements programmatically
To create an element to be attached to the DOM use the creaeElement(opts) method:
var root = querySelector('#put_here');
el = test1.createElement();                
root.appendChild(el);         The created element is an instance of HTMLElement. To access the related riot-element:
var riotel = (el as any)._tag;  // ._tag is undocumentedObservables
The Riot library lets you define Observable objects that are not UI elements:
class MyObservable extends Riot.Observable 
{
   doSomething()
   {
      this.trigger("something-done");
   }
}
var a = new MyObservable();
a.on("something-done", ()=> {
   console.log("something has been done on 'a'!");
});Router
The Riot library comes also with a minimalistic router, the API is the same also in TypeScript.
Example:
// install router hash changed function
riot.route((id,username) =>
{
   console.log(`hash changed to: id=${id} username=${username}`);
});
// start the router
riot.route.start();
// route to an address
riot.route("welcome/nino.porcino");
// stop the router
riot.route.stop();Examples
A timer-based counter element
@Riot.template(`
<timer>
   <div>
      timer: { time }<br>
      trasclusion is '<yield/>'<br>                 
      <div each="{el in mylist}">iterating over array item "{el}"<br></div>
   </div>
</timer>`)
class Timer extends Riot.Element {
   time: number;
   timerHandle: number;  
   mylist = ["one","two","three"];
   
   // initializes the element with opts
   constructor(opts) {      
      super();
      this.time=opts.time||0;
      this.timerHandle=setInterval(() => this.ticks(),1000);      
   }
      
   ticks() {
      this.time++;
      this.update();  // refreshes the element
   }
   // handles the unmount event 
   unmounted()   
   {         
      clearInterval(this.timerHandle);
   }
}Then install the element and mount on the page with:
riot.mount('*');   // mounts all elementsPrecompiled tags
To speed up application startup times, tags can be precompiled in order to avoid compiling them at runtime.
Precompiled tags can be also concatenated into a single JavaScript file, avoiding to raise an HTTP request for each tag.
RiotTS can be switched to use precompiled files very easily by 
just including them (via <script src="..."></script>).
If the precompiled file is included, RiotTS will just use it, otherwise it will load tags via HTTP and compile them at runtime.
Precompiled files are normally intended for production, during the development they are usually turned off for a faster REPL cycle.
Precompiled files are generated with the grunt task grunt-riotts-precompile.
How to setup the task:
- First install grunt-cli,gruntandgrunt-riotts-precompile:
$ npm install -g grunt-cli
$ npm install grunt --save-dev
$ npm install grunt-riotts-precompile --save-dev- Use a Gruntfiles.jslike this:
module.exports = function(grunt) {      
   grunt.initConfig({
      precompileTags: {
         src: ['tags/**/*.html'],
         dest: 'precompiled-tags.js',
         indexByTagName: false
      }
   });
   
   grunt.loadNpmTasks('grunt-riotts-precompile');
   
   grunt.registerTask('default', ['precompileTags']);  
   grunt.registerTask('off', ['precompileTags:off']);
};How to run the task according to the above Gruntfiles.js:
- from the command line, use gruntto create the precompiled file (precompiled-tags.js)
- use - grunt offto turn off precompilation (will empty- precompiled-tags.js)
The generate precompiled-tags.js file can be inlined with a <script> tag 
just before loading the element's code, e.g.:
   <script type="text/javascript" src="precompiled-tags.js"></script>
   <script type="text/javascript" src="elements/mytag.js"></script>Precompiled tags can be easily turned off by just commenting the inclusion:
   <!-- <script type="text/javascript" src="precompiled-tags.js"></script> -->
   <script type="text/javascript" src="elements/mytag.js"></script>or by just emptying the file precompiled-tags.js.
The indexByTagName option:
If indexByTagName is set to true compiled tags will be indexed by tagname rather than file path. So it will 
be possible to define them in RiotTS with just
@template("mytag")instead of:
@template("mytagdirectory/mytag.html")Note: Tags defined by tag name rather than path cannot work if precompiled tags are turned off.
Contributing
Contributions are welcome.
If you find bugs or want to improve it, just send a pull request.
Change log
- v1.0.7- BREAKING CHANGE: ship as npmpackage (boweris no longer supported). The way files are loaded is changed please check again the docs.@templateis now available as@Riot.template.
 
- BREAKING CHANGE: ship as 
- v0.0.22- removed the need for registration, .registerand.registerAllare now removed from the API
 
- removed the need for registration, 
- v0.0.21- aligned router API to riot v2.3.11
 
- v0.0.19- support for precompiled tags
- deprecated support for "template-cache" in favor of precompiled tags
 
- v0.0.18- aligned with Riot's v2.3.11 API
- for old Riot v2.2, use RiotTS v0.0.17
 
- v0.0.17- support for template-cache
 
- v0.0.16- added Riot.registerAll()
 
- added 
- v0.0.15- support for riot builtin mixins
 
- v0.0.11- support for property getter/setter
 
- v0.0.8- new @template syntax, @component syntax obsolete
 
- v0.0.6- deprecated loading templates from named tags
 
- v0.0.5- addded method createElement()
 
- addded method 
- v0.0.0 to v0.0.4- early experimental versions