I've looked around quite a bit for Meteor examples showing how to implement app settings and user specific settings. The only thing I found was Telesc.pe. And it uses a Settings
collection. However, it only has a global (meaning same for everyone) app settings.
Building on that example, I've created my own settings
collections which is available on both the server and the client.
// Server and Client
Settings = new Meteor.Collection('settings');
In each Settings
record there is a userId
field which is equal to 'Default' or the user's id.
{
...
userId: 'Default' // <-- 'Default' or Meteor.userId()
}
I have my publish function publishing both the Default (app) settings AND the user's settings. (Side note: in this app everyone IS logged in, no guests allowed)
// Server
Meteor.publish('settings', function() {
return Settings.find({userId: {$in: [this.userId, 'default']}});
});
The idea here is that the user will use the Default settings until they change a settings thereby reducing the number of records in the collection.
I've also tried to abstract away a lot of the tedious stuff and create a few helpers to get and set settings for the user.
// Server and Client
// get user specific settings, fallback to default settings
// (not sure if this is the best way, but it works)
settings = function() {
return Settings.findOne({userId:Meteor.userId()})
|| Settings.findOne({userId:'default'});
};
// Get value of a specific setting
getSetting = function(key) {
return Session.get('settingsLoaded') ? settings()[key] : undefined;
};
// Set value of a specific setting
setSetting = function(key, value) {
// bunch of logic here to see if a user specific record exists
// if so, do update
// if not, do insert
};
So far, this implementation seems to be working fairly well. I can set and get settings in the console via m helper functions.
// in the console...
setSetting('foo', 'bar');
getSetting('foo') // == 'bar'
The issue I'm having happens when I go to start making my app act differently based on certain settings. For example, I have a template called 'phrases' with a variable inside called 'phrases'. I want to change how they are sorted based on the user's settings.
Template.phrases.phrases = function () {
var sort = {};
var sortKey = getSetting('sortPhrasesBy'); // if I console.log this it is ALWAYS equal to 'title', 'body', or 'date', which is what I want.
sort[sortKey] = 1;
// returns cursor with all phrases, sorted
return Phrases.find({}, {sort:sort});
};
Except that I keep getting Deps
exceptions and I can't tell what is wrong.
Exception from Deps recompute: TypeError: Cannot read property 'nodeName' of null
at Patcher.match (http://localhost:3000/packages/spark.js?3a050592ceb34d6c585c70f1df11e353610be0ab:1540:12)
at http://localhost:3000/packages/spark.js?3a050592ceb34d6c585c70f1df11e353610be0ab:1364:23
at visitNodes (http://localhost:3000/packages/spark.js?3a050592ceb34d6c585c70f1df11e353610be0ab:1320:11)
at visitNodes (http://localhost:3000/packages/spark.js?3a050592ceb34d6c585c70f1df11e353610be0ab:1321:9)
at visitNodes (http://localhost:3000/packages/spark.js?3a050592ceb34d6c585c70f1df11e353610be0ab:1321:9)
at visitNodes (http://localhost:3000/packages/spark.js?3a050592ceb34d6c585c70f1df11e353610be0ab:1321:9)
at visitNodes (http://localhost:3000/packages/spark.js?3a050592ceb34d6c585c70f1df11e353610be0ab:1321:9)
at patch (http://localhost:3000/packages/spark.js?3a050592ceb34d6c585c70f1df11e353610be0ab:1334:3)
at http://localhost:3000/packages/spark.js?3a050592ceb34d6c585c70f1df11e353610be0ab:698:7
at LiveRange.operate (http://localhost:3000/packages/liverange.js?b3097d72d458e645fd4f0021c8ff5189abe8d98a:491:9)
I have no idea what could be causing this. :/
However, this code actually works! It does actually sort the phrases based on what the user has set. But in the console I can see this exception being thrown every time the settings are changed. First load is fine.
So, am I doing something fundamentally wrong here? I must admit I don't yet have my head fully wrapped around what Meteor is doing behind the curtain yet.
I don't know if this is helpful or not. But before I tried implementing a settings collection, I used the Session
object. So I had something like this:
// on client
Session.setDefault('sortPhrasesBy', 'title);
Template.phrases.phrases = function () {
var sort = {};
var sortKey = Session.get('sortPhrasesBy');
sort[sortKey] = 1;
// returns cursor with all phrases, sorted a certain way
return Phrases.find({}, {sort:sort});
};
This worked without issue. It's just not real flexible.
Is there another way I should be doing this? I'd love to know what the guys building meteor are doing for settings in there personal testing/projects if anyone happens to know.
Sorry so long of a post, I was trying to anticipate what questions might be asked about what I already tried and such.
Thanks for any help you can provide!
userId() reactive function will give you the ID of the currently logged in user.
Meteor is a full-stack JavaScript platform for developing modern web and mobile applications. Meteor includes a key set of technologies for building connected-client reactive applications, a build tool, and a curated set of packages from the Node. js and general JavaScript community.
Meteor makes developing web applications simple. It's easy to learn, and comes with a pre-built arsenal of powerful functionalities.
Meteor, or MeteorJS, is a partly proprietary, mostly free and open-source isomorphic JavaScript web framework written using Node.js. Meteor allows for rapid prototyping and produces cross-platform (Android, iOS, Web) code.
The Meteor Accounts system (ex. accounts-password) has the concept of user-specific settings built-in as the 'profile' field of the user object. It is automatically published and is reactive as well (since Meteor.user() is reactive).
Here are the relevant docs: http://docs.meteor.com/#meteor_user
Regarding the "nodeName" error, it is hard to debug but generally when I get that error it is because I am trying to access part of the DOM in a template helper that doesn't actually exist. I've also seen it when I accidentally had two DOM elements with the same ID (fairly easy to do with sub-templates).
To track it down I remove code until it stops happening then add it back piece-by-piece until I find the root cause.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With