Search code examples
javascriptdatatablesractivejsbootstrap-multiselect

is it possible to render part of a ractive template on click event?


for a CRUD-Interface I have a JSON in a Datatable rendered by ractive. So for two of the columns I need a multiselect dropdown (with bootstrap-multiselect), as the values are predefined out of another list of computed values.

Simplified it looks like this:

const DataTpl = '{{#PersonData:i}}' +
    '<td><select multiple id="persons{{i}}" value="{{hasSkill}}">' +
    '{{#Skills}}' +
    '<option value="{{_id}}">{{Skill}}</option>' +
    '{{/Skills}}' +
    '</select></td>' +
    '<td><button on-click="@this.edit(i)"></button></td>';

let ractive = new Ractive({
    el: '#table',
    template: DataTpl,
    data: {
        allData: docs
    },
    computed: {
         Skills() {
            // --> this computes a list of possible Skills out of the given Data
        },
        PersonData() {
            // --> this computes a list of Persons
        }
   }
});

The Script works great as long as I have a small amount of persons and skills, but in reality there are about 1.000-1.500 persons and as much skills. So if I try to render it all at once my application crashes out of memory or takes ages to build up the list.

Does anyone know a way to render the skills list - including the preselected values - just on click of my edit button to the table, so the application can manage bigger datasets?


Solution

  • So if I understand correctly, you simply want to show the forms for a row only when you click on edit? You can simply use conditionals and methods to change how the row renders depending on the current values, whether as data or as form.

    Ractive.DEBUG = false;
    const PeopleTable = Ractive.extend({
      data: () => ({
        people: [],
        currentlyEditing: null,
        options: {}
      }),
      isBeingEdited(i){
        return this.get('currentlyEditing') === i;
      },
      template: `
        <table>
          {{#each people }}
            {{#if @this.isBeingEdited(@index) }}
              <tr>
                <td><input type="text" value="{{ name }}"></td>
                <td><input type="text" value="{{ email }}"></td>
                <td>
                  <select value="{{ something }}">
                    {{#each options }}
                      <option value="{{ @key }}">{{ this }}</option>
                    {{/each}}
                  </select>
                </td>
                <td><button type="button" on-click="@this.set('currentlyEditing', null)">Done</button></td>
              </tr>
            {{ else }}
              <tr>
                <td>{{ name }}</td>
                <td>{{ email }}</td>
                <td>{{ options[something] }}</td>
                <td>
                  {{#if !currentlyEditing }}
                  <button type="button" on-click="@this.set('currentlyEditing', @index)">Edit</button>
                  {{/if}}
                </td>
              </tr>
            {{/if}}
          {{/each}}
        </table>  
      `
    });
    
    const App = new Ractive({
      components: { PeopleTable },
      el: 'body',
      data: () => ({
        people: [
          { name: 'bob', email: '[email protected]', something: 1 },
          { name: 'joe', email: '[email protected]', something: 2 },
          { name: 'gin', email: '[email protected]', something: 3 },
        ],
        somethingOptions: {
          '1': 'foo',
          '2': 'bar',
          '3': 'baz'
        }
      }),
      template: `
        <PeopleTable people="{{ people }}" options="{{ somethingOptions }}" />
      `
    });
    <script src="https://unpkg.com/[email protected]/ractive.min.js"></script>

    Ractive can render a ton of things fairly easily and fast, as seen on this dbmonster demo. So if your code is slow, there must be something else going on. Alternatively, you don't have to render 1,500+ things. Let Ractive paginate that list, render 100 at a time or something.