fancy_syntax 0.0.7

  • Example
  • Installing
  • Versions
  • 14


Fancy Syntax is an MDV BindingDelegate that implements an expressive custom binding syntax for MDV (Model-driven Views) templates in Dart.

Fancy Syntax allows you to write complex binding expressions, with property access, function invocation, list/map indexing, and two-way filtering like {{ person.title + " " + person.getFullName() | upppercase }}.



MDV allows you to define templates directly in HTML that are rendered by the browser into the DOM. Templates are bound to a data model, and changes to the data are automatically reflected in the DOM, and changes in HTML inputs are assigned back into the model. The template and model are bound together via binding expressions that are evaluated against the model. These binding expressions are placed in double-curly-braces, or "mustaches".


  <p>Hello {{ }}</p>

MDV includes a very basic binding syntax which only allows a series of dot-separate property names.

Custom Binding Syntaxes with BindingDelegate

While MDV's built-in syntax is very basic, it does allow custom syntaxes called "binding delegates" to be installed and used. A binding delegate can interpret the contents of mustaches however it likes. Fancy Syntax is such a binding delegate.


<template syntax="fancy">
  <p>Hello {{ person.title + " " + person.getFullName() | uppercase }}</p>


Installing from Pub

Add the following to your pubspec.yaml file:

  fancy_syntax: 0.0.6

Hint: check for the latest version number.

Then import syntax.dart:

import 'package:fancy_syntax/syntax.dart';

Registering a Binding Delegate

Binding delegates must be installed on a template before they can be used. In your main() function, first initialize MDV, then set the bindingDelegate property of your template elements to an instance of FancySyntax. The templates will then use the FancySyntax instance to interpret binding expressions.

import 'dart:html';
import 'package:mdv/mdv.dart' as mdv;
import 'package:fancy_syntax:syntax.dart';

main() {
  var template = query('#my_template');
  template.bindingDelegate = new FancySyntax();

Registering Top-Level Variables

Before a top-level variable can be used, it must be registered. The FancySyntax constructor takes a map of named values to use as variables.

main() {
  var globals = {
    'uppercase': (String v) => v.toUpperCase(),
    'app_id': 'fancy_app_123',
  var template = query('#my_template');
  template.bindingDelegate = new FancySyntax(globals: globals);


The Model and Scope

Fancy Syntax allows binding to more than just the model assigned to a template instance. Top-level variables can be defined so that you can use filters, global variables and constants, functions, etc. These variables and the model are held together in a container called a Scope. Scopes can be nested, which happens when template tags are nested.

Two-way Bindings

Bindings can be used to modify the data model based on events in the DOM. The most common case is to bind an <input> element's value field to a model property and have the property update when the input changes. For this to work, the binding expression must be "assignable". Only a subset of expressions are assignable. Assignable expressions cannot contain function calls, operators, and any index operator must have a literal argument. Assignable expressions can contain filter operators as long as all the filters are two-way transformers.

Some restrictions may be relaxed further as allowed.

Assignable Expressions:

  • foo
  • items[0].description
  • people['john'].name
  • product.cost | convertCurrency('ZWD') where convertCurrency evaluates to a Tranformer object.

Non-Assignable Expressions:

  • a + 1
  • !c
  • foo()
  • person.lastName | uppercase where uppercase is a filter function.


Expressions are generally null-safe. If an intermediate expression yields null the entire expression will return null, rather than throwing an exception. Property access, method invocation and operators are null-safe. Passing null to a function that doesn't handle null will not be null safe.


Fancy Syntax has experimental support for binding to streams, and when new values are passed to the stream, the template updates. The feature is not fully implemented yet.

See the examples in /example/streams for more details.


Property Access

Properties on the model and in the scope are looked up via simple property names, like foo. Property names are looked up first in the top-level variables, next in the model, then recursively in parent scopes. Properties on objects can be access with dot notation like

The keyword this always refers to the model if there is one, otherwise this is null. If you have model properties and top-level variables with the same name, you can use this to refer to the model property.


Fancy Syntax supports number, boolean, string, and map literals. Strings can use either single or double quotes.

  • Numbers: 1, 1.0
  • Booleans: true, false
  • Strings: 'abc', "xyz"
  • Maps: { 'a': 1, 'b': 2 }

List literals are planned:

Functions and Methods

If a property is a function in the scope, a method on the model, or a method on an object, it can be invoked with standard function syntax. Functions and Methods can take arguments. Named arguments are not supported. Arguments can be literals or variables.


  • Top-level function: myFunction()
  • Top-level function with arguments: myFunction(a, b, 42)
  • Model method: aMethod()
  • Method on nested-property: a.b.anotherMethod()


Fancy Syntax supports the following binary and unary operators:

  • Arithmetic operators: +, -, *, /, %, unary + and -
  • Comparison operators: ==, !=, <=, <, >, >=
  • Boolean operators: &&, ||, unary !

Expressions do not support bitwise operators such as &, |, << and >>, or increment/decrement operators (++ and --)

List and Map Indexing

List and Map like objects can be accessed via the index operator: []


  • items[2]
  • people['john']

Unlike JavaScript, list and map contents are not generally available via property access. That is, the previous examples are not equivalent to items.2 and people.john. This ensures that access to properties and methods on Lists and Maps is preserved.

Filters and Transformers

A filter is a function that transforms a value into another, used via the pipe syntax: value | filter Any function that takes exactly one argument can be used as a filter.


If is "John", and a top-level function named uppercase has been registered, then | uppercase will have the value "JOHN".

The pipe syntax is used rather than a regular function call so that we can support two-way bindings through transformers. A transformer is a filter that has an inverse function. Transformers must extend or implement the Transformer class, which has forward() and reverse() methods.

Repeating Templates

A template can be repeated by using the "repeat" attribute with a binding. The binding can either evaluate to an Iterable, in which case the template is instantiated for each item in the iterable and the model of the instance is set to the item, or the binding can be a "in" iterator expression, in which case a new variable is added to each scope.

The following examples produce the same output.

Evaluate to an iterable:

<template repeat="{{ items }}">
  <div>{{ }}</div>

"in" expression:

<template repeat="{{ item in items }}">
  <div>{{ item }}</div>


The syntax implemented is experimental and subject to change, in fact, it will change soon. The goal is to be compatible with Polymer's binding syntax. We will announce breaking changes on the mailing list.

Please file issues on Github for any bugs you find or for feature requests.

You can discuss Fancy Syntax on the mailing list.


// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:html';

import 'package:fancy_syntax/syntax.dart';
import 'package:mdv/mdv.dart' as mdv;

import 'person.dart';

main() {
  var john = new Person('John', 'Messerly', ['A', 'B', 'C']);
  var justin = new Person('Justin', 'Fagnani', ['D', 'E', 'F']);
  var globals = {
    'uppercase': (String v) => v.toUpperCase(),
    'people': [john, justin],

      ..bindingDelegate = new FancySyntax(globals: globals)
      ..model = john;

  query('#test2').model = john;

1. Depend on it

Add this to your package's pubspec.yaml file:

  fancy_syntax: "^0.0.7"

2. Install it

You can install packages from the command line:

with pub:

$ pub get

Alternatively, your editor might support pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:

import 'package:fancy_syntax/async.dart';

import 'package:fancy_syntax/eval.dart';

import 'package:fancy_syntax/expression.dart';

import 'package:fancy_syntax/filter.dart';

import 'package:fancy_syntax/parser.dart';

import 'package:fancy_syntax/syntax.dart';

import 'package:fancy_syntax/tokenizer.dart';

import 'package:fancy_syntax/visitor.dart';
Version Uploaded Documentation Archive
0.0.7 Aug 6, 2013 Go to the documentation of fancy_syntax 0.0.7 Download fancy_syntax 0.0.7 archive
0.0.6 Aug 1, 2013 Go to the documentation of fancy_syntax 0.0.6 Download fancy_syntax 0.0.6 archive
0.0.5 Jul 25, 2013 Go to the documentation of fancy_syntax 0.0.5 Download fancy_syntax 0.0.5 archive
0.0.4 Jul 24, 2013 Go to the documentation of fancy_syntax 0.0.4 Download fancy_syntax 0.0.4 archive
0.0.3 Jul 19, 2013 Go to the documentation of fancy_syntax 0.0.3 Download fancy_syntax 0.0.3 archive
0.0.2 Jul 10, 2013 Go to the documentation of fancy_syntax 0.0.2 Download fancy_syntax 0.0.2 archive
0.0.1 Jun 20, 2013 Go to the documentation of fancy_syntax 0.0.1 Download fancy_syntax 0.0.1 archive
0.0.2-docs Jul 19, 2013 Go to the documentation of fancy_syntax 0.0.2-docs Download fancy_syntax 0.0.2-docs archive


This feature is new.
We welcome feedback.
More details: scoring.

We analyzed this package, and provided a score, details, and suggestions below.

  • tool failures on Jan 21, 2018
  • Dart: 2.0.0-dev.15.0
  • pana: 0.10.0


Describes how popular the package is relative to other packages. [more]
1 / 100
Code health derived from static analysis. [more]
46 / 100
Reflects how tidy and up-to-date the package is. [more]
0 / 100
Overall score:
Weighted score of the above. [more]


Detected platforms: unsure

Error(s) prevent platform classification.


  • Fix lib/src/mirrors.dart.

    Strong-mode analysis of lib/src/mirrors.dart failed with the following error:

    line: 17 col: 19
    The getter 'members' isn't defined for the class 'ClassMirror'.

  • Fix lib/visitor.dart.

    Strong-mode analysis of lib/visitor.dart failed with the following error:

    line: 24 col: 52
    'E' doesn't extend 'Expression'.

  • Fix further 3 Dart files.

    Similar analysis of the following files failed:

    • lib/eval.dart
    • lib/syntax.dart
    • lib/parser.dart
  • Fix platform conflicts.

    Make sure none of the libraries use mutually exclusive dependendencies.

  • Maintain

    Changelog entries help clients to follow the progress in your code.

  • Fix issues reported by dartanalyzer.

    dartanalyzer reported 3 error(s) and 0 warning(s).

  • Use constrained dependencies.

    The pubspec.yaml contains 3 dependencies without version constraints. Specify version ranges for the following dependencies: browser, mdv, observe.

  • The description is too short.

    Add more detail about the package, what it does and what is its target use case. Try to write at least 60 characters.

  • Package is pre-v1 release.

    While there is nothing inherently wrong with versions of 0.*.*, it usually means that the author is still experimenting with the general direction API.


Package Constraint Resolved Available
Direct dependencies
browser any 0.10.0+2
mdv any 0.8.5
observe any 0.15.1
Transitive dependencies
analyzer 0.29.11 0.30.0+4
args 0.13.7 1.2.0
async 2.0.3
barback 0.15.2+14
charcode 1.1.1
cli_util 0.0.1+2 0.1.2+1
code_transformers 0.5.1+3
collection 1.14.5
convert 2.0.1
crypto 2.0.2+1
csslib 0.14.1
func 1.0.0
glob 1.1.5
html 0.13.2+2
isolate 1.1.0
logging 0.11.3+1
matcher 0.12.1+4
meta 1.1.2
observable 0.20.4+3
package_config 1.0.3
path 1.5.1
plugin 0.2.0+2
pool 1.3.4
quiver 0.27.0 0.28.0
smoke 0.3.6+3
source_maps 0.10.4
source_span 1.4.0
stack_trace 1.9.1
string_scanner 1.0.2
typed_data 1.1.5
utf 0.9.0+3
watcher 0.9.7+6
when 0.2.0
which 0.1.3
yaml 2.1.13
Dev dependencies
unittest any