Backbone.js: avoid view→model→view double conversion

随声附和 提交于 2019-12-09 10:30:48

问题


I’m trying to build this:

When I edit field on the left it should update the one on the right and vice-versa.

  • Editing a value in an input field causes the text cursor to jump at the end of it.

  • Typing "2" in the fahrenheit field gets replaced with 1.999999999999, as you can see on the screenshot. This happens because of the double conversion:
    view’s Fº → model’s Cº → view’s Fº.

How can I avoid that?


Update:

I want to know the elegant way of dealing with two-way bindings in MVC frameworks such as Backbone.js.

MVC

var Temperature = Backbone.Model.extend({
    defaults: {
        celsius: 0
    },
    fahrenheit: function(value) {
        if (typeof value == 'undefined') {
            return this.c2f(this.get('celsius'));
        }
        value = parseFloat(value);
        this.set('celsius', this.f2c(value));
    },
    c2f: function(c) {
        return 9/5 * c + 32;
    },
    f2c: function(f) {
        return 5/9 * (f - 32);
    }
});


var TemperatureView = Backbone.View.extend({
    el: document.body,
    model: new Temperature(),
    events: {
        "input #celsius": "updateCelsius",
        "input #fahrenheit": "updateFahrenheit"
    },
    initialize: function() {
        this.listenTo(this.model, 'change:celsius', this.render);
        this.render();
    },
    render: function() {
        this.$('#celsius').val(this.model.get('celsius'));
        this.$('#fahrenheit').val(this.model.fahrenheit());
    },
    updateCelsius: function(event) {
        this.model.set('celsius', event.target.value);
    },
    updateFahrenheit: function(event) {
        this.model.fahrenheit(event.target.value);
    }
});

var temperatureView = new TemperatureView();

No MVC

celsius.oninput = function(e) {
    fahrenheit.value = c2f(e.target.value)
}
fahrenheit.oninput = function(e) {
    celsius.value = f2c(e.target.value)
}
function c2f(c) {
    return 9/5 * parseFloat(c) + 32;
}
function f2c(f) {
    return 5/9 * (f - 32);
}

Not only it fixes the problem, it’s also reduces the code 3.5⨉. Clearly I’m doing MVC wrong.


回答1:


Here's my take on this; instead rendering the whole view on every change, in interactive views, use the view's jQuery or plain JS contexts just like your non-MVC example.

http://jsbin.com/fomugixe/1/edit

As the Backbone docs say:

"Two way data-binding" is avoided. While it certainly makes for a nifty demo, and works for the most basic CRUD, it doesn't tend to be terribly useful in your real-world app. Sometimes you want to update on every keypress, sometimes on blur, sometimes when the panel is closed, and sometimes when the "save" button is clicked.




回答2:


Two methods come to mind. As Kinakuta mentioned you can do something like the following so you're math works on integers, instead of decimals:

temp = ((oldTemp * 100) * conversion stuff) / 100

Depending on how complex you want your app to be you can also use something like Backbone.ModelBinder. It automatically binds your view to your model so when one updates, the other updates automatically. You can then attach a converter function to the binding so when your value goes view -> model or model -> view it's run through the converter. I can elaborate more if that idea interests you.

Update: With a simple temp converter it's not surprising that Backbone requires 3.5x as much code. An MVC framework can reduce bloat in a large project, but for a small app it might be overkill. e.g. imagine using Backbone to display "Hello World".

As for your issue, how about only rendering the other input value when one is changed, instead of both? If F input changes, re-render value in C box. With ModelBinder I would do this by having two attributes in my model: tempF and tempC. When one is modified, I re-calculate the other and ModelBinder automatically displays it. Or you can go without MB and just listen for the change event.




回答3:


set a variable at the view level where you hold the input field that started the conversion, so you don't call the conversion function on that field.



来源:https://stackoverflow.com/questions/15824887/backbone-js-avoid-view%e2%86%92model%e2%86%92view-double-conversion

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!