Собственный модуль. Динамические поля. Не type="Repeatable"

  • 28 Ответов
  • 1006 Просмотров

0 Пользователей и 1 Гость просматривают эту тему.

*

Оффлайн batiskaf

Всем привет  ^-^

При написании собственных модулей раз-за-разом возникает мысль динамического добавления единичных или групп полей в админке модуля. Т.е. не просто type="Repeatable", а так как на картинке. Кнопка "Добавить" добавляет группу полей type="text" и type="Repeatable" (например). Кнопка "Удалить" эту группу удаляет. Есть варианты, как это реализовать? Кстати, где-то читал, что планируется в одном из обновлений Joomla такая возможность. Но не помню где. И в каком обновении, тоже не помню  :dry:



Может кто-то поможет или подскажет, как реализовать?   *DRINK*

*

Оффлайн robert

JavaScript'ом, как еще?
  • Не будь паразитом, сделай что-нибудь самостоятельно!
  • В личке и по Skype не даю советов.

*

Оффлайн dmitry_stas

так а чем Repeatable не устраивает?
Тут дарят бакс просто за регистрацию! Успей получить!
Все советы на форуме раздаю бесплатно, то есть даром. Индивидуально бесплатно консультирую только по вопросам стоимости индивидуальных консультаций


*

Оффлайн batiskaf

так а чем Repeatable не устраивает?

Repeatable устраивает, если не нужен как бы Repeatable в Repeatable ))))



*

Оффлайн batiskaf

JavaScript'ом, как еще?
Я понимаю, что через JavaScript "дублируем блок".  Пытался сделать, но после сохранения модуля добавленные JavaScript-ом поля пропадают. Я слабо понимаю, как именно работает процесс формирования админки модуля (как это реализовывается в ядре а не при создании собственного модуля). И я так понял, что после сохранения модуля в любом случае мы увидим именно те поля, которые зашиты в манифесте. После ваших ответов понимаю, что скорее всего не прав. Может у кого-то есть какой пример?



*

Оффлайн robert

И я так понял, что после сохранения модуля в любом случае мы увидим именно те поля, которые зашиты в манифесте. После ваших ответов понимаю, что скорее всего не прав.
Почему? IMHO, вы правы. Вывод: нужно туда зашить свой тип поля.
  • Не будь паразитом, сделай что-нибудь самостоятельно!
  • В личке и по Skype не даю советов.

*

Оффлайн SmokerMan

я делал так, пример с двумя полями, там правда повырезал не нужное, но смысл думаю понятен
создаем 2 поля
1. просто заглушка
class JFormFieldPhones extends JFormField
{

    /**
     * The form field type.
     *
     * @var string
     * @since 11.1
     */
    protected $type = 'Phones';

    /**
     * Method to get the field input markup for a generic list.
     * Use the multiple attribute to enable multiselect.
     *
     * @return string The field input markup.
     *       
     * @since 11.1
     */
    protected function getInput()
    {
        return '';
    }
   
    protected function getLabel()
    {
        return '';
    }   
}

2. Собственно само поле
<?php
defined
('JPATH_PLATFORM') or die();

/**
 * Form Field class for the Joomla Platform.
 * Supports a generic list of options.
 *
 * @package Joomla.Platform
 * @subpackage Form
 * @since 11.1
 */
class JFormFieldRegs extends JFormField
{

    
/**
     * The form field type.
     *
     * @var string
     * @since 11.1
     */
    
protected $type 'Regs';

    
/**
     * Method to get the field input markup for a generic list.
     * Use the multiple attribute to enable multiselect.
     *
     * @return string The field input markup.
     *        
     * @since 11.1
     */
    
protected function getInput()
    {
        
$doc JFactory::getDocument();
        
$doc->addScript(JURI::root(). 'modules/mod_sypexgeo/inc/script.js');
        
        
$doc->addStyleDeclaration('#regs, #regs div, #regs .add_btn {clear:both;} #regs {margin-left:-180px}');
        
$values $this->value;
        
        
$addresses $this->form->getValue('addresses''params');

        
        
$html '<div id="regs">';
        
$html .= '<h3>'.JText::_('MOD_SYPEXGEO_REGS_LBL').'</h3>';

        if (
is_array($values)) {
            foreach (
$values as $key => $value) {
                
$html .= '<div>';
                
$address '';
                if (isset(
$addresses[$key])) {
                    
$address $addresses[$key];
                }
                
$html .= '<input placeholder="'.JText::_('MOD_SYPEXGEO_PHONE').'" type="text" name="'.$this->name.'[]" value="' $value '" />';
                
$html .= '<textarea placeholder="'.JText::_('MOD_SYPEXGEO_ADDRESS').'" type="text" name="jform[params][addresses][]" />'.$address.'</textarea>';
                
$html .= '<button class="btn remove_btn" type="button">'.JText::_('MOD_SYPEXGEO_DEL').'</button>';
                
$html .= '</div>';
            }
        } else {
            
$html .= '<div style="display:none">';
            
$html .= '<input placeholder="'.JText::_('MOD_SYPEXGEO_PHONE').'" type="text" name="'.$this->name.'[]" />';
            
$html .= '<textarea placeholder="'.JText::_('MOD_SYPEXGEO_ADDRESS').'" type="text" name="jform[params][addresses][]" /></textarea>';
            
$html .= '<button class="btn remove_btn" type="button">'.JText::_('MOD_SYPEXGEO_DEL').'</button>';
            
$html .= '</div>';
        }
        
        
$html .= '<button class="btn add_btn" type="button">'.JText::_('MOD_SYPEXGEO_ADD').'</button>';
        
$html .= '</div>';
        
        return 
$html;
    }

    protected function 
getLabel()
    {
        return 
'';
    }
}


и небольшой js
jQuery( document ).ready(function() {
setRemoveBtn();
jQuery('.add_btn').on('click', function() {
var new_reg = jQuery('#regs div:first');
if (new_reg.is(':hidden')) {
new_reg.show();
return;
} else {
new_reg = new_reg.clone(true)
}
new_reg.find('input').attr('value', '');
jQuery(this).before(new_reg.prop('outerHTML'));
setRemoveBtn();
})

})
function setRemoveBtn() {
jQuery('.remove_btn').on('click', function() {
jQuery(this).parent('div').remove();
})
}

в XML добавляем поля
<fieldset name="basic" addfieldpath="/modules/mod_sypexgeo/fields">
<field name="regs" type="regs" />
<field name="addresses" type="phones" />
</fieldset>

*

Оффлайн batiskaf

я делал так, пример с двумя полями, там правда повырезал не нужное, но смысл думаю понятен ...

SmokerMan, спасибо Вам за подробный ответ. Благодаря ему я пойму свою ошибку, на сколько мне позволят мои знания. как минимум, уже ясна идея.

Но остается такой вопрос: в Joomla есть ведь очень удобные типы полей (тот же Repeatable). Как бы в методе getInput() вашего класса JFormFieldRegs не использовать HTML поля типа <textarea> и т.д., а вместо них Joomlа-вские type="Repeatable" и type="text" (например), вот прям как на картинке из первого поста? Знаю, что для каждого Joomlа-вского типа поля есть свой класс, который можно расширить и переопределить какие-то методы вывода, но как это все завязать на моей идее, не пойму.

*

Оффлайн batiskaf

я так понимаю нет ответа или мой вопрос не корректен?

*

Оффлайн robert

Как нет ответа? Вам даже дали пример. Или вы хотите, чтобы за вас сделали?
  • Не будь паразитом, сделай что-нибудь самостоятельно!
  • В личке и по Skype не даю советов.

Ещё один вариант: создать в XML скрытый инпут и сериализовывать туда строку со значением всех добавленных полей, которых нет в XML. Спасибо - в карму. Спасибо :)
Ставь лайк, если согласен, и делай репост!

  => мои публикации
    => мои работы
      => спектр моих услуг

*

Оффлайн batiskaf

Как нет ответа? Вам даже дали пример. Или вы хотите, чтобы за вас сделали?

SmokerMan
Но остается такой вопрос: в Joomla есть ведь очень удобные типы полей (тот же Repeatable). Как бы в методе getInput() вашего класса JFormFieldRegs не использовать HTML поля типа <textarea> и т.д., а вместо них Joomlа-вские type="Repeatable" и type="text" (например), вот прям как на картинке из первого поста? Знаю, что для каждого Joomlа-вского типа поля есть свой класс, который можно расширить и переопределить какие-то методы вывода, но как это все завязать на моей идее, не пойму.


Смотрите мой первый пост. Ответ, который дал SmokerMan очень полезен, но не совсем решает задачу, с которой я обратился.

*

Оффлайн robert

Еще раз: напишите свой тип поля по аналогии с примером (ну или с каким-нибудь стандартным типом). Если хотите модифицировать какой-то существующий тип, то сделайте класс своего типа унаследованным от него.
  • Не будь паразитом, сделай что-нибудь самостоятельно!
  • В личке и по Skype не даю советов.

*

Оффлайн batiskaf

я вот и не знаю, нужно мне модифицировать какой-то существующий тип, или я могу каким-то образом просто использовать существующие типы полей в собственно стеке в getInput() своего типа поля. В моем понимании не могу.

Ваше "Еще раз: напишите свой тип поля по аналогии с примером (ну или с каким-нибудь стандартным типом). Если хотите модифицировать какой-то существующий тип, то сделайте класс своего типа унаследованным от него." в моем понимании проблему не решает. Т.к. мне нужен стек стандартных джумловских типов полей в собственном типе поля.

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

*

Оффлайн Taatshi

А что должно быть под кнопкой "Редактировать"? Если там просто список позиций, можно заполнять их через разделитель - например, через запятую или каждую с новой строки, и потом из этого списка выдергивать. Тогда и стандартный вариант подойдет.
« Последнее редактирование: 24.01.2016, 03:15:10 от Taatshi »
ВЕРСТКА, САЙТЫ ПОД КЛЮЧ, УДАЛЕНИЕ ВИРУСОВ, МИГРАЦИЯ НА JOOMLA 3  /  ОТЗЫВЫ 
Минимальная ставка за платные услуги 1000 рэ Связь: telegram - Taatshi, почта - Taatshi на яндексе.

*

Оффлайн batiskaf

А что должно быть под кнопкой "Редактировать"? Если там просто список позиций, можно заполнять их через разделитель - например, через запятую или каждую с новой строки, и потом из этого списка выдергивать. Тогда и стандартный вариант подойдет.

Спасибо за ответ. Там может быть все что угодно. Например, type="text", type="sql" и type="media". На самом деле хотелось бы реализовать именно задуманное. Иначе саму идею можно свести к, например, 20-ти одинаковым стекам полей, доступным для заполнения, и не думать над кнопками "Добавить"\"Удалить", как часто делается в подобных "админках" модулей.

*

Оффлайн batiskaf

Ещё один вариант: создать в XML скрытый инпут и сериализовывать туда строку со значением всех добавленных полей, которых нет в XML. Спасибо - в карму. Спасибо :)

Хитро!) Но хотелось бы понимать именно "правильный вариант")

Правильный вариант — использовать Repeatable. Вы устроили какой-то эпический вынос мозга! Простите, конечно, но это начинает уже раздражать — вам уже 100 вариантов правильных подсказали. Ну а это один из них:

В манифесте:

   <config>
        <fields name="params">
            <fieldset name="basic" addfieldpath="/modules/mod_extension/fields/">
                <field name="text"
                    type="text"
                    description="Description"
                    label="Label"
                    default=""
                />
                <field name="hidden" type="hidden" default="" />
                <field name="virtualfields" type="virtualfields" />
            </fieldset>
        </fields>
    </config>

Это пишете в файле '/modules/mod_extension/fields/virtualfields.php'

defined('JPATH_PLATFORM') or die;

class JFormFieldVirtualfields extends JFormField
{

    protected $type = 'virtualfields';
    
    protected function getInput()
    {
        
        JFactory::getDocument()->addScriptDeclaration("
            
            jQuery(function($) {

                var text = $('#jform_params_text');
                
                var addField = function() {
                    
                    var groups = $('#general .control-group'),
                        textClone = $(text).parent().parent().clone();
                    
                    $(textClone).find('*').each(function()
                    {
                        if($(this).attr('id'))
                        {
                            $(this).removeAttr('id').val('').removeAttr('name');
                        }
                    });
                    
                    $(textClone).insertAfter($('.dynamic-fields:last').parent().parent());
                    
                };
                
                $(text).addClass('dynamic-fields');
                $('.btn-add-field').on('click', addField);
                
                var fields = $.parseJSON($('#jform_params_hidden').val());
                
                $(fields).each(function(i)
                {
                    if(i > 0)
                    {
                        addField();
                        $('.dynamic-fields:last').val(fields[i]);
                    }

                });
                
                $('#module-form').on('submit', function()
                {
                    var values = [];
                    
                    $('.dynamic-fields').each(function()
                    {
                        values.push($(this).val());
                    });
                    
                    $('#jform_params_hidden').val(JSON.stringify(values));
                    
                });
                
            });
            
        ");
        
        return '';
    }
    
    protected function getLabel()
    {
        return '<input type="button" value="Добавить поле" class="btn btn-primary btn-add-field" />';
    }
    
}

И всё! Значение всех полей теперь доступно в php:

$this->params->get('hidden')
« Последнее редактирование: 24.01.2016, 07:53:35 от Филипп Сорокин »
Ставь лайк, если согласен, и делай репост!

  => мои публикации
    => мои работы
      => спектр моих услуг

*

Оффлайн batiskaf

Филипп Сорокин, не понял по поводу "Правильный вариант — использовать Repeatable." Допустим, у меня есть прайс (чисто для примера, чтобы соответствовало  той картинке из первого поста). Он содержит 5 категорий (количество может меняться), в каждой категории от 10 до 20 позиций  (количество может меняться). Логика такая: администратор заполняет поле "Категория" (type="text"), затем открывает type="Repeatable" и добавляет нужное количество позиций. Таким же образом он добавляет нужное ему количество остальных категорий и полей для этих категорий (кнопка "Добавить" на картинке). Так что "Правильный вариант — использовать Repeatable." тут не поможет.

В любом случае, благодаря Вашей идее по поводу скрытого поля уже наваял нужный мне вариант. Завтра утром пересмотрю Ваш пример. Уверен, подчеркну для себя что-то полезное.

Извиняюсь, если кому-то вынес мозг. Вам и SmokerMan спасибо в карму)
« Последнее редактирование: 24.01.2016, 06:43:29 от batiskaf »

Да ладно! Это нормальная "рабочая обстановка" на форуме, так что не пугайтесь и вливайтесь! :)
А мой набросок составлен наспех, так что не черпайте из него ничего полезного!
Ставь лайк, если согласен, и делай репост!

  => мои публикации
    => мои работы
      => спектр моих услуг

Что-то не так с шорткодом "спойлер": вырезал мне элемент массива fields\[i\], превратив в массив fields. Заменил шорткод на "Код".
P.S. По-ходу регулярка по всему форуму работает, так что заэкранировал :)
« Последнее редактирование: 24.01.2016, 07:40:31 от Филипп Сорокин »
Ставь лайк, если согласен, и делай репост!

  => мои публикации
    => мои работы
      => спектр моих услуг

*

Оффлайн robert

Правильный вариант — использовать Repeatable.
Да.
ТС, вы упрекаете меня в ведении "тезисного чата", но сами не выкладывали ни одной строки собственного кода. Я не стал бы дальше писать здесь, если бы тема не заинтересовала меня. Объясню, как нужно использовать Repeatable:
- создаете свой класс типа поля my_type с:
  input type="text" (категория) +
  кнопкой "Добавить", которая добавляет другой input (appenChild(), позиция) +
  кнопкой "Удалить", которая удаляет последний (removeChild(), позиция)
- в XML создаете my_type_list, тип Repeatable, в котором в fieldset name="my_type_list_modal" сидит ваш my_type.
Теперь у вас есть, как вы хотите, поле Repeatable внутри Repeatable, которое может добавлять много категорий, а внутри каждой категории - сколько угодно позиций.
« Последнее редактирование: 24.01.2016, 14:34:32 от robert »
  • Не будь паразитом, сделай что-нибудь самостоятельно!
  • В личке и по Skype не даю советов.

*

Оффлайн dmitry_stas

мне кажется у ТС проблема была не столько создании повторений, сколько в
могу каким-то образом просто использовать существующие типы полей в собственно стеке в getInput() своего типа поля.
т.е. достучаться из кастомного getInput к скажем JFormFieldColor
Тут дарят бакс просто за регистрацию! Успей получить!
Все советы на форуме раздаю бесплатно, то есть даром. Индивидуально бесплатно консультирую только по вопросам стоимости индивидуальных консультаций

*

Оффлайн batiskaf

ТС, вы упрекаете меня в ведении "тезисного чата", но сами не выкладывали ни одной строки собственного кода. Я не стал бы дальше писать здесь, если бы тема не заинтересовала меня.

Извините, если выразился грубо или не уважительно. Этих целей не преследовал, поверьте.

Правильно ли я понял вашу идею?

- создаете свой класс типа поля my_type с:
  input type="text" (категория) +
  кнопкой "Добавить", которая добавляет другой input (appenChild(), позиция) +
  кнопкой "Удалить", которая удаляет последний (removeChild(), позиция)

class JFormFieldMy_type extends JFormField
{
    protected $type = 'My_type';

    protected function getInput()
    {
        $html = '
<input name="price_category" type="text" >
<input name="price_add" type="button" value="Добавить">  // добавляем позицию (input text)
<input name="price_remove" type="button" value="Удалить"> // удаляем добавленную позицию input text
';

        return $html;
    }
}

- в XML создаете my_type_list, тип Repeatable, в котором в fieldset name="my_type_list_modal" сидит ваш my_type.

<field name="my_type_list"
type="Repeatable"
icon="list"
label="Заголовок 1"
description=""
select="Добавить"
default="">

<fieldset hidden="true" name="my_type_list_modal" repeat="true" description="">

<field name="price" label ="Заголовок 2" type="my_type" description="" />

</fieldset>
</field>

Если я все правильно понял, то на выходе мы получим что-то типа:
Спойлер
[свернуть]

Но если я правильно понял вашу идею, то ранее предложенная SmokerMan-ом идея более соответствует задаче, которую я описывал и соответствует скрину из первого поста. Но и в том, и в вашем примере для меня не решенным остается вопрос, который подчеркнул dmitry_stas. Например, мне нужно не просто текстовое поле для позиции, а каждая позиция в категории должна содержать несколько стандартных полей Joomla, например type="text", type="sql" и type="media". Как их использовать в getInput в JFormFieldMy_type. Опять же, благодаря идее Филиппа Сорокина проблема для меня решена, но остается ощущение, что мог быть и более изящный способ вместо скрытого поля.
« Последнее редактирование: 24.01.2016, 20:10:35 от batiskaf »

*

Оффлайн batiskaf

мне кажется у ТС проблема была не столько создании повторений, сколько вт.е. достучаться из кастомного getInput к скажем JFormFieldColor
Да, вы правы. К примеру мне нужен JFormFieldMedia и JFormFieldList. Может  как-то в конструкторе класса кастомного поля получить их экземпляры и потом уже взаимодействовать с ихними методами. Или это бредовая мысль?

*

Оффлайн robert

Или это бредовая мысль?
Думаю, что нет. Я бы так реализовал:
- создать новое поле в XML, примерно такое
Код: (xml) [Выделить]
<field type="mytype" blahblahblah>
<subfield type="mysql" blablahblah></subfield>
<subfield type="mymedia" blablahblah></subfield>
</field>
- создать классы JFormFieldMySQL extends JFormFieldSQL и JFormFieldMyMedia extends JFormFieldMedia,
- переопределить функцию setup(SimpleXMLElement $element,$value,$group = null) в обоих классах, чтобы они брали свой элемент с subfield вместо field.
  • Не будь паразитом, сделай что-нибудь самостоятельно!
  • В личке и по Skype не даю советов.

*

Оффлайн SmokerMan

Цитировать
Например, мне нужно не просто текстовое поле для позиции, а каждая позиция в категории должна содержать несколько стандартных полей Joomla, например type="text", type="sql" и type="media".
думаю это изначально бредовая идея, исходя из своего опыта
приведу пример с тем же media
это не просто "там кнопка выводиться", а кнопка, на которое вешается событие, при клике на которое чего-то должно происходить
в данном случае выбор картинки и подставление в нужный инпут значение этой картинки
так вот при добавлении нового элемента на страницу эта кнопка естественно сама сабой не заработает и не поймет куда и чего ему ставить
задача решаема, но изначально надо понять суть происходящего)

+ к этому стандартные поля не предназначены для массивов, тот же text взять
т.е. в любом случае надо писать свою логику что к чему соответсвует
но тут плюс что в базе все сохраняется в json и это потом можно распарсить   
« Последнее редактирование: 25.01.2016, 03:55:26 от SmokerMan »

*

Оффлайн batiskaf

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