前几天,我试图做一些我认为很简单的事情,但事实证明,要想真正做到这一点真的很困难。我有一个安装了Paragraphs的Drupal 9网站,我希望用户单击节点编辑表单上的按钮,然后将一个特定的Paragraph注入到Paragraph字段中。
我找到了解决此问题的2种解决方案,它们以略有不同的方式解决了该问题。
在最初尝试使此方法生效之后,我决定使用背负式方法。这实质上是在侦听用户交互,然后触发将段落插入字段中的“段落添加”事件。我正在听的用户交互是用户在选择列表中选择不同的元素。
为了使此工作正常进行,我在页面上添加了一些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流和所得到的响应。浏览“段落”模块使我想到了各种不同的代码,这些代码似乎并没有真正产生所需的结果。在运行了几次代码之后,我能够将所需的组件提取到单个模块中。
这里需要的第一件事是一个表单元素,以控制将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处理程序。为了使此提交按钮正常工作,需要三件事。
提交callack,在提交按钮后调用。在上面的字段中,已将其创建为静态方法,然后放入类中。
一个limit_validation_errors。顾名思义,这将限制表单将产生的验证错误的数量。在这种情况下,我们告诉Drupal仅验证段落字段中是否存在错误,并在表单的其余部分执行“部分提交”。
在提交处理程序之后,在提交按钮时调用的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注入到表单中。但是,如果您要这样做的话,这应该是足够的信息,可以助您一臂之力。表单状态被传递给两个函数,因此您应该能够对其进行检查并查看已选择的内容,然后相应地修改代码。
本质上,事件的顺序如下。
用户单击节点表单上的新“插入段落”按钮。
对Drupal进行了ajax调用。
Drupal表单处理开始。
触发名为addParagraphSubmit的提交处理程序。在这一步中,我们使用具有“ selected_bundle”属性的占位符小部件为要添加到表单中的段落实体注入占位符。我们添加的段落实体称为“详细信息”。
调用内部的Paragraph渲染函数,然后使用空白的Paragraph实体表单填充表单元素。
触发了名为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,但它似乎无法解决我的问题,因为在调用这些方法之前,我需要识别实际节点是否处于编辑模