Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

provide 'set' and 'sync' disamgiguation #879

Closed
bmcmahen opened this Issue · 9 comments

4 participants

@bmcmahen

This pertains to an issue I posted on StackOverflow. In short, I typically find the auto-sync features of Meteor to be useful (very) advantageous, but there are times when it would be nice if you could use minimongo to set attributes on the client side, and then later sync those attributes to the server. This, I think, is especially important in two areas: (1) Controlling staged saving of documents while retaining the use of reactive templates, and (2) using Meteor's collections for client-unique display-related purposes, without having this content saved to the server.

Consider an example: I'm currently working on integrating a Leaflet map with Meteor, and I'm using Meteor's observe() callbacks to render markers and polylines onto the Map. If I add a polyline to my Collection, the observe() callback runs, and adds the polyline to the map. It's great and works well. But in creating a new map or (especially) editing an existing map, in order to 'mock up' potential additions/changes, I need to sync these changes to the database. I can't let the user mess around with an existing map and then choose not to save those changes. In order to do the mock up, the collection must be synced -- either that, or I duplicate the content into another client-side only Collection, and then render it... which complicates things. Instead, it would be nice to set the attributes (on the client) and then later, explicitly sync those attributes when the user is happy with their alterations, which is something I could easily do in Backbone, for example.

I also run into this issue sometimes when doing animations or display-related logic. Typically, I'd set a model attribute (say, hide: true), and my template would rerender appropriately. But I don't want hide: true to be an attribute that persists in the data, because it's unique to that user's particular session and template instance.

Anyway, I think having some (optional) set and sync option in minimongo might help in these areas. Or, if anyone has good solutions to these problems right now, I'd be interested to hear.

@scottburch

I decorate those objects with what I call a reactive var. I added a ticket here with the code.

@awwx

I can't let the user mess around with an existing map and then choose not to save those changes.

Well, this is kind of a contrary view, but why force the user to throw away their draft if they aren't ready to publish it yet? (Think of draft emails in gmail, for example). Instead, go ahead and save the draft to the server, but don't make the draft visible to other users. Now the user is free to mess around with a map, take a break, switch to a different computer... and then decide whether to publish ("save") it or not.

@bmcmahen

@awwx I do this when initially creating a new map. The user has a 'publish' option (like gmail, or wordpress) that they can select once they want it available to the public. But this doesn't work as cleanly for editing existing, public maps. I can't remark the existing map as a 'draft' because then it will remove the entire thing from public access. I've considered a 'forking' option, which would duplicate the map, allow the user to make changes, and then have them 'merged' back in... but this gets a bit complicated. It feels like I'm working around Meteor, rather than with it.

@scottburch I'm curious about the reactive var. Any further info?

Thanks for the thoughts, guys.

@awwx

How about an overlay? You have one document which is the published version, and another document which is the changes made by the user: the merged result would be what is displayed. Of course this would also take some implementation effort just like splitting set/sync would... but if there was such an "overlay" feature that you could plug in when you wanted to, it feels like it could be a more modular solution. (Suppose you had "description of party" which you wanted to be a draft and "I'm going to the party" which you did want to take effect right away... now you'd need to be syncing some fields of the document and not others).

@bmcmahen

Nice idea @awwx. I'm beginning to think this is the best option. Another simpler (but more limited) option is to also set Session variables for the various attributes. Then, in the helper, if a Session variable is present I respond with that... if not, I check for the document, and return that attribute. Upon saving, I look through the Session variable and update the document if it exists.

@bmcmahen

I'm going to close this for now, since there are workarounds. I still think this might be an issue that the Meteor devs might want to look into... Cheers.

@bmcmahen bmcmahen closed this
@meawoppl

Good commentary here. Have you thought of creating a seperate collection for the user, then having a Meteor.method to sync one onto the other when appropriate?

Also, if you end up having Leaflet pull images from a meteor directory, the inner Leaflet machinery gets a bit confused by lack of 404 errors. Check out this snippet to get routing right. Codeveloped with @belisarius222.

var connect = __meteor_bootstrap__.require("connect");
var fs = __meteor_bootstrap__.require("fs");

console.log("Starting Up Routing Hack");

__meteor_bootstrap__.app
    .use(connect.query())
    .use(function (req, res, next) {
        Fiber(function () {
        if( /^\/tileImages/.test( req.url )) {
        var checkDirectory = process.cwd + "/public/" + req.url;
        console.log(checkDirectory);
        if (fs.existsSync(checkDirectory)) {
            next();
        }
        else {
            res.statusCode = 404;
            res.end("No Such Image");
        }

        }
        else {
        next();
        }

        }).run();
    });
@bmcmahen

Part of the issue I have, is the way that I've designed my collections so that I can make the most out of Meteor's observe callbacks. I'm mapping trails onto my leaflet map. Each trail is a document in the Trails collection. And each trail has multiple features that are separate documents in a Features collection. My Features subscription is then updated automatically based on the selected Trail, and I use the observe statement to add, update and remove features to the Leaflet map automatically. It works very nicely! My map's state is driven (almost entirely) by changes to my collections. But it's not very easy to just create a duplicate, reactive Session object (or other data source) that feeds my map, because these aren't compatible with Meteor's observe callbacks.

What I've decided to try is basically what @awwx has suggested. When a user seeks to edit a map, they will, essentially, be 'forking' the map -- the trail and the features documents -- and I will then treat the 'forked' map as the currently selected map. I can then update this map using autosave, the changes will show up live (but not on the original map) and the 'save' function will be a merge. It will overwrite the original trail/features.

This will also make it possible to maintain a history of edits, of sort... by maintaining a history of forked documents.

I haven't actually implemented this, but I think it's ultimately the most feasible solution. Once I work out the details, I'll be sure to share them. The repo is here. And for those wondering, Meteor works beautifully with Leaflet.

@bmcmahen

And I haven't had any issues with Leaflet loading images. I just place them within my public folder, and use custom icons (with a custom URL) to point to the correct location.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.