1

I have a few "user settings" that I want to be based on a query I do on start-up. For instance, all my setting fields are checkbox inputs and I'll set them to yes or no based on the preference they chose previously that we have stored in the database.

My query from the client looks as follows:

   Meteor.call('getNotificationPreferences', function(err, result) {
        console.log(result);
        Session.set('aNotificationPreference', result.a);
        Session.set('bNotificationPreference', result.b);
        Session.set('cNotificationPreference', result.c);
        Session.set('dNotificationPreference', result.d);
    });

This call simply pulls that information from MongoDB and sets the session variable correctly, but then I want to use that session variable to set the checkbox field "checked" attribute. I've tried to set this directly with jQuery and also reactively with Meteor. Sometimes this works and sometimes it doesn't.

The HTML looks something like this (using jquery mobile):

<template name="preferences">
    <div data-role="collapsible" data-collapsed="false" data-collapsed-icon="mail" data-expanded-icon="edit">
        <h2>Notifications</h2>
            <div class="ui-field-contain">
                <label for="aNotificationSwitch">A</label>
                <input type="checkbox" data-role="flipswitch" data-theme="b" name="aNotificationSwitch" id="aNotificationSwitch" data-mini="true" checked={{aNotification}}>
            </div>
            <div class="ui-field-contain">
                <label for="bNotificationSwitch">B</label>
                <input type="checkbox" data-role="flipswitch" data-theme="b" name="bNotificationSwitch" id="bNotificationSwitch" data-mini="true" checked="{{bNotification}}">
            </div>
            <div class="ui-field-contain">
                <label for="cNotificationSwitch">C</label>
                <input type="checkbox" data-role="flipswitch" data-theme="b" name="cNotificationSwitch" id="cNotificationSwitch" data-mini="true" checked="{{cNotification}}">
            </div>
            <div class="ui-field-contain">
                <label for="dNotificationSwitch">D</label>
                <input type="checkbox" data-role="flipswitch" data-theme="b" name="dNotificationSwitch" id="dNotificationSwitch" data-mini="true" checked="{{dNotification}}">
            </div>
    </div>
</template>

Then in my JavaScript, I have the following:

Template.preferences.aNotification = function() {
    // Setting directly doesn't work either
    //$('#aNotificationSwitch').prop('checked', Session.get("aNotificationPreference"));
    return Session.get("aNotificationPreference");
};

Can anyone explain why this wouldn't work consistently?

I've also tried doing this the Meteor way, by publishing the preferences as follows:

   Meteor.publish("user-preferences", function () {
    return Meteor.users.find({_id: this.userId},
        {fields: {'notification': 1}});
});
occasl
  • 5,303
  • 5
  • 56
  • 81
  • to check/uncheck checkboxes programmatically: http://stackoverflow.com/a/17027734/1771795 – Omar Sep 25 '14 at 22:55

1 Answers1

2

The checked property of an HTML checkbox should not be set to either "true" or "false" as you're trying to do in your code, but respectively to "checked" and nothing.

<input type="checkbox" checked>

is the same as

<input type="checkbox" checked="checked">

These two examples will set the checkbox in the active (checked) state, although the first example is preferable because it's more concise.

An unchecked checkbox is achieved by not specifying the attribute at all :

<input type="checkbox">

So as far as Meteor is concerned, change your helper to :

Template.preferences.aNotification = function() {
    return Session.get("aNotificationPreference")?"checked":"";
};

And in the HTML, just do :

<input type="checkbox" {{aNotification}}>

From a design perspective, I wouldn't store the user settings in Session variables fetched from the server via a method call, it doesn't sound very meteorish.

Have you considered storing these settings as properties in the Meteor.user() object ? This would involve setting these properties via a method call, and then publishing the properties explicitly to the client.

Server publication :

Meteor.publish("userSettings",function(){
  if(!this.userId){
    this.ready();
    return;
  }
  return Meteor.users.find(this.userId,{
    fields:{
      "profile.settings":1
    }
  });
});

Client :

// this should be put in a iron:router RouteController waitOn !
Meteor.subscribe("userSettings");

Template.preferences.helpers({
  aNotification:function(){
    if(!Meteor.userId()){
      return "";
    }
    // this will fail if the publication is not yet ready
    // either guard accessing sub properties (this is bad)
    // or use iron:router to wait on the subscription (this is good)
    return Meteor.user().profile.settings.a?"checked":"";
  }
});
saimeunt
  • 22,666
  • 2
  • 56
  • 61
  • I tried doing it that way too but still if I refresh the browser the settings won't stick. I suspect it's because of the `Session` variable having to wait to get set and the template is already set. Funny you bring up the Meteor.user() object because that is how I'm storing it, but if I publish that back to the client, how do I set-up the client-side HTML/JS to consume it? – occasl Sep 25 '14 at 23:31
  • Your publish code is broken because your are not returning a cursor but a plain object. – saimeunt Sep 25 '14 at 23:43
  • Have you acknowledged that your helpers supposed to return the status of the checkbox are broken because they are returning a Boolean instead of `"checked"` or `""` ? – saimeunt Sep 25 '14 at 23:48
  • Yeah, so they look like this now: `Template.preferences.aPreference = function() { var user = Meteor.user(); if (user.notification) { return user.notification.a ? "checked" :""; } };` – occasl Sep 25 '14 at 23:49
  • Have you replaced the `checked="{{helper}}"` syntax to plain `{{helper}}` ? – saimeunt Sep 25 '14 at 23:52
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/61944/discussion-between-occasl-and-saimeunt). – occasl Sep 25 '14 at 23:55