Git Product home page Git Product logo

incremental-dom's Introduction

CircleCI

Incremental DOM

Overview

Incremental DOM is a library for building up DOM trees and updating them in-place when data changes. It differs from the established virtual DOM approach in that no intermediate tree is created (the existing tree is mutated in-place). This approach significantly reduces memory allocation and GC thrashing for incremental updates to the DOM tree therefore increasing performance significantly in some cases.

Incremental DOM is primarily intended as a compilation target for templating languages. It could be used to implement a higher level API for human consumption. The API was carefully designed to minimize heap allocations and where unavoidable ensure that as many objects as possible can be de-allocated by incremental GC. One unique feature of its API is that it separates opening and closing of tags so that it is suitable as a compilation target for templating languages that allow (temporarily) unbalanced HTML in templates (e.g. tags that are opened and closed in separate templates) and arbitrary logic for creating HTML attributes. Think of it as ASM.dom.

Supported Browsers

Incremental DOM supports IE9 and above.

Usage

HTML is expressed in Incremental DOM using the elementOpen, elementClose, elementVoid and text methods. Consider the following example:

var IncrementalDOM = require('incremental-dom'),
    elementOpen = IncrementalDOM.elementOpen,
    elementClose = IncrementalDOM.elementClose,
    elementVoid = IncrementalDOM.elementVoid,
    text = IncrementalDOM.text;

function render(data) {
  elementVoid('input', '', [ 'type', 'text' ]);
  elementOpen('div', '', null);
    if (data.someCondition) {
      text(data.text);
    }
  elementClose('div');
}

To render or update an existing DOM node, the patch function is used:

var patch = require('incremental-dom').patch;

var data = {
  text: 'Hello World!',
  someCondition: true
};

patch(myElement, function() {
  render(data);
});

data.text = 'Hello World!';

patch(myElement, function() {
  render(data);
});

Templating Languages and Libraries

Check out what others having been doing with Incremental DOM.

Docs

Getting Incremental DOM

Via CDN

https://ajax.googleapis.com/ajax/libs/incrementaldom/0.5.1/incremental-dom.js https://ajax.googleapis.com/ajax/libs/incrementaldom/0.5.1/incremental-dom-min.js

Using npm

npm install incremental-dom

Development

To install the required development packages, run the following command:

npm i

Running tests

To run once:

./node_modules/.bin/bazelisk test ...

To run on change:

./node_modules/.bin/ibazel run //test:unit_tests

Building

To build once:

./node_modules/.bin/bazelisk build ...

To build on change:

./node_modules/.bin/ibazel build ...

incremental-dom's People

Contributors

alexeagle avatar appzuka avatar asmiller avatar cramforce avatar davidjamesstone avatar dependabot[bot] avatar dominator008 avatar emspishak avatar ferrugemjs avatar helloiampau avatar iteriani avatar jadertao avatar joyzhong avatar jridgewell avatar juancabrera avatar mairatma avatar markuskobler avatar mbrukman avatar paolocaminiti avatar prayagverma avatar priyatam avatar rich-harris avatar samccone avatar schlusslicht avatar slaks avatar sparhami avatar tailhook avatar tepark-goog avatar vrana avatar webcss avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

incremental-dom's Issues

Add demo

@sparhami I know you have one. Would be great to get it committed into a sub directory.

Correct way to cleanup up unattached nodes?

What is the correct way to detect if nodes are being or have been unmounted?

As example would would be the best way to call onClickCleanup() in the following contrived code.

patch( document.body, Render, 1)
patch( document.body, Render, 2)

function Render(id) {
  var el = elementVoid('input', id, ['type', 'button', 'value', 'click me'])

  var onClickCleanup = listener(el, 'click', function(evt) {
    alert('clicked', evt.target)
  })

  // how to run onClickCleanup() on removal?
}

function listener(el, type, fn) {
  if (el.addEventListener) {
    el.addEventListener(type, fn, false)
    return function() { el.removeEventListener(type, fn, false) }
  } else if (el.detachEvent) {
    el.attachEvent('on' + type, fn)
    return function() { el.detachEvent('on' + type, fn) }
  }
}

version 0.2.0 on npm: skip method absent

0.2.0 from npm seems to expose only elementPlaceholder but no skip method, version 0.2.0 here on git has skip

which is to be considered the latest?
if it's the one here on git how to declare it as an npm dependency?

Input `value` set as attribute

Consider the following failing test case...

IncrementalDOM.patch(document.body, function(){
  IncrementalDOM.elementVoid('input', null, null, 'value', 'initial');
});

// Simulates typing some words in the <input>... (same results if you manually type in the input)
document.querySelector('input').value = "NOT RIGHT";

IncrementalDOM.patch(document.body, function(){
  IncrementalDOM.elementVoid('input', null, null, 'value', 'Hello World');
});

Input text is still "NOT RIGHT" and not "Hello World"

Currently, IncrementalDOM decides how to assign an attribute based on the value's type.
Function and Objects are assigned as properties (ex. node.onclick = function(){}). Everything
else is assigned with setAttribute()/removeAttribute. Docs

Unfortunately, setting an <input>'s value (or checked) must be set as a property after the user
types in the input.

Currently, I'm working around the issue by wrapping the attribute's value with new String()...

  IncrementalDOM.elementVoid('input', null, ['type', 'text'], 'value', new String('Hello World'));

... this works as typeof (new String('Hello World')) === 'object'.

Not sure if a change is needed or just requires docs to note a workaround.

Here's the requirebin's for the above testcase and workaround:
http://requirebin.com/?gist=100e687ddffd8de6e59c
http://requirebin.com/?gist=7c30ebcf7613c5afc947

Switching to ES2015

So as ES2015 (prev. ES6) was standardized, and we have such great utility like Babel, maybe its good to rewrite the project to ES2015? I can send initial pr.

Split into core / opinionated versions?

Currently, Incremental DOM avoids considering things like what should be set as attributes/props based on attribute name and instead allows a library building on top of Incremental DOM to decide.

It is probably useful to create an Incremental DOM "core" that provides the core functionality and hooks, with a more complete version implementing some of the nice to have sort of things.

Suggestions / ideas for value added things are definitely welcome.

Async Support?

Any plans or idea on adding support for asynchronous rendering?

For example, allowing the following example to work.

elementOpen('div', '', null);
setTimeout(function() {
  text('hi');
  elementClose('div');
}, 1000);

Missing Assertions

  • currentElement cannot be called inside virtual element (elementOpenStart and elementOpenEnd)
  • elementOpenEnd tag must match elementOpenStart tag

Correct way to set process.env.NODE_ENV for closure compiler builds

I'm trying to integrate iDOM into a bigger es6 codebase that uses the closure compiler directly (ie without any browserfy crud).

Normally I would use something like /** @define {boolean} */ var ENABLE_DEBUG = true; and --define='ENABLE_DEBUG=true' as descibed here.

But its not clear to me how I get the same thing with process.env.NODE_ENV.

Render to String

One of the perks of React is the ability to render its virtual dom into strings on the server. It'd be nice to have the same capabilities.

Do you think it'd be worth while to maintain string element* that could be required on the server?

// string.js

var elements = require('virtual_elements'),
    elementVoid = elements.elementVoid,
    elementOpenStart = elements.elementOpenStart,
    elementOpenEnd = elements.elementOpenEnd,
    attr = elements.attr;


var patch = function(node, fn) {
  // Will have to consider how to translate this.
  // For now, just run the patch function
  fn();
};

var elementOpen = function(tag, key, statics, ...attrs) {
  // combine statics and attrs
  // translate combined into strings `${name}="${value}`
  return `<${tag} ${combined}>`;
};

// Void tags aren't gonna like this, but psuedocode. :smile:
var elementClose = function(tag) {
  return `</${tag}>`;
}

var text = function(value) {
  return value;
};


module.exports = {
  patch: patch,
  elementVoid: elements.elementVoid,
  elementOpenStart: elements.elementOpenStart,
  elementOpenEnd: elements.elementOpenEnd,
  elementOpen: elementOpen,
  elementClose: elementClose,
  text: text,
  attr: elements.attr
};

Rename element(Open, OpenStart, Void, Close)

I realise this might be a contentious suggestion but I'm finding I end up remapping the element* to shorter names to make raw idom read better.

import {
  text,
  patch,
  elementOpen,
  elementClose,
  elementVoid
} from 'idom/index';
var open = elementOpen, close = elementClose, tag = elementVoid;

Given that idom is focused on the dom would you be open to a breaking change and dropping the element?

This is partly based on using broccoli-jsx2idom for the bulk of ui and then dropping down to raw idom when jsx does not descibe the component I'm trying to render.

This should also help reduce the size of js UI's that don't mangle function calls.

documenting the ecosystem

I love this project, as me many will do as articles and repositories will grow talking about and using it.

I was thinking it would be good to maintain a separate markdown file with a list of libraries, blog posts, benchmarks to help people get oriented and started.

I've been publishing one template library recently on github depending on idom (which already has a project in production), plus some experiments and have another project to come.

Was thinking to ask to have my little library added to the readme.md among the others for discoverability, but realized the number of projects around is going to grow soon and the blog posts and tutorials are as much valuable to new comers.

So probably best take is to move everything to a separate markdown file and link it from the main readme.

Also I was wondering if their is any "official" recommendation about how to call the projects, sort of a shared prefix or suffix to help people figure out a first sight idom is in the game. Since now I have been prefixing my projects "incremental-dom-something" but realize maybe this should be reserved to the idom team efforts to be discovered on npm, and we can come up with a separate ecosystem prefix, something like "idom-".

What do you think? And anyway thanks for this stimulating project.

Create performance benchmarks

Currently, Incremental DOM does not have any good performance benchmarks to base changes on. Ideally they would be able to run as a part of the build process as well as standalone. In addition to testing for something like average time per pass, it should also check for the maximum time per pass to make sure GC is not kicking in.

This is fairly difficult as it is hard to model how the rest of an application generates garbage during updates. While the library itself may never generate enough garbage to cause more than an young gen GC, any allocation may end up ultimately causing old-gen GC which is hard to isolate and reproduce in a test, especially as heap sizes are likely to vary between environments. Since young gen GC can be very fast, it can be difficult to notice GC occurring with the amount of noise in a test.

Additionally, a spike does not necessarily indicate a GC occurred, but could happen due to the process being scheduled off which is likely to occur if running many iterations and hogging the CPU. This is not likely to occur in actual usage while updating web pages, but is something to watch out for when creating tests

Ultimately, any sort of environment we are likely to test on will have a huge amount of RAM compared to a smartphone in a developing country, which may have as little as 256MB and much of that taken by the OS.

elementOpen should take a list of attribute name/value pairs

When dynamically evaluating templates to incremental dom you don't statically know the attributes to set, so you must call elementOpen via Function.apply. It would be more convenient to have elementOpen accept arrays of attribute and property name/value lists.

Cutting a new release?

How many more changes are you planning before cutting a new tagged release? Would also be worth moving iDOM.mutators.attributes up to iDOM.attributes comment #67.

Support for other namespaces (SVG)?

It's been the Achille's heel of templating/vdom/web components for some time, but SVG elements are in a different namespace than HTML. There are many issues that arise from this. I'm unfamiliar with this implementation, but I didn't see anything about this and I wanted to put it on your radar early. Data visualization is a hot use-case for DOM rendering, but for that, first-class support of SVG is a must.

Are you accounting for other namespaces in your design? If so, how?

Patching inside a patch has no effect

According to the documentation, this code should work:

patch(document.body, function() {
  var p = elementOpen('p');
  patch(p, function() {
    elementVoid('span');
  });
  elementClose();
});

And the result should be:

<body>
  <p>
    <span></span>
  </p>
</body>

But the <span> node is not there. Apparently the problem is with this line. I've tried to remove it, but some tests are failing then (however, based on the name they don't seem to be releated). I will investigate a bit more, but if you have any ideas on why this was added it would be nice :).

Heavy @license header?

This has been flagged by others but given the focus on size is it be worth reducing the licence header to one line or something similar to ember or rsvp.js

For example would be more acceptable?

/**! 
 * @copyright 2015 The Incremental DOM Authors. All Rights Reserved
 * @licence   Licensed under Apache License, Version 2.0
 *            https://github.com/google/incremental-dom/blob/master/LICENSE
 */

Comparison: React

This seems like a very interesting project. I'd be particularly interested in how this relates to Facebook's React. Is this intended to be a competitor project or are there any severe design differences?

Maybe it would be helpful for other people to briefly compare both projects in the README since React is very common.

Thanks!

Keeping src files when publishing / downloading from GIT with NPM

When trying to use the latest incremental-dom version through npm, by adding the repository URL into the package.json file, nothing is downloaded, apart from the LICENSE and AUTHORS file. I think this happens because of the files key defined in the package.json file.

However, if the project where you want to use it uses ES6 classes, and has already a process for building, I think it makes much more sense to be able to directly link into the source files, rather than using the compiled result (which of course is not present on the repo either).

Would it be worth then for that to add the src key into the array; or is it better to point to it as a git submodule?

IE and input types

Cross posting from HTMLBars: tildeio/htmlbars#380

We suffer from the same issue. Setting the type of an input that is already a part of any DOM tree will cause an error in IE < 9.

patch(container, function() {
  elementVoid('input', null, null, 'type', 'text');
});

We're safe using statics, since the node won't have been inserted anywhere yet โ€” statics are set during the creation and before alignment can insert it.

patch(container, function() {
  elementVoid('input', null, ['type', 'text']);
});

Explore adding support for filters

Often, you see something like:

text(formatFn(someText))

If the formatFn is a pure function, then we could add a helper that allows calling the formatting function to only be called when someText. Maybe text could take a series of formatting functions to apply if the text has changed as variable arguments.

It may also be useful for attributes, support for which could be added through the attr function.

CDN access

Since there's no dist preinstall we can't just use rawgithub is there a way we can get a cdn version of incremental-dom up so I can use it jsbin / jsfiddle?

Animation support?

Hi, do you have any plans for animation support (for node removal/insertion)? Some methods which can be used for such purpose? Or maybe you have some ideas how to animate nodes removal during the patch?

DOM Traversal via DOM?

@sparhami Did you benchmark switching from using nextSibling, etc. to caching those in a node's backing data, so that no DOM operations would be involved in traversal?

New Release?

I see a whole lot of changes have landed since the last release, but I can't tell what state master is in. Are there plans for a new release soon, or some kind of idea what needs to be done for one?

Thanks!

Roadmap Items

Just a place to aggregate things that need to be thought over:

  • Statics diffing (statics equality should be used in matches during alignment) #152 (comment)
  • First patch of server rendered keyed nodes #177
  • Incremental DOM Instances (no global state) #114

Unexpected attribute behaviour using conditionals

I encountered some unexpected behaviour whilst using conditional logic.
This could be a bug or more likely my misunderstanding the difference between statics and dynamics properties.

Consider the following:

  var patch = IncrementalDOM.patch
  var text = IncrementalDOM.text
  var elementOpen = IncrementalDOM.elementOpen
  var elementClose = IncrementalDOM.elementClose

  function description (data) {
    if (data.show) {
      elementOpen('a', null, ['class', 'show', 'href', '/foo'])
        text('Show')
      elementClose('a')
    } else {
      elementOpen('a', null, ['class', 'hide', 'href', '/bar'])
        text('Hide')
      elementClose('a')
    }
  }

  var data = {
    show: false
  }

  function render () {
    data.show = !data.show
    patch(document.body, description, data)
  }
  render()

I expected the a tags attributes to change when toggling the value of data.show between true/false.
This doesn't happen. The inner text does however change between 'Show' and 'Hide'.

Promoting the class and href attributes from statics to dynamic properties does yield the expected behaviour but my understanding was that this shouldn't be required in this case.

Dave

Skip

TLDR;

We might want to break skip into three functions:

  • prepend
  • append
  • skip (yup)

And we have an issue with keyed elements and skip, leaving an invalid keyMap with references to zombie children nodes that are no longer in the tree.


To start with, I'm curious how you see skip being used. It actually solves a problem with the Glimmer render I'm working on.

The way I see this working is like so:

function render(data) {
  return <div>
    <div id={data.id} />
  </div>;
};

// - - -
// Translates to something like

function render(data) {
  var elements = render.elements = [];
  elements.push(elementOpen("div"));
  elementVoid("div", null, null, "id", data.id);
  elementClose('div');
  return elements[0];
}

// A more efficient rerender function, since we don't need to walk the _entire_ tree
render.secondRender = function(data) {
  patch(render.elements[0], (data) => {
    elementVoid("div", null, null, "id", data.id);
  }, data);

  // Use skip to prevent clearing from outer patch context,
  // since `secondRender` was called like so:
  //     patch(container, render.secondRender, data)
  skip();
  return render.elements[0];
};

patch(container, render, data);
// Later, repatch
patch(container, render.secondRender, data);

Specifically, I imagine opening an element, skipping, and then immediately closing it โ€” no children. The children route is an option, but there are issues. Obviously we don't want to clear children, but means we could be creating a whole slew of new elements without ever garbage collecting the old:

function render(data) {
  elementVoid('div', data.key);
  skip();
}

patch(container, render, { key: i++ });
patch(container, render, { key: i++ });

That could be useful for prepending to lists... ๐Ÿ˜„. But actually, that example won't work because of a niggle in our alignment algorithm. We'll replaceChild the old keyed element (because it has a key), and it'll just be left sitting in the keyMap, even though it's no longer in the DOM (and keyMapValid === false).

Instead, we might want to break skip into three functions:

  1. prepend - Useful for my hypothetical case above
    • Required to be first call inside elementOpen
    • allows children elements after the call
      • turns off the replaceChild alignment
    • skips clearing of children
  2. append - Useful for the opposite case, appending to the list
    • Required to be first call inside elementOpen
    • allows children elements after the call
    • sets currentNode to null and previousNode to currentParent.lastChild
      • skips clearing of children, by virtue of our current algorithm
  3. skip - Useful for my Glimmer case
    • Required to be the only call inside elementOpen
      • doesn't allow children elements
    • skips clearing of any children

Web Components support

Hi,

I was trying the Custom Element demo, and I noticed the lack of browser support for the Web Components part.

Is that something that will ever be included in incremental-dom? If not, it would probably make more sense to use a library like polymer in the demo?

Decide on supported browsers

There are currently two known IE8 bugs:

  • class does not work (class must be set using the className property)
  • input type must be set before inserting an input element into the DOM (#60)

Currently, supporting IE8 seems to only require modest code changes, though it may have additional impacts on future development.

For reference, Polymer and Angular 2.0 are targeting IE10+, Ember 2.0 targeting IE9 and React targeting IE8, though some polyfills are required.

Allow explicit control of setting attributes vs properties

Compiling template syntaxes that allow users to specify whether an attribute or property is to be set, like Polymer or Angular 2, requires wrapping all primitive values in objects to force property setting. It'd be a lot friendlier of an API to just accept attributes and properties separately in elementOpen.

Version 0.2

Update docs
Create a changelist
Publish to NPM

Create a separate initial rendering pass

Currently creating a new subtree can be a somewhat slow due to the fact that the general diffing pass is used. This forces allocation of a few objects/arrays that are unneccessary when everything is a change. This should be transparent to the caller (meaning they should just be able to call patch and not care about whether the subtree exists or not).

There are two ways I have experimented with doing this in the past:

  1. For any subtree that does not have a firstChild
  2. For a patch operation that does not have a firstChild

With the current code base, the latter ends up being a bit cleaner and makes later changes easier. It also seems to be a good approach as a patch operation corresponds to a component and if things are broken down into components, there likely is no benefit to doing it on a per node basis.

There also may be some performance benefit to not switching to a creation mode for trivially sized subrees.

Attribute maps?

Are there any plans to support attribute maps, rather than serial arguments? This seems a lot easier to use to me:

elementOpen('li', {'class': 'foo', 'data-bar': 'baz'});

than:

elementOpen('li', 'class', 'foo', 'data-bar', 'baz');

The former is also a lot easier to work with programmatically. Passing an arbitrarily long list of attributes shouldn't involve having to construct a call like this:

var args = Object.keys(attrs).reduce(function(attr, list) {
  list.push(attr, attrs[attr]);
  return list;
}, []);
elementOpen.apply(null, ['li'].concat(args));

I haven't fully grokked how the statics array feature relates to this, but that seems even more obtuse, at least syntax-wise.

currentElement and DocumentFragment

If a DocumentFragment is being patched and currentElement is called at the root, then it will actually return a Node and not an Element.

I'm not sure if an assert should be added or if it should be currentNode instead. It doesn't seem like a good idea to expose the node being patched from inside, so an assert making sure that it isn't called at the root might be a good idea.

Better module bundling

It's great that this library is so small, but a big portion of the dist file is actually related to browserify, stuff like this:

}, {
  "./alignment": 2,
  "./attributes": 3,
  "./node_data": 4,
  "./traversal": 7,
  "./walker": 10
}],
10: [function(t, e, n) {

This is only necessary because of the require syntax. If you guys switch to ES2015 (ES6) modules you can use a tool like esperanto to make your dist file significantly smaller.

For an example setup of this, check out babel-library-boilerplate

I can make a PR with this if you'd like?

Explore which functions are/are not getting inlined

Running Chrome with the following command gives detailed information on which functions it is and is not inlining.

google-chrome --js-flags="--trace-inlining"

The output may be useful to see which functions are and are not getting inlined.

@jridgewell Looking into this might help with evaluating #121

Include a link to superviews.js in the documentation

Hi,

Can we get a link to superviews.js, a simple template engine that targets incremental-dom.

It's an early PoC at the moment. It has a syntax that closely maps to incremental-dom, allowing it to make full use of the features in its API.

Happy to issue a PR for this.

Any tips/contributions welcome.

Cheers

Dave

Allow setting of innerHTML and textContent properties

Setting innerHTML and textContent for an Element should be supported. To support this the following needs to be done:

  • Instead of calling setAttribute/removeAttribute for primitive (non object/function) values, check if it should be set using the property instead
  • For Elements that have innerHTML or textContent set, do not sweep out children on exit
  • Add assert to enforce elementOpen, etc. are not called inside an Element with innerHTML or textContent
  • Optionally, add semantically named attribute that behaves like textContent = '', allowing for Elements to act as insertion points for non-library managed DOM

Reaching out for advice/opinions for superview.js incremental-dom template language

Forgive me posting here - I'm sure it's not the right forum. Please let me know where might be a good place to ask and I'll get it moved.

I wonder if anyone could offer their opinion on a how I should define static attributes values in the superviews.js template language I'm building.

Regular properties use single curly braces {} to define values.

<div class="{data.className}"></div>

I needed to distinguish statics and had settled upon {=} . This works ok for referencing simple values as in the first example in the list below, but I thought it didn't look great in the case where an assignment is made like the 6th example. This will define a static handler function against the onchange event. I thought having two equal signs looked a bit naff.

I've come up with some alternatives in the hope someone could offer some opinion/advice. :)

I've batted this round my head for a day or two but I'm not convinced by any of the options really, maybe I'm over thinking it? Aesthetically I like the greater than sign, semantically the hash sign given it has no special meaning in javascript (but html it does of course :( I have just realised).

<div title="{=data.title}"></div>
<div title="={data.title}"></div>
<div title="{>data.title}"></div>
<div title="{#data.title}"></div>
<div title="{{data.title}}"></div>
<input type="text" value="{data.val}" onchange="{=data.val = this.value}">
<input type="text" value="{data.val}" onchange="={data.val = this.value}">
<input type="text" value="{data.val}" onchange="{>data.val = this.value}">
<input type="text" value="{data.val}" onchange="{#data.val = this.value}">
<input type="text" value="{data.val}" onchange="{{data.val = this.value}}">

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.