Что формирует заголовок в my = f.input :title?

У меня есть представление:

- entry = f.object
- kind = entry.new_record? ? '' : entry.kind

tr[class = "entry_row f-order-entry f-order-nested-entry" data-kind=(kind.to_s)
   class=(entry.created_without_order? ? 'entry_no_order' : '')
   class=(entry.kind == Entry::COMPLEX ? 'f-ignore-price f-complex-order-entry' : '' )]

  td.new-entry
    - if entry.created_without_order?
      = image_tag('new-box.png', size: '30x25', alt: 'new')
  td.hidden

    = f.input :id
    = f.input :entry_type_id
    = f.input :clinic_id
    = f.input :client_id
    = f.input :order_id
    = f.input :kind
    = f.input :number
    = f.input :state
    = f.input :discount_disabled, as: :string
    = f.input :final_price, input_html: { class: 'f-order-entry-final-price' }
    = f.input :sum, input_html: { class: 'f-order-entry-sum' }
    = f.input :discount_sum, input_html: { class: 'f-order-entry-discount-sum' }
    = f.input :date, as: :string, input_html: { class: 'f-order-entry-date' }

    = new_fields_template(f, :members, entry.members.length)
    = new_fields_template(f,
                          :consumables,
                          entry.consumables.length,
                          nil,
                          variables: { parent: :entry })

  td.entry-title.tooltip-bottom

    = f.input :title, input_html: { readonly: true, title:  }
    = entry.title   
    .toggle-content-button
      span.toggle-content-button-number
      span.toggle-content-button-icon

  = edit_order_entry_performer f, @performers
  = edit_order_entry_assistant f, @assistants
  = edit_order_entry_referral f, @referrals
  = edit_order_entry_store f, @stores

эта линия

= f.input :title, input_html: { readonly: true, title: }

формирует следующую разметку

<input class = "form-control string required" autocomplete = "off" readonly = "readonly" title = "" type = "text" name = "order[entries_attributes][0][title]" id = "order_entries_attributes_0_title">

получаем динамический список услуг (элементы добавляются по клику из каталога), мне нужно получить на вход атрибут title, такой же как и само название (названия длинные, не всегда помещаются на экране, всплывающая подсказка отображается позже из заголовка (это настроено, мне нужно подставить только значение, равное названию самого сервиса)

вот js, который рисует линии после добавления из каталога (каталога)

FormFactory.nestedFields = function (params) {
  //var form = params.form
  var msgPrefix = 'page.form.' + params.model + '.nestedFields.'

  var settings = params.nestedFields
  var template = params.form.find('._template_' + settings.model)

  var model = settings.model

  PubSub.subscribe(msgPrefix + 'add', function (msg, data) {
    var item = data.item
    var generated = template.railsTemplate(model)
    var fields = generated.fields
    var html = generated.html

    var response = $.extend(data, {
      html: html,
      fields: fields,
      item: item,
      msgFrom: msg
    })

    PubSub.publish(msgPrefix + 'render', response)
  })

  return {

  }
}

js, которые формируют всю таблицу (здесь интересует только исполнитель записи — имя сервиса, который мне нужно добавить в

FormFactory.orderEntryList = function (params) {
  var ENTRY_NOT_READY = 1
  const SELECT_UPDATE_DELAY = 300

  var msgPrefix = 'page.form.' + params.model + '.orderEntryList.'

  const form = params.form
  var container = params.orderEntryList.container
  var attributes = {}
  var entriesTemplate = $('._template_entries')
  var round = Utils.moneyRound

  //
  // core funcs
  //

  var init = function () {
    container.find('.entry_row').each(function (i, e) {
      var row = $(e).nestedFieldSet()
      if (gon.specific.order_locked) row.lockFromBillingChanges()
      row.init()
      row.hideContent()
      if (row.isComplex()) row.showContent()
    })

    triggerListChanged()
    updateSelects()
  }

  var updateIndexesTimeout
  var updateIndexes = function () {
    if (updateIndexesTimeout) clearTimeout(updateIndexesTimeout)

    // massive complex addition calls updateIndex too many times and freezes ui
    updateIndexesTimeout = setTimeout(function () {
      container[0].querySelectorAll('.entry_row').forEach(function (e, i) {
        var row = $(e).nestedFieldSet()
        row.setIndex(i)
        row.init()
      })
    }, 10)
  }

  var buildItem = function (proto) {
    let rez = {
      amount: proto.amount,
      assistant_id: attributes.assistant_id,
      client_id: attributes.client_id,
      clinic_id: attributes.clinic_id,
      date: attributes.date,
      discount_disabled: proto.discount_disabled,
      discount_percent: proto.discount_disabled
        ? 0
        : (attributes.discount_percent || 0),
      entry_type_id: proto.id,
      final_price: proto.price,
      kind: proto.kind,
      number: proto.number,
      price: proto.price,
      state: ENTRY_NOT_READY,
      store_id: attributes.store_id,
      title: proto.title,
      user_id: attributes.user_id,
      referral_id: attributes.referral_id,
      account: attributes.account
    }

    return rez
  }

  var triggerListChangedDelay = null
  var triggerListChanged = function () {
    if (triggerListChangedDelay) clearTimeout(triggerListChangedDelay)
    triggerListChangedDelay = setTimeout(function () {
      var result = {
        sum: 0,
        final_sum: 0,
        discountable_sum: 0
      }

      var calculateDiscountableSum = function (elem) {
        if (elem.isDeleted() || elem.get('discount_disabled', 'bool')) return
        result.discountable_sum += elem.get('sum', 'float')
      }

      container.find('.entry_row').each(function (i, e) {
        var row = $(e).nestedFieldSet()
        if (row.isDeleted()) return

        if (row.isComplex()) {
          row.getDataArray('members').forEach(calculateDiscountableSum)
        } else {
          calculateDiscountableSum(row)
        }

        result.sum += parseFloat(row.get('sum'))
        result.final_sum += parseFloat(row.get('final_sum'))
      })

      result.sum = round(result.sum)
      result.final_sum = round(result.final_sum)
      result.discount_sum = round(result.sum - result.final_sum)

      PubSub.emit('page.form.' + params.model + '.updateComponents')
      PubSub.emit(msgPrefix + 'listChanged', result)
    }, 10)
  }

  // remove passed attributes & undefineds
  var cleanAttributes = function (attrs) {
    var omitList = Array.prototype.slice.call(arguments, 1)
    attrs = _.omit.apply(_, [attrs].concat(omitList))
    return _.omit(attrs, _.isUndefined)
  }

  const postAdd = () => {
    updateIndexes()
    triggerListChanged()
    updateSelects()
  }

  var addEntry = function (entryType) {
    var entryProto = $.extend({}, entryType, {amount: 1})
    var entryAttributes = _.omit(buildItem(entryProto), _.isUndefined)
    var entryHtml = entriesTemplate.railsTemplate('entries').html
    var entryRow = entryHtml.first().nestedFieldSet()

    entryRow.set(entryAttributes)
    container.append(entryHtml)

    entryProto.entry_type_members.forEach(function (member) {
      addMember(member.member, {
        complexRow: entryRow,
        amount: member.amount,
        skipInit: true
      })
    })

    entryProto.entry_type_consumables.forEach(function (consumable) {
      addConsumable(consumable.consumable, {
        amount: consumable.amount,
        entryRow: entryRow
      })
    })

    entryRow.init()
    entryRow.hideContent()
    if (entryRow.isComplex()) entryRow.showContent()
    entryRow.recalculate()
    postAdd()
  }

  var addMember = function (entryType, params) {
    var complexRow = params.complexRow

    var memberHtml = complexRow
      .getMemberTemplate()
      .railsTemplate('members').html

    var memberRow = memberHtml.first().nestedFieldSet()
    var memberAmount = params.amount || 1
    var memberAttributes = buildItem($.extend({}, entryType, {
      amount: memberAmount
    }))

    memberAttributes = cleanAttributes(memberAttributes, 'order_id')

    if (complexRow.get('discount_disabled', 'bool')) {
      memberAttributes.discount_disabled = true
      memberAttributes.discount_percent = 0
    }

    memberRow.set(memberAttributes)
    complexRow.appendMemberHtml(memberHtml)

    entryType.entry_type_consumables.forEach(function (consumable) {
      addConsumable(consumable.consumable, {
        amount: consumable.amount * memberAmount,
        entryRow: memberRow
      })
    })

    if (!params.skipInit) {
      memberRow.hideContent()
      complexRow.init()
      postAdd()
    }
  }

  var addConsumable = function (entryType, params) {
    var entryRow = params.entryRow

    var consumableHtml = entryRow
      .getConsumableTemplate()
      .railsTemplate('consumables').html
    var consumableRow = consumableHtml.first().nestedFieldSet()

    var consumableAttributes = buildItem($.extend({}, entryType, {
      amount: params.amount || 1
    }))

    $.extend(consumableAttributes, {
      price: 0,
      final_price: 0,
      sum: 0,
      final_sum: 0,
      discount_percent: 0,
      discount_sum: 0,
      consumable: true
    })

    consumableAttributes = cleanAttributes(consumableAttributes,
      'order_id', 'user_id', 'assistant_id', 'referral_id'
    )

    consumableRow.set(consumableAttributes)
    entryRow.appendConsumableHtml(consumableHtml)

    entryRow.init()
    entryRow.redraw()
    consumableRow.redraw()
    postAdd()
  }

  var checkFieldsForNull = function (opts) {
    var attributes = {
      'performer': 'user_id',
      'assistant': 'assistant_id',
      'referral': 'referral_id'
    }
    return container.find('.f-order-entry').toArray().some(function (e, i) {
      var row = $(e).nestedFieldSet()
      var currentAttrs = row.get()
      return !currentAttrs[attributes[opts.change]]
    })
  }

  var setAttributes = function (opts) {

    container.find('.f-order-entry').each(function (i, e) {
      var row = $(e).nestedFieldSet()
      var newAttrs = _.clone(attributes)
      if (row.isConsumable()) {
        newAttrs = _.omit(newAttrs, 'user_id', 'assistant_id', 'referral_id')
      }
      var currentAttrs = row.get()

      if (row.get('discount_disabled', 'bool')) delete newAttrs.discount_percent
      if (row.get('price') == 0) delete newAttrs.discount_percent

      if (currentAttrs.user_id && !(opts.change === 'performer')) delete newAttrs.user_id
      if (currentAttrs.assistant_id && !(opts.change === 'assistant')) delete newAttrs.assistant_id
      if (currentAttrs.referral_id && !(opts.change === 'referral')) delete newAttrs.referral_id
      if (!currentAttrs.state && !(opts.change === 'state')) newAttrs.state = ENTRY_NOT_READY

      if (!opts.force) {
        if (currentAttrs.discount_percent && !(opts.change === 'discount')) delete newAttrs.discount_percent
      }

      row.set(newAttrs)
    })

    container.find('.entry_row').each(function (i, e) {
      $(e).nestedFieldSet().recalculate()
    })

    triggerListChanged()
  }

  var openHiddenErrors = function (e, data) {
    var entriesErrors = data.errors.entries_attributes
    if (!entriesErrors) return

    var entries = container.find('.entry_row').toArray().map(function (e) {
      return $(e).nestedFieldSet()
    })

    Object.keys(entriesErrors).forEach(function (entryIndex) {
      var entry = entries[parseInt(entryIndex)]
      if (!entry) return

      var entryErrors = entriesErrors[entryIndex]
      var membersErrors = entryErrors.members_attributes

      if (membersErrors) {
        Object.keys(membersErrors).forEach(function (memberIndex) {
          var member = entry.getDataArray('members')[parseInt(memberIndex)]
          let memberErrors = membersErrors[memberIndex]
          let consumableErrors = memberErrors.consumables_attributes
          if (member && consumableErrors) member.showContent()
        })
      } else {
        let consumableErrors = entryErrors.consumables_attributes
        if (consumableErrors) entry.showContent()
      }
    })
  }

  //
  // PubSub subscriptions
  //

  PubSub.on(msgPrefix + 'askAddEntry', function (msg, data) {
    if (!data.selector) return addEntry(data.item)

    var selectorRow = data.selector.closest('tr')
    var complex = selectorRow.data('complex')
    var entry = selectorRow.data('entry')
    var type = selectorRow.data('type')

    switch (type) {
      case 'members':
        addMember(data.item, {
          amount: parseInt(complex.get('amount')),
          complexRow: complex
        })
        break
      case 'consumables':
        addConsumable(data.item, {
          amount: parseInt(entry.get('amount')),
          entryRow: entry
        })
        break
      default:
        addEntry(data.item)
    }

    if (gon.application.use_tips_in_orders) { tipNotify(data.item) }

  })

  PubSub.on(msgPrefix + 'askSetAttributes', function (msg, data) {
    attributes = $.extend(
      attributes,
      _.omit($.extend({}, data.attributes), _.isUndefined)
    )

    if (checkFieldsForNull(data) || !data.change) {
      setAttributes({force: false})
    } else {
      bootbox.confirmYN(t('change_field') + ' ' + t(data.change) + ' ' + t('for_all_positions'), function (res) {
        if (res) {
          setAttributes({force: false, change: data.change})
        }
      })
    }
  })

  PubSub.on(msgPrefix + 'askForceAttributes', function (msg, data) {
    //debugger
    attributes = $.extend(
      attributes,
      _.omit($.extend({}, data.attributes), _.isUndefined)
    )
    setAttributes({force: true})
  })

  PubSub.on('page.form.' + params.model + '.setNew', init)
  PubSub.on('page.form.' + params.model + '.setEdit', init)
  PubSub.on('page.form.' + params.model + '.submitError', openHiddenErrors)

  //
  // events
  //

  var recalculateSelector =
    '.f-order-entry-price, .f-order-member-price, ' +
    '.f-order-entry-amount, .f-order-member-amount, ' +
    '.f-order-entry-discount-percent, .f-order-member-discount-percent, ' +
    '.f-entry-referral'
  container.on('keyup change mouseup', recalculateSelector, function () {
    var row = $(this).closest('tr').nestedFieldSet()
    if (row.getName() === 'members') {
      row.data('complex').recalculate()
    } else {
      row.recalculate()
    }

    triggerListChanged()
  })

  container.on('keyup change mouseup', '.f-order-entry-amount', function () {
    var row = $(this).closest('tr').nestedFieldSet()

    if (row.getName() === 'members') row.data('complex').updateSchema()
    if (row.getName() === 'consumables') row.data('entry').updateSchema()

    row.updateContentItems()
    triggerListChanged()
  })

  container.on('click', '.toggle-content-button', function () {
    var row = $(this).closest('tr').nestedFieldSet()
    if (row.enableConsumableSelector()) {
      PubSub.emit('page.form.' + params.model + '.updateComponents')
    }

    row.toggleContent()
  })

  container.on('click', '.f-nested-destroy', function (e) {
    e.preventDefault()
    var row = $(this).closest('tr').nestedFieldSet()
    var entry = row.data('entry')
    if (entry) {
      entry.getConsumableTemplate().railsTemplate('consumables', 'reduceIndex')
    }
    row.gracefulDestroy()
    updateIndexes()
    if (entry) entry.redraw()
    triggerListChanged()
  })

  const updateSelects = () => {
    const selector = '.f-entry-performer, .f-entry-assistant, .f-entry-referral'
    const selectorStore = '.f-order-entry-store'

    setTimeout(() => {
      $(selector).select2({
        dropdownAutoWidth: true,
        templateSelection: Utils.userDropdownTemplate,
        width: '100%'
      })
    }, SELECT_UPDATE_DELAY)

    setTimeout(() => {
      $(selectorStore).select2({
        dropdownAutoWidth: true,
        width: '100%'
      })
    }, SELECT_UPDATE_DELAY)
  }

  const buildReferralOption = (item) => {
    const option = document.createElement('option')
    option.text = item.short_name
    option.value = item.id

    return option
  }

  PubSub.on('page.form.order.referralField.newOption', (msg, item) => {
    // add to all nodes
    form.find('.f-entry-referral').each((i, select) => {
      select.add(buildReferralOption(item), 0)
    })

    attributes = $.extend(
      attributes,
      {referral_id: item.id}
    )
    setAttributes({force: false})

    // add to template
    entriesTemplate[0]
      .content.querySelector('.f-entry-referral')
      .add(buildReferralOption(item), 0)
  })

  return {}
}

вот мой

debug entry

--- !ruby/object:Entry
concise_attributes:
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: id
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: entry_type_id
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: created_at
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: updated_at
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: title
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: order_id
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: client_id
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: state
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: price
  value_before_type_cast: '0.0'
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: amount
  value_before_type_cast: '1'
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: stateful
  value_before_type_cast: 'false'
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: stackable
  value_before_type_cast: 'true'
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: clinic_id
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: pending_data
  value_before_type_cast: 'false'
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: sum
  value_before_type_cast: '0.0'
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: final_sum
  value_before_type_cast: '0.0'
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: discount_sum
  value_before_type_cast: '0.0'
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: discount_percent
  value_before_type_cast: '0.0'
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: user_id
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: store_id
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: kind
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: data
  value_before_type_cast: ''
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: machine_id
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: complex_id
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: analysis_laboratory_id
- !ruby/object:ActiveRecord::Attribute::FromUser
  name: deleted_at
  original_attribute: !ruby/object:ActiveRecord::Attribute::FromDatabase
    name: deleted_at
    type: !ruby/object:ActiveRecord::AttributeMethods::TimeZoneConversion::TimeZoneConverter
      delegate_dc_obj: !ruby/object:ActiveRecord::ConnectionAdapters::PostgreSQL::OID::DateTime
        precision: 
        scale: 
        limit: 
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: created_by_id
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: updated_by_id
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: deleted_by_id
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: assistant_id
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: date
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: cost_price
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: be_result
  value_before_type_cast: ''
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: comment
  value_before_type_cast: ''
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: final_price
  value_before_type_cast: '0.0'
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: number
  value_before_type_cast: ''
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: entry_id
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: consumable
  value_before_type_cast: 'false'
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: template_data
  value_before_type_cast: ''
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: template_html
  value_before_type_cast: ''
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: discount_disabled
  value_before_type_cast: 'false'
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: is_protokol_save
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: referral_id
- !ruby/object:ActiveRecord::Attribute::FromDatabase
  name: print_entry_info
  value_before_type_cast: 'true'
new_record: true
active_record_yaml_version: 2

отладочная запись.title = ноль , я не знаю почему

Можете объяснить, как формируется имя ввода и как вставить в него атрибут title с его названием?

возможно, вы могли бы попытаться изолировать / сделать свой вопрос короче

localhostdotdev 22.04.2019 01:48
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
1
126
1

Ответы 1

{ readonly: true, title:  }

это недопустимый синтаксис ruby, у вас, вероятно, есть nil или "".

также в js вы можете сделать что-то вроде document.querySelector('input').title, чтобы получить атрибут заголовка ввода.

Другие вопросы по теме