Где должна вызываться функция, содержащая данные коллекции из подписки Meteor, а также манипуляции с DOM jQuery?

Я новичок в веб-приложениях и наткнулся на проблему в Meteor, для которой я не нашел хорошего решения (пожалуйста, дайте мне знать, если ответ уже существует на https://stackoverflow.com/).

У меня есть страница шаблона profileEdit, которую я хочу обновить значениями по умолчанию из коллекции Meteor.users по мере ее отображения. Это прекрасно работает с помощью помощников по шаблонам для <input type="text">, но для:

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

а также

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

Мне пришлось использовать манипуляции с DOM jQuery, чтобы заставить его работать (это может быть моей настоящей проблемой):

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 , их следует вызывать как помощники (как обсуждалось здесь):

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');, она не обновляет выбранные/отмеченные значения, потому что вызовы jQuery пусты (я подозреваю, что это потому, что они выполняются до того, как HTML будет правильно вынесено). Добавление вызовов функций в onRendered() решает эту проблему, но не работает при обновлении страницы.

JS

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

Есть ли способ объединить эти два вызова функций и обновлять форму, когда страница перенаправляется, а также обновляется? Любые советы о том, как лучше реализовать функциональность обновления в Meteor, также приветствуются.

Отредактировано

После небольшого размышления и некоторой помощи от решения Питера я решил эту проблему, используя вместо этого только помощники пробелов и шаблонов:

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, основанное на коллекции данных, откуда можно будет вызывать этот код? Или всегда можно найти «метеоритный путь» с помощью пробелов?

Заранее спасибо,


person Jonas Sellberg    schedule 24.04.2015    source источник


Ответы (1)


Вы можете использовать помощники шаблонов, которые возвращают true/false непосредственно в шаблоне. В следующем объяснении предполагается, что ваш текущий контекст данных (this) — это ваш пользователь или профиль, в котором есть данные:

Переключатели и флажки

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

а затем объявите помощник шаблона:

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

Атрибут disabled работает точно так же. 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 ..}}, вы можете передать элемент или атрибут элемента помощнику, если хотите. Если вы этого не сделаете, вы все равно можете получить к нему доступ с помощью this внутри кода Javascript. Помощники шаблона обращаются к this как к текущему контексту данных (например, внутри цикла текущий элемент цикла).

person Peter Ilfrich    schedule 24.04.2015
comment
Спасибо, Питер, в итоге я сделал что-то подобное, используя пробелы и помощники по шаблонам, которые решили мою проблему и значительно очистили код. Мне все еще интересно, если бы мне пришлось обновить что-то через jQuery, который опирается на коллекцию данных, откуда бы вы вызвали этот код? Или всегда можно найти «метеоритный путь» с помощью пробелов? - person Jonas Sellberg; 24.04.2015
comment
Я бы ограничил манипуляции с DOM с помощью JQuery только функцией Template.name.rendered и Template.name.events (есть исключения из этого..). Реактивность иногда трудно полностью понять. В основном каждый помощник, обращающийся к базе данных (через коллекции) или сеансу (да, сеанс также является реактивным), повторно выполняется всякий раз, когда базовые данные изменяются. Кроме того, вы можете объявить другие вещи реактивными, используя atmospherejs.com/meteor/reactive-var. - person Peter Ilfrich; 25.04.2015