Форум русской поддержки Joomla!® CMS
02.12.2016, 22:05:54 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
   
   Начало   Поиск Joomla 3.0 FAQ Joomla 2.5 FAQ Joomla 1.5 FAQ Правила форума Новости Joomla Реклама Войти Регистрация Помощь  
Страниц: [1]   Вниз
  Добавить закладку  |  Печать  
Автор

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

 (Прочитано 653 раз)
0 Пользователей и 1 Гость смотрят эту тему.
batiskaf
Захожу иногда
**

Репутация: +0/-0
Offline Offline

Сообщений: 17


« : 22.01.2016, 15:41:29 »

Всем привет  Smiley

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



Может кто-то поможет или подскажет, как реализовать?   drink
Записан
robert
Профи
********

Репутация: +342/-11
Offline Offline

Пол: Мужской
Сообщений: 3566


« Ответ #1 : 22.01.2016, 15:44:49 »

JavaScript'ом, как еще?
Записан
dmitry_stas
Профи
********

Репутация: +794/-4
Offline Offline

Сообщений: 7732



« Ответ #2 : 22.01.2016, 15:44:56 »

так а чем Repeatable не устраивает?
Записан
b2z
Support Team
*****

Репутация: +707/-0
Offline Offline

Пол: Мужской
Сообщений: 7517


Разраблю понемногу


« Ответ #3 : 22.01.2016, 15:46:45 »

JavaScript'ом, как еще?
+1 Wink
Записан
batiskaf
Захожу иногда
**

Репутация: +0/-0
Offline Offline

Сообщений: 17


« Ответ #4 : 22.01.2016, 15:48:20 »

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

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


Записан
batiskaf
Захожу иногда
**

Репутация: +0/-0
Offline Offline

Сообщений: 17


« Ответ #5 : 22.01.2016, 15:58:15 »

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


Записан
robert
Профи
********

Репутация: +342/-11
Offline Offline

Пол: Мужской
Сообщений: 3566


« Ответ #6 : 22.01.2016, 16:09:38 »

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

Репутация: +692/-25
Offline Offline

Пол: Мужской
Сообщений: 5215



« Ответ #7 : 22.01.2016, 16:32:28 »

я делал так, пример с двумя полями, там правда повырезал не нужное, но смысл думаю понятен
создаем 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
Захожу иногда
**

Репутация: +0/-0
Offline Offline

Сообщений: 17


« Ответ #8 : 22.01.2016, 20:44:33 »

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

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

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

Репутация: +0/-0
Offline Offline

Сообщений: 17


« Ответ #9 : 23.01.2016, 22:17:04 »

я так понимаю нет ответа или мой вопрос не корректен?
Записан
robert
Профи
********

Репутация: +342/-11
Offline Offline

Пол: Мужской
Сообщений: 3566


« Ответ #10 : 23.01.2016, 22:29:22 »

Как нет ответа? Вам даже дали пример. Или вы хотите, чтобы за вас сделали?
Записан
Филипп Сорокин
Живу я здесь
******

Репутация: +120/-3
Offline Offline

Пол: Мужской
Сообщений: 1433


« Ответ #11 : 23.01.2016, 22:43:30 »

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

Репутация: +0/-0
Offline Offline

Сообщений: 17


« Ответ #12 : 23.01.2016, 22:44:07 »

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

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


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

Репутация: +342/-11
Offline Offline

Пол: Мужской
Сообщений: 3566


« Ответ #13 : 23.01.2016, 22:50:19 »

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

Репутация: +0/-0
Offline Offline

Сообщений: 17


« Ответ #14 : 23.01.2016, 22:59:46 »

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

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

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

Репутация: +430/-3
Online Online

Пол: Женский
Сообщений: 4712

Мама, я снова верстал во сне...


« Ответ #15 : 24.01.2016, 02:10:21 »

А что должно быть под кнопкой "Редактировать"? Если там просто список позиций, можно заполнять их через разделитель - например, через запятую или каждую с новой строки, и потом из этого списка выдергивать. Тогда и стандартный вариант подойдет.
« Последнее редактирование: 24.01.2016, 02:15:10 от Taatshi » Записан
batiskaf
Захожу иногда
**

Репутация: +0/-0
Offline Offline

Сообщений: 17


« Ответ #16 : 24.01.2016, 02:56:36 »

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

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

Репутация: +0/-0
Offline Offline

Сообщений: 17


« Ответ #17 : 24.01.2016, 03:03:39 »

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

Хитро!) Но хотелось бы понимать именно "правильный вариант")
Записан
Филипп Сорокин
Живу я здесь
******

Репутация: +120/-3
Offline Offline

Пол: Мужской
Сообщений: 1433


« Ответ #18 : 24.01.2016, 05:10:09 »

Правильный вариант — использовать 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, 06:53:35 от Филипп Сорокин » Записан
batiskaf
Захожу иногда
**

Репутация: +0/-0
Offline Offline

Сообщений: 17


« Ответ #19 : 24.01.2016, 05:39:40 »

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

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

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

Репутация: +120/-3
Offline Offline

Пол: Мужской
Сообщений: 1433


« Ответ #20 : 24.01.2016, 05:43:02 »

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

Репутация: +120/-3
Offline Offline

Пол: Мужской
Сообщений: 1433


« Ответ #21 : 24.01.2016, 06:33:48 »

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

Репутация: +342/-11
Offline Offline

Пол: Мужской
Сообщений: 3566


« Ответ #22 : 24.01.2016, 13:23:25 »

Правильный вариант — использовать 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, 13:34:32 от robert » Записан
dmitry_stas
Профи
********

Репутация: +794/-4
Offline Offline

Сообщений: 7732



« Ответ #23 : 24.01.2016, 13:46:52 »

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

Репутация: +0/-0
Offline Offline

Сообщений: 17


« Ответ #24 : 24.01.2016, 18:26:06 »

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

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

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

- создаете свой класс типа поля 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, 19:10:35 от batiskaf » Записан
batiskaf
Захожу иногда
**

Репутация: +0/-0
Offline Offline

Сообщений: 17


« Ответ #25 : 24.01.2016, 18:31:00 »

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

Репутация: +342/-11
Offline Offline

Пол: Мужской
Сообщений: 3566


« Ответ #26 : 24.01.2016, 19:56:20 »

Или это бредовая мысль?
Думаю, что нет. Я бы так реализовал:
- создать новое поле в 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.
Записан
SmokerMan
Профи
********

Репутация: +692/-25
Offline Offline

Пол: Мужской
Сообщений: 5215



« Ответ #27 : 25.01.2016, 02:45:41 »

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

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

Репутация: +0/-0
Offline Offline

Сообщений: 17


« Ответ #28 : 26.01.2016, 05:14:23 »

пытался найти, где я читал об добавлении во одном из планируемых обновлений похожих возможностей, но так и не нашел) не приснилось ли мне это  dry
Записан
Страниц: [1]   Вверх
  Добавить закладку  |  Печать  
 
Перейти в:  

Powered by SMF 1.1.21 | SMF © 2006, Simple Machines

Joomlaforum.ru is not affiliated with or endorsed by the Joomla! Project or Open Source Matters.
The Joomla! name and logo is used under a limited license granted by Open Source Matters
the trademark holder in the United States and other countries.

LiveInternet