Blaze template iterate over object

2020-05-09 21:56发布

I am trying to iterate over an object in blaze template (meteor) , in console I can see the data but nothing on template.How can I get this working ? #each not working , arrayify also didn't work.


Added here from comments:

{{#each contactList}} 
 <tr class="clickable" name="edit-contact" >
   <td>{{name}} </td>
   <td>{{email}} </td>
   <td>{{title}}</td>
   <td>{{phone1}}</td>
   <td>{{phone2}}</td>
   <td>{{phone3}}</td>
 </tr>
{{/each}}

JS:

contactList: function() { 
  $.ajax({ 
    url: Meteor.absoluteUrl()+'contacts/get_by_company/'+Session.get(‌​'company_id'),
    type: 'GET',
    error: function() { callback(); }, 
    success: function(res) { console.log(res); return res; }, 
  });
}

2条回答
欢心
2楼-- · 2020-05-09 22:46

To answer your primary question, the reason your Template is not iterating is because your contactList function is simply not returning anything. And even if it did return something, it still would likely not work because of your approach. Unfortunately, the way to fix this is not just by adding a simple return statement but rather changing your entire approach.

First of all, I would highly encourage you to read and follow the Blaze Tutorial from beginning to end and before returning back to your project. Based on the sample code that you have shared, it is clear that you have misunderstood most of the Meteor basics (which is a shame because Meteor is an extremely powerful and enjoyable framework). Hopefully, I can help clear some things up, but it is definitely essential to understand how Meteor works before trying to jump in.

The biggest issue that I see here is that you are defining API endpoints and using them from your front end. While this is a fairly normal approach in other frameworks/technologies, the relationship between the server and client is completely different in Meteor. So different in fact that only an example will be able to demonstrate this difference.

Based upon what you provided in your question, I have re-written everything to explain how to approach this in Meteor.

First would be the template definition (no real change here).

<template name="manageContacts">
  <table>
    <thead>
      <tr>
        <th>Name</th>
        <th>Email</th>
        <th>Title</th>
        <th>Phone 1</th>
        <th>Phone 2</th>
        <th>Phone 3</th>
      </tr>
    </thead>
    <tbody>
      {{#each contact in contactList}} 
      <tr class="clickable" name="edit-contact" >
        <td>{{contact.name}}</td>
        <td>{{contact.email}}</td>
        <td>{{contact.title}}</td>
        <td>{{contact.phone1}}</td>
        <td>{{contact.phone2}}</td>
        <td>{{contact.phone3}}</td>
      </tr>
      {{/each}}
    </tbody>
  </table>
</template>

The next part however is quite different however. Please note that I don't really recommend combining server and client only code within the same file, but I did so in this instance to save space.

const Contacts = new Mongo.Collection('contacts');

if (Meteor.isServer) {
  Meteor.publish('contacts', function() {
    return Contacts.find();
  });
}

if (Meteor.isClient) {
  Template.manageContacts.onCreated(function() {
    Meteor.subscribe('contacts');
  });

  Template.manageContacts.helpers({
    contactList: function() {
      return Contacts.find({
        company_id: Session.get(‌​'company_id')
      });
    }  
  });
}

What we have going on here is the creation of a contacts mongo collection that will store all the contact data. We then define a publish function on the server that publishes all the contact data to the client. From the client (e.g. the template) we subscribe to the publication (this is how the template acquires its data) and provide a helper function (contactList) to the Template that returns a mongo cursor. Blaze will of course be able to iterate over the cursor and all our contacts will render on the screen.

查看更多
该账号已被封号
3楼-- · 2020-05-09 22:58

The immediate reason for your contactList helper not providing you with your expected list of contacts is that you call an asynchronous function ($.ajax) and do not return anything after that call.

See How do I return the response from an asynchronous call?

Meteor is not aware of when your asynchronous call completes, nor of its result.

If you really need to keep your AJAX call, you could store the result in a ReactiveVar and read it in your helper. Meteor knows that it should automatically re-run your helper whenever a reactive source is updated within that helper function. Therefore, your template will automatically receive the result when it arrives.

import { ReactiveVar } from 'meteor/reactive-var'

var contacts = new ReactiveVar();

Template.templateName.onCreated(function () {
    $.ajax({ 
        url: Meteor.absoluteUrl()+'contacts/get_by_company/'+Session.get(‌​'company_id'),
        type: 'GET',
        error: function() { callback(); }, 
        success: function (res) {
            console.log(res);
            contacts.set(res); // Update the reactive var.
            return res; // Useless.
        }
    });
});

Template.templateName.helpers({
    contactList: function () {
        return contacts.get(); // Will get updated later on and Meteor will automatically refresh the helper.
    }
});

That being said, within Meteor there is hardly a need for REST endpoints, as pointed out by @jordanwillis. If you can re-factor the way you retrieve your contacts list, you can get a much more Meteor-like structure, with all its advantages (real time update, flexibility of manipulating the data client-side, etc.)

查看更多
登录 后发表回答