Em.computed and, or с инверсией

Ember

Em.computed.and, Em.computed.or — это два отличных макроса, которые реализуют логические функции and, or для любого количества аргументов:

Em.Object.create({
    p1: true,
    p2: false,
    p3: true,
    p4: false,
    p5: Em.computed.and('p1', 'p2', 'p3', 'p4'), // p1 && p2 && p3 && p4
    p6: Em.computed.or('p1', 'p2', 'p4') // p1 || p2 || p4
});

Иногда бывают ситуации, когда внутри and/or нужно брать обратное значение зависимого свойства (проще говоря, не p1, а !p1). В случае, когда такое свойство одно, то можно сделать так:

Em.Object.create({
    p1: true,
    notP1: Em.computed.not('p1'),
    p2: false,
    p3: true,
    p4: false,
    p5: Em.computed.and('notP1', 'p2', 'p3', 'p4'), // !p1 && p2 && p3 && p4
    p6: Em.computed.or('notP1', 'p2', 'p4') // !p1 || p2 || p4
});

А если их больше? Засорять объект бестолковыми свойствами не очень хочется. Как вариант — написать свои and, or, но не с маджонгом и гейшами, а с возможностью указывать, что значение свойства должно браться инвертированным. Пример:

Em.Object.create({
    p1: true,
    p2: false,
    p3: true,
    p4: false,
    p5: Em.computed.customAnd('!p1', 'p2', 'p3', 'p4'), // !p1 && p2 && p3 && p4
    p6: Em.computed.customOr('!p1', 'p2', 'p4') // !p1 || p2 || p4
});

Реализация макросов customAnd, customOr основана на принципе создания макросов с динамическим количеством зависимых свойств в самом Ember (см. исходник). and, or являются результатом выполнения функции generateComputedWithProperties. Доступа извне к ней нет, но это и не особо надо, потому что необходима только идея ее работы. В качестве параметра в нее передается собственно «тело» (функция) с требуемыми вычислениями для computed property. Оно, в свою очередь, оборачивается в Ember.computed и выполняется со значениями зависимых свойств. Эти значения вычисляются в другой функции — getProperties. Она так же недоступна извне. Но, опять-таки, не сильно и нужна 🙂 Все, что делают эти две функции (generateComputedWithProperties, getProperties), нам нужно, но в немного измененном виде:

  • getProperties должна проверять, что значение propertyName может начинаться с «!». Если это так, то значение надо брать инвертированным, а ключ в ret надо делать без «!».
  • generateComputedWithProperties перед выполнением computedFunc.property.apply должна убирать «!» со всех имен зависимых свойств.
const {
  get,
  computed
} = Ember;
 
function getProperties(self, propertyNames) {
  var ret = {};
  for (var i = 0; i < propertyNames.length; i++) {
    var propertyName = propertyNames[i];
    var value;
    if ('!' === propertyName[0]) {
      propertyName = propertyName.substring(1);
      value = !self.get(propertyName);
    }
    else {
      value = self.get(propertyName);
    }
    ret[propertyName] = value;
  }
  return ret;
}
 
function generateComputedWithProperties(macro) {
  return function (...properties) {
    const computedFunc = computed({
      get() {
        return macro.apply(this, [getProperties(this, properties)]);
      }
    });
    var realProperties = properties.slice().invoke('replace', '!', '');
    return computedFunc.property.apply(computedFunc, realProperties);
  };
}

Требуемые условия выполнены и эти функции можно использовать для написания своих customAnd, customOr:

Em.computed.customAnd = generateComputedWithProperties(function (properties) {
  var value;
  for (var key in properties) {
    value = !!properties[key];
    if (properties.hasOwnProperty(key) && !value) {
      return false;
    }
  }
  return value;
});
 
Em.computed.customOr = generateComputedWithProperties(function (properties) {
  var value;
  for (var key in properties) {
    value = !!properties[key];
    if (properties.hasOwnProperty(key) && value) {
      return value;
    }
  }
  return value;
});

Рабочая демка доступ на jsbin — ссылка. При инициализации в консоль выводятся имена зависимых свойств для p4 (and), p5 (customAnd), p6 (or), p7 (customOr). Как видно, никаких «!» там нет — только корректные имена. Нажав на кнопки «Toggle p*» несколько раз, можно убедиться в правильности работы новых макросов.

, , , ,

Оставить комментарий

Top ↑ | Main page | Back