Как сделать вложенные TV MIGx и как это потом вывести с помощью fenom

Доброе утро сообщество!
Сегодня у меня день рождения, а значит замечательный день чтобы написать новую заметку =)
Итак, буквально недавно столкнулся с задачей вывести несколько аккордеонов подряд, причем каждый их которых должен иметь собственный заголовок. Решено для этого было использовать вложенные TV типа MIGx. Подробности под катом.На моём примере использовалось 2 уровня вложенности. То есть внутри одного TV был вложен только один TV. Но я не исключаю, что можно сколько угодно больше уровней вложенности делать, просто пока не проверял. Далее по порядку:

  1. Создаем MIGx конфигурацию AccordionItems, тот что на втором уровне.

    Показываю в редакторе MIGx полей для понимания:


    • Далее настроил форму, причем в поле description в качестве inputTV можно было ничего не указывать, я указал созданный заранее простой TV с визуальным редактором TinyMCE чтобы было удобно наполнять текстом. Если бы не указал, то было бы простое текстовое поле:

    • И колонки, тут все просто:

    • После чего создаем TV поле одноименное, с указанием типа MIGx и имени его конфигурации AccordionItems.
  2. Следующим этапом идет создание MIGx конфигурации AccordionSections тут все по аналогии, но только в поле inputTV мы уже указываем TV AccordionItems:
  3. После чего создаем TV поле одноименное, с указанием типа MIGx и имени его конфигурации AccordionSections.
  4. Ну а напоследок самое интересное, на мой взгляд создаем чанк который бы выводил аккордеоны с заголовками, причем нужно было чтобы редактировались данные в одном месте, в данном случае в одном ресурсе, а выводилось одни и те же секции везде где будет вставлен чанк.

    Ниже код чанка и затем пояснение по некоторым моментам:

    {if $_modx->resource.id == '832'?}
                <div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
                    {foreach ($_modx->resource.AccordionSections | fromJSON) as $AccordionSection}
                    {var $sectionIds = $AccordionSection.MIGX_id}
                    <p class="accordion-section-title">{$AccordionSection.sectionTitle}</p>
                    {foreach ($AccordionSection.sectionContent | fromJSON) as $AccordionItem}
                    <div class="panel panel-default">
                        {var $accordionIds = $AccordionItem.MIGX_id}
                        <div class="panel-heading" role="tab" id="h{$sectionIds}-{$accordionIds}">
                            <h4 class="panel-title">
                                <a role="button" data-toggle="collapse" data-parent="#accordion" href="#c{$sectionIds}-{$accordionIds}" aria-expanded="true" aria-controls="c{$sectionIds}-{$accordionIds}">
                                    <i class="more-less glyphicon glyphicon-plus"></i>
                                    <span class="accordion-section-header">{$AccordionItem.title}</span>
                                </a>
                            </h4>
                        </div>
                        <div id="c{$sectionIds}-{$accordionIds}" class="panel-collapse collapse" role="tabpane{$sectionIds}-{$accordionIds}" aria-labelledby="h{$sectionIds}-{$accordionIds}">
                            <div class="panel-body">
                                  {$AccordionItem.description}
                            </div>
                        </div>
                    </div>
                    {/foreach}
                {/foreach}
                </div><!-- panel-group -->
            {else}
                <div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
                    {var $otherAccSections = 832 | resource : 'AccordionSections'}
                    
                    {foreach ($otherAccSections | fromJSON) as $AccordionSection}
    
                    {var $sectionIds = $AccordionSection.MIGX_id}
                    <p class="accordion-section-title">{$AccordionSection.sectionTitle}</p>
                    {foreach ($AccordionSection.sectionContent | fromJSON) as $AccordionItem}
                    <div class="panel panel-default">
                        {var $accordionIds = $AccordionItem.MIGX_id}
                        <div class="panel-heading" role="tab" id="h{$sectionIds}-{$accordionIds}">
                            <h4 class="panel-title">
                                <a role="button" data-toggle="collapse" data-parent="#accordion" href="#c{$sectionIds}-{$accordionIds}" aria-expanded="true" aria-controls="c{$sectionIds}-{$accordionIds}">
                                    <i class="more-less glyphicon glyphicon-plus"></i>
                                    <span class="accordion-section-header">{$AccordionItem.title}</span>
                                </a>
                            </h4>
                        </div>
                        <div id="c{$sectionIds}-{$accordionIds}" class="panel-collapse collapse" role="tabpane{$sectionIds}-{$accordionIds}" aria-labelledby="h{$sectionIds}-{$accordionIds}">
                            <div class="panel-body">
                                  {$AccordionItem.description}
                            </div>
                        </div>
                    </div>
                    {/foreach}
                {/foreach}
                </div>
            {/if}
    • Для вывода данных используется простой разбор полей с помощью foreach
    • Для того чтобы секции аккордеона имели уникальные уникальные css классы и айди использовались поля MIGx конфигураций MIGX_id и создавались переменные для того чтобы не запутаться в коде.
    • В чанке условие, если айди ресурса тот для которого изначально создавалось TV поле с аккордеоном, то код имеет вид наподобие
      {$_modx->resource.AccordionSections}
      , если ресурс имеет любой другой айди то в коде указывается айди и поля ресурса которые нужно разобрать
      {832 | resource : 'AccordionSections'}
    • При разборе полей TV уровня, то есть AccordionSections когда доходим до поля sectionContent, производим еще один разбор этого поля как TV типа MIGx ведь оно в себе как раз и содержит вложенный TV второго уровня, то есть AccordionItems
Вот такое решение, надеюсь кому нибудь пригодится.
Sergey Leleko
08 июня 2018, 04:54
modx.pro
9
3 915
0

Комментарии: 8

UDAV
08 июня 2018, 10:30
+1
Замудрил конечно) Все делается намного проще если сразу код migx указывать в tv поле.

id получить тоже можно гораздо проще.
{foreach ($AccordionSection.sectionContent | fromJSON) as $idx => $AccordionItem}
в $idx будет id нужный
    Баха Волков
    08 июня 2018, 10:52
    0
    Я на счёт этого промолчал, хотя и вот это тоже мне не понятно, думал, что еще кого-то обижу (много людей сейчас обижаются):

    {var $accordionIds = $AccordionItem.MIGX_id}

    Зачем засовывать в переменную что-то, если в этом нет необходимости, разве что для удобство…
      Sergey Leleko
      08 июня 2018, 11:11
      0
      мне так удобнее было, не знаю какие обиды.
        Баха Волков
        08 июня 2018, 11:55
        0
        Да я то не про вас лично :), тем более я так и написал:
        разве что для удобствА…
    Баха Волков
    08 июня 2018, 10:47
    +3
    Сразу извиняюсь, просто если раньше нужно было так делать, то сейчас можно и попроще и без лишних TV

    1)
    Далее настроил форму, причем в поле description в качестве inputTV можно было ничего не указывать, я указал созданный заранее простой TV с визуальным редактором TinyMCE чтобы было удобно наполнять текстом. Если бы не указал, то было бы простое текстовое поле:

    TV создавать бессмысленно, так как есть Input TV type в котором нужно указывать тип поля, т.е. достаточно указать richtext и всё. Результат: Тот же, зато нет лишнего TV.

    2)
    После чего создаем TV поле одноименное, с указанием типа MIGx и имени его конфигурации AccordionItems.

    Это из той же оперы, зачем создавать TV, если есть Input TV type и Configs которому в json формате можно передать все параметры, т.е. можно например так:

    Input TV type указать number и передать ему что-то типа:

    {
       "allowDecimals":"No",
       "allowNegative":"No"
    }
    т.е. здесь я вместо того чтобы создавать лишний TV с типом ввода «Число», где «Разрешить десятичные» и «Разрешить минус» поставил бы «Нет» и данный TV у меня просто бы висел в админке и в БД так и не пригодившись, я указываю MIGX-у.

    В вашем же случае нужно так:


    Фотография кликабельна

    Спасибо за внимание!
      mngatoff
      08 июня 2018, 15:15
      +1
      в данном случае в конфиге не нужен json — достаточно просто указать AccordionItems. JSON нужен только для полей, отличных от migx
      Sergey Leleko
      08 июня 2018, 10:52
      1
      +2
      Спасибо за конструктивную критику и разъяснения. Решение сам искал, не знал что можно было сделать иначе)
        Илья Уткин
        09 июня 2018, 07:01
        +2
        А если бы статью не написал, то и не узнал бы) и другие тоже почитают комменты и что-то для себя вынесут (я, например, тоже новое прочитал).
        Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
        8