0
\$\begingroup\$

I want to create a JS MVVM framework for learning and personal project.

jsFiddle

HTML:

<input type="text" mk="value=test" value="test" />
<br />
<span mk="text=test"></span>

JS (markjs):

(function () {
    Mark = {};
    var mark = {
        text: {},
        value: {}
    };



    Mark.set = function (name, value) {
        for (var key in mark) {
            if (mark[key][name]) {
                mark[key][name].value = value;
                rejuvenate();
            }
        }
    }

    function rejuvenate() {
        for (var key in mark) {
            for (var name in mark[key]) {
                if (mark[key][name]) {
                    if (key === 'text') mark[key][name].node.innerText = mark[key][name].value;
                    else if (key === 'value') mark[key][name].node.value = mark[key][name].value;
                    else if (key === 'click') mark[key][name].node
                }
            }
        }
    }


    var elems = document.getElementsByTagName('*');
    for (var ii = 0; ii < elems.length; ii++) {
        if (elems[ii].getAttribute('mk')) {
            var marks = elems[ii].getAttribute('mk').split(';');
            if (marks.length > 0) {
                for (var jj = 0; jj < marks.length; jj++) {
                    var d = marks[jj].split('=');
                    if (d[0] === 'value' || d[0] === 'text') {
                        mark[d[0]][d[1]] = {
                            node: elems[ii],
                            name: d[1],
                            value: ''
                        };
                        if (d[0] === 'value') {
                            elems[ii].onkeydown = function (e) {
                                e = e || window.event;
                                var charCode = e.charCode || e.keyCode,
                                    character = String.fromCharCode(charCode),
                                    value = this.value;

                                var cmk = this.getAttribute('mk').split(';');
                                for (var cc = 0; cc < cmk.length; cc++) {
                                    var dd = cmk[cc].split('=');
                                    Mark.set(dd[1], value);
                                }
                            }
                        }

                    }
                }
            }
        }
    }
})();

Mark.set('test', 'Yoza');

I tried to create angular-model-like or ko-observable-like. I created a model name: test. If any mark (mk) with marker value=test update will update any element innerTextwith marker text=test. It's like KnockoutJS but for now I want to understand how it works. My problem is that input update is always late, not like Angular every type will update model.

I also provide Mark.set(name, value). It will update every marker with same name to that value.

Please help me to improve this code and review my code and concept.

\$\endgroup\$
2
\$\begingroup\$

I want to create a js MVVM framework

Oh no... not again. No, seriously. If this is for learning purposes or personal stuff, that's fine. If you plan to use this in real projects and production, you might consider picking up an existing framework or help improve an existing one.

my problem is input update always late, not like angular every type will update model.

That's because during a keydown event, the value of the input hasn't been changed yet. Frameworks usually use a combination of different events (which differ across elements as well as browsers) to consistently get values whenever the UI state changes. For instance, radio buttons in older IE don't fire some event on selection (I think it was change) and frameworks work around it by detecting click instead.

angular every type will update model

The approach of each framework is different. Angular uses "dirty checking", which is a periodic check of data changes, and re-rendering once necessary. Frameworks like Ember and Backbone rely on setters which, aside from setting values, recompute dependent entities like computed props, and the DOM.

var elems = document.getElementsByTagName('*');
for (var ii = 0; ii < elems.length; ii++) {
  if (elems[ii].getAttribute('mk')) {

This is a bad idea. It's fast in small cases, terrible when your page is huge. Consider narrowing down the initial set of elements instead of getting every single one of them and filtering.

<input type="text" mk="value=test" value="test" />

Your markup is also... too much. All we needed is to know where this input binds to. You'd only need to assign the binding. Additionally, when using frameworks, you seldom actually touch the values. Values come straight from the view-model. In this case, "test" shouldn't be necessary. The following should be fine:

<input type="text" data-mk="test" />

You should also consider when your data starts to contain objects and arrays. You'd then have to deal with data contexts, key path resolution, parsing the expressions, scoping. Your example works fine when your DOM only has one model to bind to. In real life, you could have a dozen of data sources and elements nesting each other.

elems[ii].onkeydown = function (e) {
    e = e || window.event;
    var charCode = e.charCode || e.keyCode,
        character = String.fromCharCode(charCode),
        value = this.value;

    var cmk = this.getAttribute('mk').split(';');
    for (var cc = 0; cc < cmk.length; cc++) {
        var dd = cmk[cc].split('=');
        Mark.set(dd[1], value);
    }
}

Like I said earlier, listening to events require combinations of events and may differ across elements and browsers. You could move this logic out of your main framework logic (maybe in a separate function, or an entirely separate module) that you could simply pull in and call.

\$\endgroup\$
  • \$\begingroup\$ thanks for your response it really help me, this is for learning and personal project. \$\endgroup\$ – yozawiratama Nov 15 '15 at 1:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.