Skip to content
chemerisuk edited this page Dec 18, 2014 · 9 revisions

Unlike many others in better-dom there is no concepts like element attributes and element properties. Just to remind why vanilla DOM is total mess assuming we have element like below on the page:

<a href="/chemerisuk/better-dom" id="foo" data-attr="test">better-dom</a>

Now let's check what every entity returns:

var vanillaFoo = document.getElementById("foo");

vanillaFoo.href; // => "https://github.com/chemerisuk/better-dom"
vanillaFoo.getAttribute("href"); // => "/chemerisuk/better-dom"
vanillaFoo["data-attr"]; // => undefined
vanillaFoo.getAttribute("data-attr"); // => "test"

As we see from the example:

  1. method getAttribute always returns exact string that an element has in markup
  2. property with the same name on the other hand can exist or not
  3. if a property exist, it may have a special behavior, therefore result value can be different from what you have in markup

Similar logic applies to setAttribute. A bit complicated, isn't it?

Getter and setter to rescue

In better-dom, things are clearer. Every element has only two methods: $Element#get and $Element#set.

var foo = DOM.find("#foo");

foo.get("href"); // => "https://github.com/chemerisuk/better-dom"
foo.get("data-attr"); // => "test"

Algorithm is simple: if an element has a property with an appropriate name, it's returned as a result. Otherwise an attribute value is returned.

Private properties

Native DOM doesn't have a concept private data storage associated with a particular element. Well, it has dataset in HTML5, but that property touches the DOM and introduces unnecessary side effects, therefore it's slow.

In JavaScript we usually use _ (underscore) symbol to mark private data. Why can't we use the same syntax for $Element too:

foo.set("_bar", "hello");
foo.get("_bar"); // => "hello"
foo.get("_unknown"); // => undefined

If there is no such private property the library tries to parse appropriate data-* attribute. Parsing of JSON attributes supported as well. For instance, if we have attributes like below:

data-simple="value"
data-obj-attr=`{"a": "b"}`

Those value can be read using calls like below:

foo.get("_simple");  // => "value"
foo.get("_objAttr"); // => {a: "b"}

Note: for private properties you have to use camel cased syntax which will be used to find the appropriate dash-separated attribute name.

Element 'value' shortcut

Vanilla DOM has a concept of empty elements. Those elements have an important difference from regular: they can't have child nodes. Check an example below:

var vanillaDiv = document.createElement("div");

vanillaDiv.innerHTML = "<b>hello</b>";
vanillaDiv.innerHTML; // => "<b>hello</b>"
vanillaDiv.value = "<b>hello</b>";
vanillaDiv.value; // => undefined

Now try the same with <input>:

var vanillaInput = document.createElement("input");

vanillaInput.innerHTML = "<b>hello</b>";
vanillaInput.innerHTML; // => ""
vanillaInput.value = "<b>hello</b>";
vanillaInput.value; // => "<b>hello</b>"

In better-dom this problem is solved using a 'value' shortcuts, e.g. when $Element#get or $Element#set method is called without passing the first argument:

var div = DOM.create("div");
var input = DOM.create("input");

div.set("<b>hello</b>");
div.get();            // => "<b>hello</b>"

input.set("<b>hello</b>");
input.get();            // => "<b>hello</b>"

Much simpler, isn't it? If you need to specify which property you want to access, you can always pass the name:

div.get("innerHTML"); // => "<b>hello</b>"
div.get("value");     // => undefined

input.get("value");     // => "<b>hello</b>"
input.get("innerHTML"); // => ""

In other words you can use $Element#get() and $Element.set(String) to make accessing to inner content to be consistent.