当前位置: 首页 > 编程笔记 >

Drupal 9:在节点编辑页面上自动注入段落形式

章烨烨
2023-03-14
本文向大家介绍Drupal 9:在节点编辑页面上自动注入段落形式,包括了Drupal 9:在节点编辑页面上自动注入段落形式的使用技巧和注意事项,需要的朋友参考一下

前几天,我试图做一些我认为很简单的事情,但事实证明,要想真正做到这一点真的很困难。我有一个安装了Paragraphs的Drupal 9网站,我希望用户单击节点编辑表单上的按钮,然后将一个特定的Paragraph注入到Paragraph字段中。

我找到了解决此问题的2种解决方案,它们以略有不同的方式解决了该问题。

ggy回现有事件

在最初尝试使此方法生效之后,我决定使用背负式方法。这实质上是在侦听用户交互,然后触发将段落插入字段中的“段落添加”事件。我正在听的用户交互是用户在选择列表中选择不同的元素。

为了使此工作正常进行,我在页面上添加了一些JavaScript,并将其附加到名为“ field_type”的选择列表字段中。

function my_module_form_node_page_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state)
{
  $form['field_type']['widget']['#attached']['library'][] = 'my_module/node';
}

node:
  js:
    js/piggy-back.js: {}
  dependencies:
    - core/drupal

这将加载到名为piggy-back.js的JavaScript文件中。

如下所示,该文件用于将附加到不同“段落”添加按钮的不同事件汇总在一起。当用户更改字段类型选择列表时,将触发一个事件,然后触发一个段落事件。

(function ($, Drupal, drupalSettings) {
 
  'use strict';
 
  Drupal.behaviors.bform = {
    attach : function(context, settings) {
      // 加载现有的更改事件。
      var paragraphDetailEvents = $._data($("#field-paragraph-detail-add-more")[0], "events");
      var paragraphHeaderEvents = $._data($("#field-paragraph-header-add-more")[0], "events");
 
      $('#edit-field-type').change(function(event) {
        let changeValue = $(this).val();
        if (changeValue == 1) {
          $.each(paragraphDetailEvents.mousedown, function () {
            this.handler(event);
          });
        }
        if (changeValue == 2) {
          $.each(paragraphHeaderEvents.mousedown, function () {
            this.handler(event);
          });
        }
      });
    }
  };
 
})(jQuery, Drupal);

您可能可以修改此代码以适合您的需求,但这是对实际产生预期结果的问题的简单解决方案

注入段落按钮Ajax回调

尽管搭载方法有效,但我真正想做的是完全控制ajax流和所得到的响应。浏览“段落”模块使我想到了各种不同的代码,这些代码似乎并没有真正产生所需的结果。在运行了几次代码之后,我能够将所需的组件提取到单个模块中。

这里需要的第一件事是一个表单元素,以控制将Paragraph实体表单注入到页面中。这由提交按钮处理,该提交按钮使用hook_form_node_page_form_alter()挂钩插入到节点编辑表单中。该按钮被注入到名为“ field_type”的字段旁边,但是我已经对此进行了抽象,以便您可以将其移动到所需的任何位置。段落字段名称还需要在顶部抽象为一个变量,因此您可以将其指向所需的任何段落字段。对“添加更多”字段和类名称的引用将与Paragraph表单本身集成在一起。

    function my_module_form_node_page_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state)
    {
      $paragraphFieldName = 'field_paragraph';
      $injectParagraphFieldName = 'field_type';
     
      $paragraphField = NestedArray::getValue($form, [$paragraphFieldName]);
     
      $injectParagraphField = NestedArray::getValue($form, [$injectParagraphFieldName]);
     
      $injectParagraphField['inject_paragraph'] = [
        '#type' => 'submit',
        '#name' => 'field_type_my_module',
        '#value' => t('Inject Paragraph'),
        '#attributes' => ['class' => ['field-set-selection-submit']],
        '#limit_validation_errors' => [array_merge($paragraphField['#parents'], [$paragraphFieldName, 'add_more'])],
        '#submit' => [['\Drupal\my_module\InjectParagraph', 'addParagraphSubmit']],
        '#ajax' => [
          'callback' => ['\Drupal\my_module\InjectParagraph', 'addParagraphAjax'],
          'wrapper' => str_replace('_', '-', $paragraphFieldName) . '-add-more-wrapper',
          'effect' => 'fade',
          'progress' => [
            'type' => 'fullscreen',
          ]
        ],
      ];
      NestedArray::setValue($form, [$injectParagraphFieldName], $injectParagraphField);
    }

    该按钮将充当用户输入,并在元素周围包装Submit和ajax处理程序。为了使此提交按钮正常工作,需要三件事。

    1. 提交callack,在提交按钮后调用。在上面的字段中,已将其创建为静态方法,然后放入类中。

    2. 一个limit_validation_errors。顾名思义,这将限制表单将产生的验证错误的数量。在这种情况下,我们告诉Drupal仅验证段落字段中是否存在错误,并在表单的其余部分执行“部分提交”。

    3. 在提交处理程序之后,在提交按钮时调用的Ajax回调。同样,它已被抽象到一个单独的类中。

    包含addParagraphSubmit和addParagraphAjax处理程序的类是执行操作的地方。这是完整的课程,我添加了很多评论以显示正在发生的事情。

    <?php
     
    namespace Drupal\my_module;
     
    use Drupal\Component\Utility\NestedArray;
    use Drupal\Core\Field\FieldStorageDefinitionInterface;
    use Drupal\Core\Form\FormStateInterface;
    use Drupal\paragraphs\Plugin\Field\FieldWidget\ParagraphsWidget;
     
    class InjectParagraph {
     
      public static function addParagraphSubmit(array $form, FormStateInterface $form_state)
      {
        // 设置有问题的段落字段。
        $paragraphFieldName = 'field_paragraph';
     
        // 从表单中提取段落字段。
        $element = NestedArray::getValue($form, [$paragraphFieldName, 'widget']);
        $field_name = $element['#field_name'];
        $field_parents = $element['#field_parents'];
     
        // 获取窗口小部件状态。
        $widget_state = static::getWidgetState($field_parents, $field_name, $form_state);
     
        // 插入新段落并增加项目数。
        $widget_state['selected_bundle'][] = 'detail';
        $widget_state['items_count']++;
     
        // 更新小部件状态。
        static::setWidgetState($field_parents, $field_name, $form_state, $widget_state);
     
        // 重建表格。
        $form_state->setRebuild();
      }
     
      public static function addParagraphAjax(array $form, FormStateInterface $form_state)
      {
        // 设置有问题的段落字段。
        $paragraphFieldName = 'field_paragraph';
     
        // 从表单中提取段落字段。
        $element = NestedArray::getValue($form, [$paragraphFieldName, 'widget']);
     
        // 使用所需的Ajax格式更新字段。
        $delta = $element['#max_delta'];
        $element[$delta]['#prefix'] = '<div>' . (isset($element[$delta]['#prefix']) ? $element[$delta]['#prefix'] : '');
        $element[$delta]['#suffix'] = (isset($element[$delta]['#suffix']) ? $element[$delta]['#suffix'] : '') . '</div>';
     
        // 从段落模块中清除添加更多增量。
        NestedArray::setValue(
          $element,
          ['add_more', 'add_more_delta', '#value'],
          ''
        );
     
        // 返回段落元素。
        return $element;
      }
     
      public static function getWidgetState(array $parents, $field_name, FormStateInterface $form_state) {
        return NestedArray::getValue($form_state->getStorage(), array_merge(['field_storage', '#parents'], $parents, ['#fields', $field_name]));
      }
     
      public static function setWidgetState(array $parents, $field_name, FormStateInterface $form_state, array $field_state) {
        NestedArray::setValue($form_state->getStorage(), array_merge(['field_storage', '#parents'], $parents, ['#fields', $field_name]), $field_state);
      }
    }

    如果您熟悉“段落”模块,那么您会认出其中的一些代码,因为这些部分已从“段落”模块中获取。我需要复制和粘贴此处所需的一些代码,因为它们在Paragraph小部件中被设置为私有或受保护的方法,因此无法访问。我在这里省略了一些细节,因为代码只会将一种类型的Paragraph注入到表单中。但是,如果您要这样做的话,这应该是足够的信息,可以助您一臂之力。表单状态被传递给两个函数,因此您应该能够对其进行检查并查看已选择的内容,然后相应地修改代码。

    本质上,事件的顺序如下。

    1. 用户单击节点表单上的新“插入段落”按钮。

    2. 对Drupal进行了ajax调用。

    3. Drupal表单处理开始。

    4. 触发名为addParagraphSubmit的提交处理程序。在这一步中,我们使用具有“ selected_bundle”属性的占位符小部件为要添加到表单中的段落实体注入占位符。我们添加的段落实体称为“详细信息”。

    5. 调用内部的Paragraph渲染函数,然后使用空白的Paragraph实体表单填充表单元素。

    6. 触发了名为addParagraphAjax的ajax处理程序。在此步骤中,将显示空的Paragraph实体表单,只是将其包装在某些HTML中,以便该表单的行为与普通的Paragraph表单相同。

    如您所见,在这里既需要提交处理程序,也需要ajax处理程序,以便正确插入Paragraph实体表单。如果没有将提交处理程序称为ajax处理程序,则它什么也不会做。确保同时调用这两个处理程序,这取决于我们注入的表单元素中的limit_validation_errors设置。如果缺少此元素,则仅调用ajax处理程序,该过程太迟了,无法添加Paragraph实体。我以前没有使用过此设置,因此不确定它做了什么,因此我什至可以就此设置撰写一篇完全独立的文章,因为它极大地改变了ajax回调的工作方式。

    经过数小时的调试,实验和调整,以上所有代码均已组合在一起。希望对您有用。

     类似资料:
    • 基于“在购物车和订单项名称下显示伍兹商业产品自定义字段”回答我以前的一个问题,代码在产品编辑页面上显示自定义字段。当填写这些字段时,数据将显示在产品页面上。 下面是代码: 如何在“管理”面板的“编辑订单”页面上显示自定义字段?它应该在产品名称后显示这些字段。 更新 据我所知,woocommerce\u checkout\u create\u order\u line\u item对此负责。但我无法

    • 问题内容: 我正在使用itext生成pdf文件。我想在页面中间对齐标题。目前我正在使用这样 是正确的还是有其他最佳方法来做到这一点? 问题答案: 用途: 有关更多可能值,请参见界面中的常量。

    • 点击任意文档进入编辑页面。 1.左上角显示当前文档的标题,点击可快速切换最近编辑的文档。 2.右侧四个按钮分别是 思维导图:点击可进入思维导图模式 演示模式:点击可进入演示模式 分享:对文档进行分享相关操作 帮助:查看简明教程、快捷键列表、反馈建议 3.右上角更多功能 界面设置:可设置是否自动收缩描述、夜间模式、自适应宽度等 导出/下载:将该文档导出为本地文件 打印:使用打印机打印该文档 返回:回

    • 7.6. 编辑页面 编辑功能是wiki不可缺少的。现在,我们创建两个新的处理函数(handler):editHandler显示"edit page"表单(form),saveHandler保存表单(form)中的数据。 首先,将他们添加到main()函数中: func main() { http.HandleFunc("/view/", viewHandler) htt

    • 我想将woocommerce结帐页面的“订单注释”文本字段更改为“特殊注释”。但是我找不到这个文件的确切位置。在我的localhost文件夹中可以在哪里找到此文件? 这是页面的截图:

    • 我想知道如何实现这个功能: 我有一个可编辑的JTree,可以编辑节点的名称。如果我有一个节点是分支节点(其中有一些叶节点),并且该分支节点在编辑时展开,编辑后,该节点将折叠。 编辑完成后,如果分支节点打开,我想让它保持打开状态,如果分支节点折叠,我想让它折叠。 我试图查看TreeWireExpandListener,但它似乎无法解决我的问题,因为在调用这些方法之前,我需要识别实际节点是否处于编辑模