首页 > 解决方案 > 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 {}
}

这是我的

调试入口

--- !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

debug entry.title = nill,不知道为什么

你能解释一下输入名称是如何形成的,以及如何在其中插入标题属性及其名称吗?

标签: javascriptjqueryruby-on-railsslim-lang

解决方案


{ readonly: true, title:  }

这不是有效的 ruby​​ 语法,你可能有nil""有。

同样在 js 中,您可以执行诸如document.querySelector('input').title获取输入的标题属性之类的操作。


推荐阅读