Table with links as rows


#1

Hey,

I have a basic question:

I have a table, each entry should be a clickable link. More precisely, the whole row should be clickable. Does Meteor come with some predefined function for this?

My table and the currently not working solution looks like this:

        <table class="highlight">
            <thead>
            <tr>
                <th>Field 1</th>
                <th>Field 2</th>
                <th>Field 3</th>
                <th>Field 4</th>
            </tr>
            </thead>
            <tbody>

                {{#each item in database}}
                <tr>
                    <a href="{{pathFor 'Itemdetail.show' _id=item._id}}">
                        <td>{{item.name}}</td>
                        <td>{{item.price}}</td>
                        <td>{{item.amount}}</td>
                        <td>{{item.text}}</td>
                    </a>
                </tr>
                {{/each}}

            </tbody>
        </table>

Thanks in advance!


#2

To specify the problem:

The issue that a table row cannot be turned into a clickable link just by adding <a> tags before each row is not related to Meteor or Blaze at all, as it simply can not be done like this. As a possibly solution, I could add a click function to each <td> element, like this:

<td class="clickable_Item" data-href="{{pathFor 'Itemdetails.show' _id=item._id}}">{{item.itemId}}</td>

and add a click logic inside the template event:

Template.itemdata.events({
    'click .clickable_Item': function(evt) {
        window.open($(evt.target).attr("data-href"), '_self');
    }
});

This works.

However, the problem is: the whole page will reload, and the data appearning on the next page will load slower (possibly due to Minimongo not being used)?!

So how do I solve this best in Meteor and Blaze? Maybe there are some packages for this?

Thanks!


#3

You almost never use regular anchor elements in Blaze. Assign events handlers instead.

For instance like this:

<tr class="item-row">
  <td>{{item.name}}</td>
  <td>{{item.price}}</td>
  <td>{{item.amount}}</td>
  <td>{{item.text}}</td>
</tr>

Template.itemdata.events({
    'click .item-row': function(evt) {
        ... 
        // do routing here, e.g. FlowRouter.go('...')
        ...
    }
});

Inside an event handler, this relates to the clicked element. In your case, it’s the item element that has been clicked. So it’s quite easy to get its data and do routing based on this. No need for pathFor.

Disclaimer: I have never used this on <tr> elements. But I don’t see any reason why it shouldn’t work. If it does not, you could use the selector click .item-row td instead.


#4

Thanks alot!

But how can I then access the _id in the Template?

<tr class="item-row">
  <td>{{item.name}}</td>
  <td>{{item.price}}</td>
  <td>{{item.amount}}</td>
  <td>{{item.text}}</td>
</tr>
Template.itemdata.events({
    'click .item-row'() {
        FlowRouter.go('Itemdetail.show', { _id: ???});
    }
});

Wouldn’t I need to pass the _id of the particular item to the template event?

Thanks!


#5

You need to use a template for rendering a row. Then, the _id will be available in the template handler code.

So instead of

<template name="blah">
  {{#each item in database}}
    <tr>
      ...
    </tr>
  {{/each}}
</template>

use something like this:

<template name="blah">
  {{#each item in database}}
    {{> outputRow item=item}}
  {{/each}}
</template>

<template name="outputRow">
  <tr>
    ...
  </tr>
</template>

and then you’re able to access the document in the template lifecycle methods:

Template.outputRow.onCreated(function outputRowOnCreated() {
  console.log(this.data.item);
});

Template.outputRow.events({
  'click .item-row'(e, ti) {
    console.log(ti.data.item);
  },
});

#6

You can access the _id without a template too!

Template.itemdata.events({
    'click .item-row'() {
      console.log(this._id)
    }
});

this inside events should refer to the clicked item


#7

Thanks for the input!

robfallows approach worked, hertebys suggestion does not. I do not understand why though.

(I have changed the names of the database items a little):

Working solution:


<template name="userdata">
            {{#each user in userbase}}
                {{> outputRow user=user}}
            {{/each}}
</template>

<template name="outputRow">
    <tr class="user-row">
        <td>{{user.userId}}</td>
        <td>{{user.address}}</td>
    </tr>
</template>

Template.outputRow.events({
    'click .user-row'(e, ti) {
        console.log(ti.data.user._id);
    },
});

Promising solution which does not work and returns an undefined object:

<template name="userdata">
            {{#each user in userbase}}
                <tr class="user-row">
                    <td>{{user.userId}}</td>
                    <td>{{user.address}}</td>
                </tr>
            {{/each}}
</template>

Template.userdata.events({
    'click .user-row'() {
        console.log(this._id)
    },
});

Why can I not access the user in the second example?

Secondly, I would like to know more about the paramters passed to the function:

'click .item-row'(e, ti) {
        console.log(ti.data.user._id);
},

What exactly is passed by e and ti? I mean, why are two parameters used to pass the object?

Thanks in advance!


#8

Hmm it doesn’t? :thinking: I haven’t used Blaze in a while but I thought that should work…

The first argument (e) is the event. It’s a regular js event object. The second argument (ti) is the template instance.


#9

It’s a bug I guess. The following works:

                {{#each userCollection}}
                    <tr class="user-row">
                        <td>{{userId}}</td>
                        <td>{{address}}</td>
                    </tr>
                {{/each}}

Template.userdata.events({
  'click .user-row': function () {
    FlowRouter.go('Userbasedetail.show', {_id: this._id});
  },
});