Как изменить класс ошибки обертки div при использовании CakePHP с помощью Bootstrap

Я использую Bootstrap 3.0RC1 с CakePHP 2.3.6. Пытаясь воспользоваться преимуществами тех красиво выглядящих классов, как has-error и has-warning для состояния проверки, мне нужно изменить класс элементов по умолчанию FormHelper добавляет к обертке div.

До сих пор я использую этот код:

echo $this->Form->create('User', array(
    'inputDefaults' => array(
        'class' => 'form-control',
        'div' => array('class' => 'form-group'),
        'label' => array('class' => 'control-label'),
        'error' => array('attributes' => array('wrap' => 'span', 'class' => 'help-block'))
    )
)); 

echo $this->Form->input('email'));

Что выведет это при ошибке:

<div class="form-group error">
    <label for="UserEmail" class="control-label">Email</label>
    <input name="data[User][email]" class="form-control form-error" type="email" value="[email protected]">
    <span class="help-block">Email already in use.</span>
</div>

Все просто отлично, за исключением того, что мне нужно изменить класс error в оберточном div на has-error, поэтому для label, input и span применяются новые стили. Пока не найдено чистого решения.

Уродливое решение, я думал, это скопировать стили has-error из Bootstrap в класс error в моем приложении.

Ответ 1

Если вы закроете FormHelper, вы найдете в этой строке "уродливый" код, делающий магию ошибок.

Поскольку исходные авторы не оставили никаких шансов сделать это по конфигурации, я предлагаю вам написать собственный BootstrapFormHelper и переопределить функцию ввода, изменив эту единственную строку.

Вот фрагмент:

//inside public function input($fieldName, $options = array())

$out['error'] = null;
if ($type !== 'hidden' && $error !== false) {
    $errMsg = $this->error($fieldName, $error);
    if ($errMsg) {
        $divOptions = $this->addClass($divOptions, 'has-error'); //old string value was 'error'
        if ($errorMessage) {
            $out['error'] = $errMsg;
        }
    }
}

Поскольку я уже использую пользовательские BootstrapFormHelper, здесь ссылка на полный текст.

Просто скопируйте файл в app\View\Helper и добавьте в ВСЕ свои контроллеры следующую строку:

public $helpers = array(
  'Form' => array('className' => 'BootstrapForm')
);

предполагая, что вы сохранили gist как BootstrapFormHelper.php.

Ответ 2

РЕШЕНИЕ я ИСПОЛЬЗОВАНИЕ:

Каждый раз, когда вы создаете новый ввод, проверяйте, есть ли какие-либо ошибки для этого поля, используя функцию CakePhp isFieldError() и просто добавьте класс "has-error" для div, как показано ниже:

Просто настройка div:

'div' => array('class' => "form-group ".($this->Form->isFieldError('username') ? 'has-error' : '')),

Полный код для одного поля:

<?php echo $this->Form->input(
    'username',
    array(
        'label' => array('text' => 'Username', 'class' => 'strong'), 'placeholder' => "Your Username", 'class' => 'form-control', 
        'div' => array('class' => "form-group ".($this->Form->isFieldError('username') ? 'has-error' : '') ),
        'error' => array('attributes' => array('wrap' => 'p', 'class' => 'help-block has-error'))
        )
); ?>

Ответ 3

Несколько менее уродливое решение состоит в том, чтобы добавить ваш селектор для этого типа ошибки div в ваш загрузочный CSS файл. Таким образом, вы не копируете все значения стиля, вы просто добавляете свои разделители ошибок в существующие определения стиля.

Другим вариантом будет использование javascript для изменения этих классов с "error" на "has-error" на DOMREADY, хотя ваша страница будет выглядеть странно до этого времени. Не совсем чистое решение.

Ответ 4

Я согласен с первым ответом Дерека, добавив ваши стили в файл Bootstrap CSS.

Строки 1590-1611

    .has-error .help-block,
    .has-error .control-label {
      color: #b94a48;
    }

    .has-error .form-control {
      border-color: #b94a48;
      -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
              box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
    }

    .has-error .form-control:focus {
      border-color: #953b39;
      -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
              box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
    }

    .has-error .input-group-addon {
      color: #b94a48;
      background-color: #f2dede;
      border-color: #b94a48;
    }

Вы должны изменить это на:

    .error .help-bloc, .has-error .help-block,
    .error .control-label, .has-error .control-label {
      color: #b94a48;
    }

    .error .form-control, .has-error .form-control {
      border-color: #b94a48;
      -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
              box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
    }

    .error .form-control:focus, .has-error .form-control:focus {
      border-color: #953b39;
      -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
              box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
    }

    .error .input-group-addon, .has-error .input-group-addon {
      color: #b94a48;
      background-color: #f2dede;
      border-color: #b94a48;
    }

Ответ 5

Я никогда не использовал CakePHP, но я осмеливаюсь публиковать ответ здесь. Я думаю, что элемент сообщения должен иметь возможность переносить несколько классов, как и любой другой элемент.

Итак, простое редактирование:

'error' => array('attributes' => array('wrap' => 'span', 'class' => 'help-block has-error'))

Я не вижу причин копировать и вставлять код css.

Ответ 6

Я использовал jQuery.

<script>
$(document).ready(function() {
    $('.form-control').parent('.error').each(function() {
        $(this).addClass('has-error');
    });
});
</script>

Ответ 7

Я использую пользовательский помощник, который адаптирован к любой структуре CSS. В этом случае Bootstrap.

<?php

App::uses('AppHelper', 'View/Helper');

class UIHelper extends AppHelper
{
    public $helpers = array('Html', 'Form');

    public function textBox($fieldName, $options = array()) {
        $options += array('class' => 'form-control', 'div'=>false, 'error' => array('attributes' => array('wrap' => 'span', 'class' => 'help-block')));

        if (isset($options['label'])) {
            if (is_array($options['label'])) {
                $options['label'] += array('class' => 'control-label');
            } else {
                $options['label'] = array('text' => $options['label'], 'class' => 'control-label');
            }
        } else {
            $options['label'] = array('class' => 'control-label');
        }

        $divOptions = array('class' => "form-group has-feedback");
        if (isset($options['div'])) {
            if (is_array($options['div'])) {
                $divOptions += $options['div'];
            }
        }
        $options['div'] = false;                

        $divText = $this->Form->input($fieldName, $options);

        if ($this->Form->isFieldError($fieldName)) {
            $divOptions['class'] = "form-group has-error has-feedback";
            $divText .= $this->Html->tag('span', null, array('class' => "glyphicon glyphicon-remove form-control-feedback"));
        }

        return $this->Html->tag('div', $divText, $divOptions);
    }

}

?>

Затем используйте это вместо стандартного Form помощника

echo $this->UI->textBox('email'));