简体   繁体   English

在Meteor集合中查询afQuickField select的值失败。 为什么?

[英]Querying Meteor collection for values for afQuickField select fails. Why?

Have I made a error in my code or have I found a bug in autoform or Meteor? 我在代码中犯了错误,还是在自动格式化或Meteor中发现了错误? I strongly believe this is my error but cannot find it. 我坚信这是我的错误,但找不到它。

In my Meteor application when querying a collection to provide values for a select input field in a form, the function run on the server returns a correctly populated array but an empty array when run on the client. 在我的Meteor应用程序中,当查询集合以为表单中的选择输入字段提供值时,在服务器上运行的函数返回正确填充的数组,但在客户端上运行时返回空数组。

The application will track medical research subjects. 该应用程序将跟踪医学研究主题。 I have collections for Studies and for study Sponsors. 我有用于研究和研究赞助人的收藏。 When creating or editing a study I want to enter a study sponsor from a list of existing sponsors. 创建或编辑研究时,我想从现有赞助者列表中输入研究赞助者。 Autoform and simple-schema are used to create the create and edit forms. Autoform和simple-schema用于创建创建和编辑表单。 The select input for the study sponsor names is supplied with names in the schema for Studies as an Array given to 'allowedValues'. 研究赞助商名称的选择输入在研究方案中以“允许值”的数组形式提供给研究。 When allowedValues is given an explicit array all works as expected. 当为allowedValues提供了一个显式数组时,所有功能都可以正常工作。 However, when the array is supplied by a function 但是,当数组由函数提供时

sponsorNames = function(){
  sn =  Sponsors.find().map(function(sp){ return sp.sponsorname });
  console.log(sn);
  return sn;
};

that collects the array values from the Sponsors collection the generated list is empty. 从Sponsors集合中收集数组值的生成的列表为空。

The console.log statement in the sponsorNames function prints the populated array to the cli where I am running the application. SponsorNames函数中的console.log语句将填充的数组打印到运行应用程序的cli上。 However, the browser console shows an empty array from the same console.log statement. 但是,浏览器控制台在同一console.log语句中显示一个空数组。 I believe the code is running on both the server and on the client yielding two different results. 我相信代码在服务器和客户端上都运行,产生两个不同的结果。 In all other respects the code runs as it should. 在所有其他方面,代码均应正常运行。

An abbreviated application structure: 缩写的应用程序结构:

research
  both
    collections
      sponsors.js
      studies.js
    router
      routes.js
  client
    sponsor
      events.js
      helpers.js
      templates.html
    study
      events.js
      helpers.js
      templates.html
      subscribe.js
  server
    methods.js
    publish.js
    security.js

both/collections/sponsors.js 两者/collections/sponsors.js

Sponsors = new Meteor.Collection('sponsors');

Schema.Sponsors =  new SimpleSchema({
  sponsorname: {
    type: String,
    label: 'Sponsor Name'
  },
});

Sponsors.attachSchema(Schema.Sponsors);

both/collections/studies.js 两者/collections/studies.js

Studies = new Meteor.Collection('studies');

sponsorNames = function(){
  sn =  Sponsors.find().map(function(sp){ return sp.sponsorname });
  console.log(sn);
  return sn;
};

Schema.Studies =  new SimpleSchema({
  studyname: {
    type: String,
    label: 'Study Name'
  },
  sponsor: {
    type: String,
    label: 'Sponsor',
    allowedValues: sponsorNames(),
  },
  sitenum: {
    type: String,
    label: 'Site Number'
  },
});

Studies.attachSchema(Schema.Studies);

client/study/templates.js 客户/研究/templates.js

<template name='editStudy'>
  {{#autoForm collection=studies id="updateStudyForm" type="update" doc=doc}}
    <fieldset>
      <legend>Edit a Study</legend>
      {{> studyPanel1}}
    </fieldset>
    <button type="submit" class="btn btn-primary">Update</button>
  {{/autoForm}}
</template>

<template name='studyPanel1'>
      {{> afQuickField name="studyname" class="form-control input"}}
      {{> afQuickField name="sponsor" class="form-control input" options='allowed' }}
      {{> afQuickField name="sitenum" class="form-control input"}}
</template>

client/study/helpers.js 客户/研究/helpers.js

Template.addStudy.helpers({
  studies: function(){
    return Studies;
  },
});

Template.editStudy.helpers({
  studies: function(){
    return Studies;
  },
  doc: function(){
    return this;
  }
});

client/study/events.js 客户/研究/events.js

var sponsorHooksObject = {
  after: {
    insert: function(error, result) {
      if (!error) {
        Router.go('sponsorsPage');
      };
    },
    update: function(error, result) {
      if (!error) {
        Router.go('sponsorsPage');
      };
    }
  },
};

AutoForm.hooks({
  insertSponsorForm: sponsorHooksObject,
  updateSponsorForm: sponsorHooksObject
});

client/subscribe.js 客户端/subscribe.js

Meteor.subscribe('Subjects');
Meteor.subscribe('Studies');
Meteor.subscribe('Sponsors');

server/methods.js 服务器/methods.js

Meteor.methods({
  'removeSubjectData': function(id){
    Subjects.remove(id);
  },

  'removeStudyData': function(id){
    Studies.remove(id);
  },

  'removeSponsorData': function(id){
    Sponsors.remove(id);
  },
});

server/publish.js 服务器/publish.js

Meteor.publish('Subjects', function(){
  return Subjects.find({});
});

Meteor.publish('Studies', function(){
  return Studies.find({});
});

Meteor.publish('Sponsors', function(){
  return Sponsors.find({});
});

server/security.js 服务器/security.js

Subjects.permit(['insert', 'update', 'remove']).apply();

Studies.permit(['insert', 'update', 'remove']).apply();

Sponsors.permit(['insert', 'update', 'remove']).apply();

Meteor list: 流星列表:

accounts-password            1.1.1
alanning:roles               1.2.13
aldeed:autoform              5.3.2
aldeed:collection2           2.3.3
aldeed:simple-schema         1.3.3
aslagle:reactive-table       0.8.9
email                        1.0.6
fortawesome:fontawesome      4.3.0
ian:accounts-ui-bootstrap-3  1.2.71
iron:router                  1.0.9
meteor-platform              1.2.2
ongoworks:security           1.2.0
reactive-var                 1.0.5
twbs:bootstrap               3.3.5

I was simply going about this wrong. 我只是想解决这个错误。 The query of the Sponsors collection for sponsorNames to populate the select field belongs in a template helper. 在Sponsors集合中查询的SponsorNames以填充选择字段属于模板帮助器。 With these changes the app works correctly. 通过这些更改,应用程序可以正常运行。

both/collections/studies.js 两者/collections/studies.js

Studies = new Meteor.Collection('studies');

// Remove these:
// sponsorNames = function(){
//   sn =  Sponsors.find().map(function(sp){ return sp.sponsorname });
//   console.log(sn);
//   return sn;
// };

Schema.Studies =  new SimpleSchema({
  studyname: {
    type: String,
    label: 'Study Name'
  },
  sponsor: {
    type: String,
    label: 'Sponsor',
    // Remove this:
    // allowedValues: sponsorNames(),
  },
  sitenum: {
    type: String,
    label: 'Site Number'
  },
});

Studies.attachSchema(Schema.Studies);

client/study/templates.js 客户/研究/templates.js

<template name='editStudy'>
  {{#autoForm collection=studies id="updateStudyForm" type="update" doc=doc}}
    <fieldset>
      <legend>Edit a Study</legend>
      {{> studyPanel1}}
    </fieldset>
    <button type="submit" class="btn btn-primary">Update</button>
  {{/autoForm}}
</template>

<template name='studyPanel1'>
      {{> afQuickField name="studyname" class="form-control input"}}
      {{> afQuickField name="sponsor" class="form-control input"
                       type='select'  options=sponsorNames }}  <!-- Add this: -->
      {{> afQuickField name="sitenum" class="form-control input"}}
</template>

client/study/helpers.js 客户/研究/helpers.js

Template.addStudy.helpers({
  studies: function(){
    return Studies;
  },
});

Template.editStudy.helpers({
  studies: function(){
    return Studies;
  },
  doc: function(){
    return this;
  }
});

// Add this:
Template.registerHelper("sponsorNames", function() {
  return Sponsors.find().map(function(sp){
    return {label: sp.sponsorname, value: sp.sponsorname};
  });
});

You are correct that sponsorNames returns an empty array on the client, this is because the function is called before the subscription is ready. 您没错,SponsorNames在客户端上返回了一个空数组,这是因为在准备好订阅之前调用了该函数。 I wonder if you could do something like this instead (untested): 我想知道您是否可以做这样的事情(未经测试):

Studies = new Meteor.Collection('studies');

Tracker.autorun(function () {

    sn = Sponsors.find().map(function(sp){ return sp.sponsorname });

    Schema.Studies =  new SimpleSchema({
      studyname: {
        type: String,
        label: 'Study Name'
      },
      sponsor: {
        type: String,
        label: 'Sponsor',
        allowedValues: sn,
      },
      sitenum: {
        type: String,
        label: 'Site Number'
      },
    });

    Studies.attachSchema(Schema.Studies, { replace: true });

});

To explain: 解释:

Tracker.autorun will rerun the code every time any dependencies are invalidated. 每当任何依赖项无效时,Tracker.autorun都会重新运行代码。 The dependency here is the Sponsors.find() query so once the subscription loads the result of Sponsors.find() will change and the tracker function will rerun. 这里的依赖项是Sponsors.find()查询,因此一旦订阅加载,Sponsors.find()的结果将更改,并且跟踪器函数将重新运行。

Attaching the schema with replace:true will replace the entire schema each time, so allowedValues: [] will be replaced with the new array of sponsors. 每次将模式replace:true都会替换整个模式,因此, allowedValues: []将被新的发起人数组替换。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM