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处理程序。为了使此提交按钮正常工作,需要三件事。
提交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回调的工作方式。
经过数小时的调试,实验和调整,以上所有代码均已组合在一起。希望对您有用。
以上是 Drupal 9:在节点编辑页面上自动注入段落形式 的全部内容, 来源链接: utcz.com/z/350535.html