Search code examples
ractivejs

Update "progress bar" based on selection in Ractive


I am new to Ractive.js. What i am basically trying to achieve is that based on the id selection(from the combo box),update appropriate progress bar.

In below sample, there are two progress bars and 4 buttons(+25,+10,-25,-10).User can select any progressbar(say "first") and then press any buttons like +25 etc.When the user performs this action, appropriate progressbar should be updated(in this case "first" by say "25").

I have tried but am not sure how to select context based on progressbar selection.In my case,both progress bars get updated irrespective of what i have selected in select box. Please let me know how can i resolve this issue and also tell me if there is a way to clean the code(something like ng-repeat etc)

Please see the code in See full code here....

.progress-bar {
 position: relative;
 width: 200px;
 height: 40px;
 border: 1px solid black;
 }
.progress-bar-fill {
 height: inherit;
 background-color: orange;
}    

.progress-bar-fill-red {
height: inherit;
background-color: red;  
}
.progress-label {
position: relative;
top: 3px;
left: 5px;
color: #000;
}
input[type=range] {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
cursor: pointer;
/* essentially making range slider invisible */
opacity: 0;
}

Solution

  • The trick here is to keep track of which progress bar is selected (which you're doing with the selectedProgress value), and use that to determine which value to update.

    Another trick: any time you find yourself writing the same (or similar) code again and again, it's usually a sign that you can abstract something into a function or loop (the so-called Don't Repeat Yourself rule, or DRY). In this case, we can move the progress bars into a repeated section. Having done that, it makes more sense to keep the value of the progress bar in the same object as the name, like { name: 'first', value: 0 }, because then, when we're iterating over the progressbar objects, we can just use {{value}} to refer to that progress bar's value, rather than having to retrieve the value from somewhere else.

    By the same token we can avoid re-writing the logic that updates the value, by having a single function (let's call it adjust) and calling it directly from the template:

    var ractive = new Ractive({
      el: document.body,
      template: '#template',
      data: {
        progressbars: [
          // notice no `id` field – in the <select>, we can just
          // use the current index
          { name: 'first', value: 0 },
          { name: 'second', value: 0 }
    
          // and so on...
        ],
        amounts: [ +25, +10, -10, -25 ]
      },
      adjust: function ( d ) {
        var selected = this.get( 'selectedProgress' );
        if ( selected == null ) return;
    
        var keypath = 'progressbars[' + selected + '].value';
        this.add( keypath, d );
      }
    });
    
    {{#each amounts}}
      <button disabled='{{selectedProgress == null}}' on-click='adjust(this)'>{{this > 0 ? '+' : ''}}{{this}}</button>
    {{/each}}
    

    Now, whenever the button (which is disabled if you haven't selected a progress bar) is clicked, the adjust function is called with the current amount in the amounts array (i.e. this).

    All of which is easier to show than to describe, so here's an updated fiddle: http://jsfiddle.net/rich_harris/k8vpcv27/