@Renius
дурак восторженный

Javascript(Coffee) best practice: как мне сделать это лучше?

Прошу уважаемого сообщества предлажить мне прием, разрешающий вопрос: «Как мне из этого гекзаметра сделать хойку?»
$('.dropdown-toggle').parent().find('.dropdown-element').click ->
    $(this).parents('.btn-group').find('.dropdown-toggle').text(this.textContent)
    if $('.container').data($(this).data('attribute')) == undefined
      console.log 'undef'
      $('.container').data($(this).data('attribute'), new Object)

    if $(this).data('place')
      if $('.container').data($(this).data('attribute'))[$(this).data('place')] == undefined
        $('.container').data($(this).data('attribute'))[$(this).data('place')] = new Object
      $('.container').data($(this).data('attribute'))[$(this).data('place')][$(this).data('change')] = $(this).data($(this).data('change'))
    else
      $('.container').data($(this).data('attribute'))[$(this).data('change')] = $(this).data($(this).data('change'))


предвосхищая вопрос: Зачем это нужно?
Во первых: я не фронтендщик, для меня это все не нативно, а делать нужно.
Страничка на которой это работает сверстана в bootstrap, что, как любой фреймворк, накладывает ограничения на привычный функционал. Страничка представляет из себя 18 вкладок. Каждый клик на этих вкладках улетает ajax-ом на сервер и вносит изменения в объект.
Объектом POST и PUT данных является $('.container').data(). Где все очень-очень RESTfull, для того чтобы разработчики невеб версии нашего проекта понимали как с нашим REST серсивом работать.

Классических select, radio и checkbox нет, вместо них bootstrap dropdown.js, button.js. Поэтому сборка данных через html forms невозможна.
Приведенный выше код складывает значения всех моих псевдо селекторов в $('.container').data() объект вида

wheels: Object
  front_left: Object
    brand: "Barum"
    diameter: "14"
    profile: "10.5"
    protector: "4"
    width: "32"
    __proto__: Object
  front_right: Object
    brand: "Continental"
      profile: "12.5"
      protector: "6"
      width: "155"

Т.о. я делаю тоже самое, что делает сериализатор форм, только вручную, так как объектов форм у меня нет.
Получается чудный объект, с сохранением REST парадигмы, который прекрасно кушается сервером как есть.

Started PUT "/reports/9" for 127.0.0.1 at 2012-07-24 17:51:34 +0600
  Processing by ReportsController#update as */*
  Parameters: {
    "report"=>{
      "wheels"=>{
        "rear_left"=>{
          "width"=>"135", 
          "profile"=>"10.5",
          "diameter"=>"14",
          "protector"=>"3", 
          "brand"=>"Barum"
        }, 
        "front_left"=>{
          "brand"=>"Barum",
          "width"=>"32",
          "profile"=>"10.5",
          "diameter"=>"14",
          "protector"=>"4"
        }
      },
    "id" => 9}
  }


Это кушается на сервере всего двумя строчками, и отказываться от столь локоничного и прозрачного подхода не стоит:

@report = Report.find(params[:id])
@report.update_attributes(params[:report])


Каждый псевдо селектор выглядит следующим образом
 HAML
%ul.dropdown-menu.pull-right
  - (12..24).to_a.each do |i|
    %li
      .dropdown-element{:data => {:attribute => 'wheels',:place => 'front_right', :change => 'diameter', :diameter => i}}=i


Мой кофи, создает объект wheels в $('.container'), если его нет, создает внутри front_right, если его нет, и кладет туда diameter.
Если понадобится что-то изменить в coffee скрипте, то я предложу застрелить меня. Т.е. гибкая реакция на изменение функционала мне боле недоступна.
Там еще 18 подобных объектов, выглядящих на выходе как будто их создала сериализация обычной формы, но то, универсальное для всех объектов, решениe-велосипед, которое я разработал не поддерживает дебаг ввиду суровой своей спагетности и быдлячества. Посыпаю голову пеплом.

P.S.
Если есть красивое и изящное решение — обязуюсь опубликовать результат и весь пройденный путь с длинной ссылкой на автора, и частыми упоминаниями автора решения. Нужно знать своих героев.
  • Вопрос задан
  • 2905 просмотров
Пригласить эксперта
Ответы на вопрос 4
k12th
@k12th
console.log(`You're pulling my leg, right?`);
Первый кусок кода — это восхитительный пример того, почему чейнинг в jQuery является злом.
Ответ написан
@hom9k
Немного сложно это всё вот так воспринять без конкретного примера, поэтому просто предложу немного поправить код.

$('.dropdown-toggle').parent().find('.dropdown-element').click ->
  $(@).parents('.btn-group').find('.dropdown-toggle').text(@textContent)
  
  attr = $(@).data('attribute')
  console.log('undef') unless $('.container').data(attr)
  container_data = $('.container').data(attr) || new Object
  change = $(@).data('change')
  place = $(@).data('place')

  if place
    container_data[place] ||= new Object
    container_data[place][change] = $(@).data(change)
  else
    container_data[change] = $(@).data(change)

  $('.container').data(attr,container_data)


Можно еще парой комментов снабдить и уже намного лучше будет :)

Не гарантирую, что все правильно, поскольку нет возможности проверить, но, наверное, как-то так.
Ответ написан
sdevalex
@sdevalex
Используйте внутренние перменные и не плодите море строк, типа…
$(this).data('place')

Сделайте в одном месте
var place = $(this).data('place')


Уже после этого код станет в 2-3 раза чище.
Ответ написан
@Renius Автор вопроса
дурак восторженный
Можете разьяснить?
1. есть css
.pull-right {float: right}
почему span.pull-right и div.pull-right это плохо?
2. Когда я говорю зеленое я могу подразумевать кнопку и бэкграунд
Но когда я пишу кнопка.зеленая я знаю, и я не ошибусь в том, что работаю именно с кнопкой, я могу случайно написать.коричневая, но коричневой кнопки у меня нет, а.коричневая будет найден в доме. Работа с неожиданным объектом может привести к нежелательным батхертам.
Специалист который будет, упоси бог, работать с моим кодом будет лучше ориентироватья в дереве если будет написано button.dropdown-toggle.
Это вносит порядок.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы