0

I have two collections:

Group = {
  users: [Array_of_User]
}

User = {
  name: _string_
}

I'm listing groups ans I'm trying to know in the template if a user is in the groups:

mytemplate.js

Template.mytemplate.helpers({
  groups: function(){
      return Groups.find();
  },
  currentUsername: 'test'
});

mytemplate.html

<template name="main">
  <ul>
    {{#each groups}}
    <li>
      {{#if [the group contains currentUsername] }}
      contains
      {{else}}
      doesn't contain
      {{/if}}
    </li>
    {{/each}}
  </ul>
</template>

The question is: what can I put on the helpers and instead of [the group contains currentUsername] to make it work?

Also, I'm not saying this is the way to do it. I'm open to any suggestions even if it means I have to change a lot.

Erdal G.
  • 2,694
  • 2
  • 27
  • 37
  • @Kyll I don't think so, because when you have this problem you also have to know what to put in the helper's part. So, it's not an only-js problem but more related to Meteor. Which by the way is solved well in the two responses. I've just edited question accordingly. – Erdal G. Nov 12 '15 at 12:19
  • I know but you figured the whole helper part pretty well. The only logic missing was the one of actually finding the element in the array, hence the duplicate suggestion. – Kyll Nov 12 '15 at 12:26
  • Well, in my case I didn't know I had to use `this` for the data scope in the helper part. So, it was actually really helpful. But to know if people coming here will do it to know only the js part, I have no idea. You may be right. – Erdal G. Nov 12 '15 at 12:52

2 Answers2

2

You could use the Underscore.js function _.findWhere(list, properties) to check whether the group contains the username:

if (Meteor.isClient) {
    Template.main.helpers({
        groups: function() {
            return Groups.find();
        },
        currentUsername: 'Matthias',
        isInGroup: function(username) {
            return !!_.findWhere(this.users, {
                name: username
            });
        }
    });
}

<template name="main">
  <ul>
    {{#each groups}}
    <li>
      {{#if isInGroup currentUsername}}
        contains
      {{else}}
        doesn't contain
      {{/if}}
    </li>
    {{/each}}
  </ul>
</template>

if (Meteor.isServer) {
    Meteor.startup(function() {
        Groups.insert({
            users: [{
                name: "Matthias"
            }, {
                name: "Angie"
            }]
        });
    });
}

Here is a MeteorPad.

Matthias A. Eckhart
  • 5,136
  • 4
  • 27
  • 34
  • Why add in an external library just to perform an iteration, which can easily be accomplished with JS. – Ruby_Pry Nov 11 '15 at 19:15
  • 1
    As you may know, Meteor core depends on [Underscore.js](http://underscorejs.org). As a result, you can use this library on the server as well as on the client. However, you don't have to. I am just proposing a different approach, which is in my opinion more intuitive than performing an iteration. – Matthias A. Eckhart Nov 11 '15 at 19:31
  • 1
    I think it's generally preferable to always use some kind of functional library to do this kind of thing, personally I use ramda, which is a lot nicer than underscore. But underscore works and is prepackaged.... be nicer if the answer used newer syntax in the helpers groups() {} instead of groups: function() {} etc... – Keith Nicholas Nov 11 '15 at 22:26
  • 1
    Works like a charm (there is a small glitch though: it should be `name: unsername`). Actually, before posting I did use JS .forEach iteration almost like this answer. My error was not using `this` on the Template helper side. – Erdal G. Nov 12 '15 at 09:47
  • 1
    Needz moar underscore: `_.contains(_.pluck(this.users, 'name'), username)` with [`_.pluck`](http://underscorejs.org/#pluck) and [`_.contains`](http://underscorejs.org/#contains). – Kyll Nov 12 '15 at 13:42
  • @erdalg - if you read my answer, I explain why you need to use 'this'. And that is the core of this question, not whether you should use findWhere or forEach. I'm shocked people are more concerned with the implementation than actually explaining the logic and concepts here. – Ruby_Pry Nov 12 '15 at 15:57
0

Within your each block, your data context becomes the current group that is being iterated over. Therefore you can write a helper method that references that current data context like this:

userInGroup: function(username) {
  var userInGroup;
  this.forEach(function(groupUsername) {
    if (username == groupUsername) {
      userInGroup = true;
    }
  };
  return userInGroup;
}

'this' within the userInGroup template helper references the current group as long as you use the helper within an a group iteration.

You can then use the helper like this:

<template name="main">
  <ul>
    {{#each groups}}
    <li>
      {{#if userInGroup currentUsername}}
      contains
      {{else}}
      doesn't contain
      {{/if}}
    </li>
    {{/each}}
  </ul>
</template>
Ruby_Pry
  • 237
  • 1
  • 10
  • (I continue here) I totally agree, that's the limits of SO as questions must be very sharp. Moderators are eagerly waiting more points :p Next time I'll post my code! :) By the way, I was shocked someone gave you a down vote. We can debate on which solution is better, but yours is certainly not 'bad'... – Erdal G. Nov 12 '15 at 16:16
  • 1
    Yea, I have no idea why anyone would down vote my answer. @matthias' answer is more concise and he correctly informed me that underscore is already added as a dep into Meteor. However, my answer offers value for a random viewer who stumbles upon this question because I explain the underlying logic. – Ruby_Pry Nov 12 '15 at 16:46