应该在哪里调用包含来自 Meteor 订阅的 Collection 数据以及 jQuery DOM 操作的函数?

Where should a function be called containing Collection data from a Meteor subscription as well as jQuery DOM manipulation?

我是 Web 应用程序的新手,在 Meteor 中偶然发现了一个问题,我还没有找到好的解决方案(如果 https://whosebug.com/ 上已经有答案,请告诉我)。

我有一个 profileEdit 模板页面,我想在呈现时使用 Meteor.users 集合中的默认值进行更新。使用 <input type="text"> 的模板助手可以正常工作,但对于:

<select class="form-control" name="profileNamePrefix" id="profileNamePrefix">

<label><input type="radio" name="profileGender">Male</label>

我必须使用 jQuery DOM 操作才能让它工作(这可能是我真正的问题):

JS

// GLOBAL FUNCTIONS
updateSelectedOption = function() {
    var currentUserId = Meteor.userId();
    var currentUser = Meteor.users.findOne(currentUserId);
    var profileTitleOptions = $('#profileNamePrefix').children();
    var status = false;
    for (var i = 0; i < profileTitleOptions.length; i++) {
      if (currentUser && currentUser.profile &&
          currentUser.profile.title === profileTitleOptions[i].value) {
        profileTitleOptions[i].selected = true;
        statue = true;
        break;
      };
    };
    return status;
};

updateCheckedRadio = function() {
    var currentUserId = Meteor.userId();
    var currentUser = Meteor.users.findOne(currentUserId);
    var profileGenderRadios = $('input:radio[name="profileGender"]');
    var status = false;
    for (var i = 0; i < profileGenderRadios.length; i++) {
      if (currentUser && currentUser.profile && 
          currentUser.profile.gender === $(profileGenderRadios[i].closest('label'))[0].innerText) {
        $(profileGenderRadios[i]).attr("checked", "checked");
        status = true;
        break;
      };
    };
    return status;
};

这些函数有效,但我不知道在哪里调用函数。由于他们从 Meteor.users Collection 获取数据,他们应该被称为助手(如讨论的 here):

JS

Template.profileEdit.helpers({
  'selectOptionIfTitleIs': function() {
    return updateSelectedOption();
  },
  'checkRadioIfGenderIs': function() {
    return updateCheckedRadio();
});

HTML

<template name="profileEdit">
  <form role="form">
    <div class="row">
      <div class="col-sm-2">
        <div class="form-group">
          <label>Title</label>
          <select class="form-control" name="profileNamePrefix" id="profileNamePrefix">
            <option value="Mr">Mr.</option>
            <option value="Ms">Ms.</option>
            <option value="Mrs">Mrs.</option>
            <option value="Dr">Dr.</option>
            <option value="Prof">Prof.</option>
            <option value="Sir">Sir</option>
          </select>
          {{#if selectOptionIfTitleIs}}
          {{/if}}
        </div>
      </div><!-- /.col-sm-2 -->
      <div class="col-sm-2">
        <div class="radio">
          <label><input type="radio" name="profileGender">Male</label>
        </div>
        <div class="radio">
          <label><input type="radio" name="profileGender">Female</label>
        </div>
      </div><!-- /.col-sm-2 -->
      {{#if checkRadioIfGenderIs}}
      {{/if}}
    </div>
  </form>
</template>

这在刷新页面时有效,但是当它通过 Router.go('profileEdit'); 从导航栏重定向时,它不会更新 selected/checked 值,因为 jQuery 调用是空的(我怀疑这是因为它们是在 HTML 正确呈现之前执行的)。将函数调用添加到 onRendered() 可以解决此问题,但在刷新页面时不起作用。

JS

Template.profileEdit.onRendered(function() {
  updateSelectedOption();
  updateCheckedRadio();
});

有没有办法统一这两个函数调用并在页面重定向和刷新时保持表单更新?关于如何在 Meteor 中以更好的方式实现更新功能的任何提示也很受欢迎。

已编辑

经过一番思考并从 Peter 的解决方案获得一些帮助后,我最终通过仅使用空格键和模板助手解决了这个问题:

HTML

<form role="form">
    <div class="col-sm-2">
      <div class="form-group">
        <label>Title</label>
        <select class="form-control" name="profileNamePrefix" id="profileNamePrefix">
        {{#each namePrefixes}}
          <option value="{{value}}" selected="{{prefixIsSelected}}">{{name}}</option>
        {{/each}}
        </select>
      </div>
    </div><!-- /.col-sm-2 -->
    <div class="col-sm-2">
      {{#each genders}}
        <div class="radio">
          <label><input type="radio" name="profileGender" checked="{{genderIsChecked}}">{{name}}</label>
        </div>
      {{/each}}
    </div><!-- /.col-sm-2 -->
</form>

JS

Template.profileEdit.helpers({
  namePrefixes: [{
      name: "Mr.",
      value: "Mr"
    },
    {
      name: "Ms.",
      value: "Ms"
    },
    {
      name: "Mrs.",
      value: "Mrs"
    },
    {
      name: "Dr.",
      value: "Dr"
    },
    {
      name: "Prof.",
      value: "Prof"
    },
    {
      name: "Sir",
      value: "Sir"
    }
  ],
  genders: [{name: "Male"},
            {name: "Female"}
  ],
  'prefixIsSelected': function() {
    var currentUserId = Meteor.userId();
    var currentUser = Meteor.users.findOne(currentUserId);
    return currentUser && currentUser.profile && currentUser.profile.title === this.value;
  },
  'genderIsChecked': function() {
    var currentUserId = Meteor.userId();
    var currentUser = Meteor.users.findOne(currentUserId);
    return currentUser && currentUser.profile && currentUser.profile.gender === this.name;
  }
});

这样,当重定向或刷新时表单会正确更新。剩下的唯一问题是,如果我被迫通过依赖于数据集合的 jQuery 更新某些内容,那么从哪里调用该代码?还是总是可以使用空格键找到 'Meteor way'?

提前致谢,

您可以直接在模板中使用 return true/false 的模板助手。 以下解释假定您当前的数据上下文 (this) 是您的用户或具有数据的配置文件:

单选按钮和复选框

<input name="gender" type="radio" checked="{{genderCheck 'male'}}"/> Male

然后声明一个模板助手:

genderCheck: function(value) {
    return (this.profile.gender == value);
}

禁用属性的工作方式相同。 Blaze(Meteor 模板)在交付 DOM.

时删除过时的选中和禁用属性

选择

<select name="salutation">
  <option selected="{{checkSalutation 'Mr'}}">Mr</option>
  <option selected="{{checkSalutation 'Mrs'}}">Mrs</option>
  ..
</select>

还有帮手:

checkSalutation: function(value) {
    return (this.profile.salutation == value);
}

如果您有一个 {{#each ..}} 循环,您可以根据需要将元素或元素的属性传递给助手。如果您不这样做,您仍然可以使用 Javascript 代码中的 this 访问它。模板助手将 this 称为当前数据上下文(例如,在循环内当前循环元素)。