0

I have a template that I am loading from a route like so:

this.route('formEdit', {
  path: '/admin/form/:_id',
  data: function() { return Forms.findOne({_id: this.params._id}); },
  onBeforeAction: function() { AccountUtils.authenticationRequired(this, ['ADMIN']); }
});

In which I have a template defined like:

<template name="formEdit">
  <div id="formContainer">
    ...
    {{#each header_fields}}
      <div class="sortable">
        {{> headerFieldViewRow }}
      </div>
    {{/each}}
  </div>
</template>

And:

<template name="headerFieldViewRow">
  {{#with header_field}}
    ...
  {{/with}}
</template>

I then make the container around all the header fields sortable using jQuery UI Sortable:

Template.formEdit.rendered = function() {
    $('.sortable').sortable({
        axis: "y",
        stop: function(event, ui) {
            var form = Blaze.getData($('#formContainer')[0]);
            var newFormHeaders = [];
            $('#headerFieldsTable div.headerField').each(function(idx, headerFieldDiv) {
                var header = Blaze.getData(headerFieldDiv);
                header.sequence = idx;
                Meteor.call('saveHeaderField', header);
                newFormHeaders.push({header_field_id: header._id});
            });
            form.header_fields = newFormHeaders;
            Meteor.call('saveForm', form);
        }
    });
}

Basically, when sorting stops, loop through all the headers, getting the data for each and updating the sequence number, then re-build the array in Forms and save them back. In the server code I have printouts for the two save calls, and the do properly print out the correct order of both the headers and the form.

The problem I am running into is that, after sorting, the visual display of the form and it's headers "snaps" back to the pre-sorted state, even though the data in the DB is correct. If I simply reload the form, either by hitting enter in the Address bar or by simply re-loading it from the menu, everything is displayed correctly. It's as if the reactive piece isn't working.

I have noted that I am getting an error when I update the client code in my server log that reads:

=> Client modified -- refreshing
I20141010-18:25:47.017(-4)? Failed to receive keepalive! Exiting.
=> Exited with code: 1

I don't think this is related as I was getting that error prior to adding this sorting code.

Update: Adding code for saveForm and saveHeader

saveForm:

// Saves the Form to the DB
saveForm: function(params) {
    // Structure the data to send
    var formEntry = {
        title: params.title,
        client_id: params.client_id,
        header_fields: params.header_fields,
        form_fields: params.form_fields,
        created_by: Meteor.userId(),
        created_on: new Date()
    };

    if (params._id == null) {
        console.log("Saving new Form entry: %j", formEntry);
        formEntry._id = Forms.insert(formEntry);
    } else {
        formEntry._id = params._id;
        console.log("Updating Form entry: %j", formEntry);
        Forms.update({_id: formEntry._id}, formEntry);
    }

    return formEntry;
}

saveHeader:

// Saves the HeaderField to the DB
saveHeaderField: function(params) {
    // Structure the data to send
    var headerFieldEntry = {
        label: params.label,
        field_type: params.field_type,
        field_options: params.field_options,
        form_id: params.form_id,
        required: params.required,
        allows_pictures: params.allows_pictures,
        record_geo: params.record_geo
    };

    if (params._id == null) {
        console.log("Saving new HeaderField entry: %j", headerFieldEntry);
        headerFieldEntry._id = HeaderFields.insert(headerFieldEntry);
    } else {
        headerFieldEntry._id = params._id;
        console.log("Updating HeaderField entry: %j", headerFieldEntry);
        HeaderFields.update({_id: headerFieldEntry._id}, headerFieldEntry);
    }

    return headerFieldEntry;
}
CodeChimp
  • 8,016
  • 5
  • 41
  • 79

1 Answers1

0

I think the issue here is that Meteor.call will run on the server - you either need to use a callback or invalidate your template, if you want to return a value Meteor.call. From the docs:

On the client, if you do not pass a callback and you are not inside a stub, call will return undefined, and you will have no way to get the return value of the method. That is because the client doesn't have fibers, so there is not actually any way it can block on the remote execution of a method.

There is more info in this answer and this answer and the Meteor.call docs.

Hope that helps!

Community
  • 1
  • 1
Jordan Davis
  • 1,271
  • 14
  • 24
  • Is it because I am using a `findOne()` and instead of using `find()` to get a cursor in my route? – CodeChimp Oct 12 '14 at 18:13
  • I think that your route is fine. Your code works in the sense that it is persisting to the DB, but the Meteor.call won't update your view if called from the Template context. Could you post the code for the saveForm meteor method and the saveHeaderField method? – Jordan Davis Oct 13 '14 at 01:36
  • I edited the original post to include these two methods. In essence they perform an upsert and return the resulting record. One question I have is, how does one go about invalidating the Template? I don't see any methods to do that. – CodeChimp Oct 13 '14 at 15:15