Synchronize interdependent Dojo widgets/values

2019-08-18 09:57发布

问题:

I'm about to build a simple "mortgage calculator" where a user is to adjust some sliders OR edit values in input fields in order to calculate some final value based on the provided data.

Schematically it will look something like this:

Slider1 - Input1
Slider2a - Input2a
Slider2b - Input2b

The idea is that the value of the input must be reflected in the slider, and vice versa. In addition, the values and limits of slider 2a/2b and input 2a/2b depend on each other, according to some simple rule.

It has to be done in Dojo, which I've never used before, and, even though Dojo has quite good documentation, it is a little overwhelming, so I'd appreciate if someone could point me in the right direction.

回答1:

First of all, here is my solution working at jsFiddle: http://jsfiddle.net/phusick/HCx3w/

You can use dojo/aspect, dojo/topic and dojo/Stateful and directly connect those widgets to each other in various ways. You will probably end up with a tightly coupled set of widgets, i.e. those widgets will know about each other, even if there is no reason a particular widget should have any knowledge about the fact its value is being synchronized with another widget.

Contrary to the aforementioned you can apply loose coupling principle, which will allow you to synchronize any number of widgets without any mutual references among them. Here is my solution:

  1. Obtain references to widgets and couple them into sets (arrays):

    var slider1 = registry.byId("slider1");
    var slider2 = registry.byId("slider2");
    var spinner1 = registry.byId("spinner1");
    var spinner2 = registry.byId("spinner2");
    
    var set1 = [slider1, spinner1];
    var set2 = [slider2, spinner2];
    
  2. synchronize function:

    var synchronize = function(/*Array*/ widgets, /*String*/ topicName) {
    
        var synchronized = function() {
            var count = 0;
            array.forEach(widgets, function(widget) {
                if(widget.get("synchronized") === true) { count++} 
            });
            return (count == widgets.length);
        }
    
        array.forEach(widgets, function(w) {
    
            w.set("synchronized", false);
    
            // register onchange handler for each widget in the set
            w.on("change", function(value) {
                array.forEach(widgets, function(widget) {
                    if(this !== widget) {
                        widget.set("value", value);
                        widget.set("synchronized", true);
                    }                                         
                }, this);
    
                // needed to publish topic just once per value change across all the widgets in the set
                if(synchronized()) {
                    array.forEach(widgets, function(widget) {
                        widget.set("synchronized", false);
                    });
                    // publish topic if any
                    if(topicName) { topic.publish(topicName, value)};
                }
            });
        });
    }
    
  3. Register sets of widgets to synchronize via sychronize function:

    synchronize(set1, "value1-changed");   // synchronize and publish topic when value changes
    synchronize(set2);                     // just synchronize
    
  4. Subscribe to the topic you registered above:

    topic.subscribe("value1-changed", function(value) {
        console.log("value1-changed", value);
        // here you can change value and limits of of `set2` widgets
    });
    


回答2:

dojo. Stateful is your friend... http://dojotoolkit.org/reference-guide/1.7/dojo/Stateful.html



回答3:

Have you tried dojo.connect. This can be used method chaining. So when the event is fired in control multiple methods can be invoked. Beside this there is publish\subscribe mechanism in dojo. In pub\sum model you can write method to subscribe for simple message strings. When some method published that string, than subscriber method will be invoked.