Skip to content
This repository

Multiple Collection Reactive Join #147

Closed
pctj101 opened this Issue May 19, 2012 · 10 comments

7 participants

pctj101 Audrey Roy Tom Wijsman David Greenspan Nick Martin spastai Marcelo Reyna
pctj101
pctj101 commented May 19, 2012

Say I have a few collections:
Chefs
Customers
Dishes

And for each day in my schedule, I need to remember which Chef, is cooking which Dish, for which Customer.

I want to display it like a battleship grid...

Day XYZ

Chef #1
Grid
X axis - Customer
Y axis - Dish

Chef #2
Grid
X axis - Customer
Y axis - Dish

I'm going to use a few templates like:

Template: home
{{#each chefs}}
{{>chef}}
{{/each}}

Template: chef
{{#each customers}}
{{> customer}}
{{/each}}

Template: customer
{{#each dishes}}
{{> dish}}
{{/each}}

Template: dish

<template name='dish'>
  <div class='servethis {{serving}}'>Serve {{name}}</div>
</template>

Well.. by the time I click .servethis, that template has no idea what 'customer' or 'chef' it exists under.

We can pass the chef._id and customer.id into the template using a helper and modifying the dish to include:
dishes = _.map(dishes, function(dish) { return {dish: dish, customer_id = customer.id, chef_id = chef.id}; } );

But now dishes is an Array, not a reactive Collection.... which presents a problem when Customers.find() returns 0 results at first, then 10 results later for example. So it seems modifying the return value of find() is not a good idea when directly used as a template helper.

Alternatively we can cure this by using a single Collection called ChefsCustomerDishes. However to loop this, we'd need to pre-create all the objects for every possible combination of at least Chef + Customer, leaving only the Dish attribute unknown. Otherwise, without pre-creating these objects, there would be nothing for mustache to loop through.

This is particularly problematic when you factor in dates... because precreating all these records for all dates just for the sake of display doesn't seem like the optimal approach.

I've considered using jQuery to suck out all the _id's from the DOM. For example:

<div class='date' data-date='2012-05-15'>
  <div class='chef' data-chefid='1232390582'>
    <div class='customer' data-customerid='23095fffabb'>
      <div class='dish' data-dishid='f00df00d'>
          <div class='servethis'>Click me</div>
      </div>
    </div>
  </div>
</div>

But then I realized that using jQuery to extract my function variables seemed a bit suboptimal.

   serveThis(
                    $(e.target).closest(".date").data("date")
                    $(e.target).closest(".chef").data("chefid")
                    $(e.target).closest(".customer").data("customerid")
                    $(e.target).closest(".dish").data("dishid")
    );

However, even with that solution it leaves the helpers abandoned.. for example

Template.dish.serving = function() {
    // this = dish object, but we don't know what HTML element it is on the dom because 
    //   the same dish object is reused multiple times under different chefs and customers
    day = $("?????"); // hmm!!! 
    chef = $("?????"); // hmm!!! 
    customer = $("?????"); // hmm!!! 

    // Are we serving this dish?
    if (serving) { 
        return "serving";
    } else {
        return "";
    }
}

Perhaps there's a better way?

Tom Wijsman
TomWij commented May 19, 2012

The last thing is not true, since you have set data-dishid you can access it.

Other than that, I think it would be nice to be able to do something like {{#each chefs}}{{#each customer}}{{chefs.name}}{{/each}}{{/each}} as well as something similar when accessing it from Template.dish.serving, like this.ancestor('chefs').name.

pctj101
pctj101 commented May 19, 2012

The problem is that I use the same dish._id in multiple places. So yes I can tell which dish, but not for which Customer or by which Chef, which is the main goal.

Tom Wijsman
TomWij commented May 20, 2012

Uhm, you can...

                $(e.target).closest(".date").data("date")
                $(e.target).closest(".chef").data("chefid")
                $(e.target).closest(".customer").data("customerid")
                $(e.target).closest(".dish").data("dishid")
pctj101
pctj101 commented May 20, 2012

@TomWij / Yes, you can do that when it is a reaction to a mouseclick. But it doesn't work when it's a helper for example to determine if a css classname is added to a

tag for example since {{serving}} isn't passed an event object.
<div class='servethis {{serving}}'>Serve {{name}}</div>
David Greenspan
Owner

In a template, the Handlebars ../ path prefix might help: http://handlebarsjs.com/#paths

In an event handler, there isn't a great way to do this at present. If you want to get the data for a node besides the event target, the function you want is findEventData in packages/liveui/liveui.js. It's a local, inaccessible function, but everything it uses is accessible.

pctj101
pctj101 commented May 24, 2012

@dgreensp Thanks, that's an interesting approach. Let me see how far that gets me.

Nick Martin
Owner
n1mmy commented June 19, 2012

@pctj101 Did handlebars .. do what you want? Did you end up with a workable pattern? Should I close this bug?

Audrey Roy

I'm closing this for now, but @pctj101 if that doesn't work, comment here about what happened and I'll reopen this.

Audrey Roy audreyr closed this August 16, 2012
spastai

Having template

{{#each requests}}
Confirm
{/each}}

Template.parentItem.events({
'click .confirm': function (event, template) {
    console.dir(template.data);
}
});

outputs parentItem properties

Marcelo Reyna

Thank you spastai

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.