npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

domr

v1.0.1

Published

fast and async DOM updates

Downloads

9

Readme

domr

Update DOM element content/attributes asynchronously.

Heavily inspired by Ampersand.js DOM bindings but without needing inheritance and wrapping your data into Models/State objects.

"inheritance is the root of all evil" - Albert Einstein :P

Important: I will only test on modern browsers, use at your own risk.

Why?

Couldn't find anything that was fast on a slow mobile device and worked the way I wanted, so let's reinvent the wheel. See this twitter thread for more details.

I know there are hundreds of JS frameworks out there and that data binding is the coolest thing since sliced bread, but this will probably work better for my use case (low memory, slow cpu, few updates and usually async - usually in batches).

This approach allows you to write the markup and build the DOM any way you want (eg. web components, any template language or just plain HTML).

Example

given this HTML fragment:

<section id="foo">
  <h1></h1>
  <img />
  <p role="caption"></p>
</section>

You can update it with:

var domr = require('domr');
var el = document.getElementById('#foo');

// this will create a mapping between properties and elements/actions
var foo = domr.create(el, {
  'doge.title': 'h1',
  'doge.image': {
    selector: 'img',
    type: 'attr',
    name: 'src'
  },
  'doge.description': {
    role: 'caption'
  },
  isWarning: {
    // "@" matches the root element itself
    selector: '@',
    type: 'toggleClass',
    name: 'is-warning'
  }
});

// this will update the DOM asynchronously
foo.render({
  isWarning: true,
  doge: {
    title: 'Wow, Such Awesome',
    image: 'doge.jpg',
    description: 'wow. much javascript. such ipsum',
  }
}, onRenderComplete);


// called after data is updated (on next animation frame)
function onRenderComplete(element) {
  console.log('rendered the element #'+ element.id);
}

The document will be updated on the next requestAnimationFrame, becoming:

<section id="foo" class="is-warning">
  <h1>Wow, Such Awesome</h1>
  <img src="doge.jpg" />
  <p role="caption">wow. much javascript. such ipsum</p>
</section>

If you call render multiple times in a row with different data, it should only update the DOM once. DOM manipulation is batched and throttled, and always happens on a requestAnimationFrame.

Subsequent calls to render should be faster since we cache references to all the needed elements on the first call. We also check which data changed since last render and only update the affected elements/attributes.

When you don't need the binding anymore you can call destroy to remove any references to elements and cached data (not needed on most cases tho).

// remove internal cache and references to elements
foo.destroy();

Tips

This lib is not only about raw performance, a great benefit is that you can keep calling render even if the data did not change and it is smart enough to only update the affected elements. This simplifies the development process and reduces the amount of conditionals in the codebase.

It's similar to the way React works, in the sense that we always render but only it's smart enough to only update the DOM when needed. The main difference is that we don't have a virtual DOM and we also don't handle how the state/data is passed into the views (meaning that we save thousands of lines of code on the library side but you might need to implement more logic yourself).

Binding types

Bindings treats undefined, null, and NaN as '' (empty string).

text

Sets textContent of selected element.

'model.key': {
    type: 'text',
    selector: '.someSelector' // or role
}

class

Sets class as string that matches value of property. It can handle multiple classes (single string separated by spaces) and will also remove previous class if value is updated.

'model.key': {
    type: 'class',
    selector: '.someSelector' // or role
}

attribute / attr

Sets the whole attribute to match value of property.

'model.key': {
    type: 'attribute', // or "attr"
    selector: '#something', // or role
    name: 'width'
}

toggleClass

Add/removes class based on boolean interpretation of property name.

'model.active': {
    type: 'toggleClass',
    selector: '#something', // or role
    // to specify name of class to toggle (if different than key name)
    // you could either specify a name
    name: 'active'
    // or a yes/no case
    yes: 'active',
    no: 'not-active'
}

toggleAttribute / toggleAttr

Toggles whole attribute on the element (think checked) based on boolean interpretation of property name.

'model.isAwesome': {
    type: 'toggleAttribute', // or "toggleAttr"
    selector: '#something', // or role
    name: 'checked'
}

html

Renders innerHTML based on property value.

PS: this won't escape any HTML entities and can be used as an attack vector (XSS), favor the text type as much as possible.

'model.key': {
    type: 'html',
    selector: '#something' // or role
}

Handling multiple bindings for a given key

If given an array, then treat each contained item as separate binding

'key': [
    {
        type: 'toggleClass',
        selector: '#something', // or role
        name: 'active' // (optional) name of class to toggle if different than key name
    },
    {
        type: 'attr',
        selector: '#something', // or role
        name: 'width'
    }
]

Install

Modules are converted to node.js format during npm publish in case you want to use it with browserify.

npm install domr

or you can use the something like volo to download the AMD source files. (or just use the files inside src)

volo add millermedeiros/domr#src domr

License

Released under the MIT license.