Search code examples
javascriptractivejs

Ractive.js flip boolean function


I am new to Javascript (started today) and I am using the Ractive framework to make a web app to deliver an analytics product. I am trying to make a function that flips a boolean value in the .on function. I have something like this but it isn't working. Can someone help me about how to think about this problem?

ractive.on('flipBool', function ( ) {
  ractive.set( 'theData.*.Visible', !'theData.*.Visible' );
});

Solution

  • Following on from ofrommel's answer, I thought I'd quickly explain what's going on in the initial code snippet, as it might be helpful in future.

    When you call ractive.set('theData.*.Visible', !'theData.*.Visible'), you're setting everything that matches theData.*.Visible to a single value, which is !'theData.*.Visible - and because the ! operator simply negates whatever follows it, and a non-empty string is considered truthy, !'theData.*.Visible' === false. So it's the equivalent of doing this:

    ractive.set( 'theData.*.Visible', false );
    

    So instead of using the keypath in the second argument, you have to actually get the value of the keypath:

    // this...
    ractive.toggle( 'foo' );
    
    // ...is equivalent to this:
    ractive.set( 'foo', !ractive.get( 'foo' ) );
    

    Unfortunately, that doesn't actually work with keypaths that contain the * character:

    // this...
    ractive.toggle( 'theData.*.Visible' );
    
    // ...is equivalent to this...
    ractive.set( 'theData.*.Visible', !ractive.get( 'theData.*.Visible' ) );
    
    // ...which is equivalent to this:
     ractive.set( 'theData.*.Visible', true );
    

    Because ractive.get('theData.*.Visible') is always undefined, that means that toggling the value will always set all matching keypaths to true, which isn't what you want. (I've just opened an issue on GitHub to address this.)

    So the best way to achieve what you want, at present, is to iterate through the array and update everything manually, like so:

    ractive = new Ractive({
      el: 'main',
      template: '#template',
      data: {
        people: [
          { name: 'Alice', visible: false },
          { name: 'Bob', visible: true },
          { name: 'Caroline', visible: true },
          { name: 'Dave', visible: false },
          { name: 'Eric', visible: false }
        ]
      },
      flipBool: function () {
        var changes = {};
        this.get( 'people' ).forEach( function ( person, i ) {
          changes[ 'people.' + i + '.visible' ] = !person.visible;
        });
        this.set( changes );
      }
    });
    <script src="http://cdn.ractivejs.org/latest/ractive.js"></script>
    
    <main></main>
    
    <script id='template' type='text/html'>
      <button on-click='flipBool()'>flip</button>
      
      {{#each people}}
        {{#if visible}}
          <p>{{name}} is visible</p>
        {{/if}}
      {{/each}}
    </script>