隐藏表单字段
Creating your business website with any CMS requires you to make the back-end user friendly, and that means making the forms meaningful and accessible. In this article, we’re going to explore OctoberCMS form widgets and create a widget called UniqueValue
, which helps the user enter a unique value. This could be useful for entering emails, usernames, post slugs, etc. Let’s get started.
使用任何CMS创建业务网站都需要使后端用户友好,这意味着使表格有意义且易于访问。 在本文中,我们将探索OctoberCMS表单小部件,并创建一个名为UniqueValue
小部件,该小部件可帮助用户输入唯一值。 这对于输入电子邮件,用户名,帖子内容等很有用。让我们开始吧。
可用的表单小部件 (Available Form Widgets)
OctoberCMS provides a list of simple field types like email input, password, dropdown options, etc. The documentation has a list of all available fields. Moreover, the CMS provides some custom widgets like the media manager widget which lets you select an item from your media library or the WYSIWYG editor, Markdown editor, etc.
OctoberCMS提供了简单字段类型的列表,例如电子邮件输入,密码,下拉选项等。 文档中包含所有可用字段的列表。 此外,CMS还提供了一些自定义小部件,例如媒体管理器小部件,可让您从媒体库或WYSIWYG编辑器,Markdown编辑器等中选择一个项目。
An interesting widget we should mention here is the repeater widget. Let’s say you have a recipes website. The cook will enter the recipe name and start filling in the ingredients. You might ask the user “how many ingredients do you need?” and based on that, you can generate the form fields. Another clean way to do it is to have a button at the bottom of the form that says Add new ingredient
, which will generate the necessary fields for the cook when needed.
我们应该在这里提到的一个有趣的小部件是转发器小部件 。 假设您有一个食谱网站。 厨师将输入食谱名称,并开始填写食材。 您可能会问用户“您需要多少成分?” 基于此,您可以生成表单字段。 另一种干净的方法是在表格底部有一个按钮,上面写着Add new ingredient
,它将在需要时为厨师生成必要的字段。
Here is an example configuration for the recipe form:
这是配方表格的示例配置:
// models/recipe/fields.yaml
fields:
name:
label: Name
type: text
required: true
ingredients:
label: Ingredients
type: repeater
prompt: Add new ingredient
form:
fields:
ingredient:
label: Ingredient
type: text
how_much:
label: How much
type: number
unit:
label: Unit
type: dropdown
options:
spoon: Spoon
ounce: Ounce
# etc
创建一个表单小部件 (Creating a Form Widget)
If you read the previous OctoberCMS article (you should, it’s great!), you’ll know that we built a CRUD plugin. We’ll be using it in this article, so make sure to clone it into your OctoberCMS installation.
如果您阅读了上一篇OctoberCMS的文章 (您应该很棒,那太好了!),您会知道我们构建了一个CRUD插件 。 我们将在本文中使用它,因此请确保将其克隆到OctoberCMS安装中。
# Inside your plugins folder
git clone git@github.com:Whyounes/OctoberCMS_Sitepoint_plugin_demo.git rafie/sitepointDemo
You can check the final code for this tutorial in the uniqueValue-formwidget
branch in the same repo.
您可以检查最终代码本教程中uniqueValue-formwidget
分支在同一回购 。
To start building our widget, we use the create:formwidget
scaffolding command which creates a view folder, assets folder and a FormWidgetBase
class.
要开始构建窗口小部件,我们使用create:formwidget
脚手架命令,该命令将创建视图文件夹,资产文件夹和FormWidgetBase
类。
php artisan create:formwidget rafie.SitepointDemo UniqueValue
Our UniqueValue
widget requires three properties:
我们的UniqueValue
小部件需要三个属性:
modelClass
: The model class that will have the unique field.modelClass
:将具有唯一字段的模型类。selectFrom
: The field name inside the model. Defaults toname
.selectFrom
:模型内的字段名称。 默认为name
。pattern
: The displayed input type (text
,email
,number
,url
). Defaults totext
.pattern
:显示的输入类型(text
,email
,number
,url
)。 默认为text
。
After our form widget class is constructed, it will automatically call the inherited init
method, which is responsible for preparing our widget for rendering.
构造窗体小部件类后,它将自动调用继承的init
方法,该方法负责准备要渲染的小部件。
// formwidgets/UniqueValue.php
class UniqueValue extends FormWidgetBase
{
/**
* {@inheritDoc}
*/
protected $defaultAlias = 'rafie_sitepointDemo_uniquevalue';
/**
* {@inheritDoc}
*/
public function init()
{
}
}
Our parent WidgetBase
class provides a fillFromConfig
helper method which maps the passed config properties from the fields.yaml
file to the form widget class’ attributes.
我们的父WidgetBase
类提供了fillFromConfig
帮助器方法,该方法将传递的config属性从fields.yaml
文件映射到表单小部件类的属性。
// formwidgets/UniqueValue.php
class UniqueValue extends FormWidgetBase
{
/*
* Config attributes
*/
protected $modelClass = null;
protected $selectFrom = 'name';
protected $pattern = 'text';
/**
* {@inheritDoc}
*/
protected $defaultAlias = 'rafie_sitepointDemo_uniquevalue';
/**
* {@inheritDoc}
*/
public function init()
{
$this->fillFromConfig([
'modelClass',
'selectFrom',
'pattern'
]);
$this->assertModelClass();
parent::init();
}
// ...
}
After calling the fillFromConfig
function, we assert that the model class exists and then call the parent init
method.
调用fillFromConfig
函数后,我们断言模型类存在,然后调用父init
方法。
// formwidgets/UniqueValue.php
class UniqueValue extends FormWidgetBase
{
// ...
protected function assertModelClass()
{
if( !isset($this->modelClass) || !class_exists($this->modelClass) )
{
throw new \InvalidArgumentException(sprintf("Model class {%s} not found.", $this->modelClass));
}
}
// ...
}
// formwidgets/uniquevalue/UniqueValue.php
class UniqueValue extends FormWidgetBase
{
// ...
public function render()
{
$this->prepareVars();
return $this->makePartial('uniquevalue');
}
/**
* Prepares the form widget view data
*/
public function prepareVars()
{
$this->vars['inputType'] = $this->pattern;
$this->vars['name'] = $this->formField->getName();
$this->vars['value'] = $this->getLoadValue();
$this->vars['model'] = $this->model;
}
}
OctoberCMS will look for the partial inside the partials
folder and pass the $this->vars
array to it.
OctoberCMS将在partials
文件夹中查找partial,然后将$this->vars
数组传递给它。
// formwidgets/uniquevalue/partials/_uniquevalue.htm
<?php if ($this->previewMode): ?>
<div class="form-control">
<?= $value ?>
</div>
<?php else: ?>
<div class="input-group">
<input
type="<?= $inputType ?>"
id="<?= $this->getId('input') ?>"
name="<?= $name ?>"
value="<?= $value ?>"
class="form-control unique_widget"
autocomplete="off"
/>
<span class="input-group-addon oc-icon-remove"></span>
</div>
<?php endif ?>
The input has a preview and an editing mode. When editing, we display an input and fill the type using the specified pattern. The value is automatically set in this case if we are updating a record. The span.input-group-addon
element will display a check or a remove icon depending on the entered value.
输入具有预览和编辑模式。 在编辑时,我们显示输入并使用指定的模式填充类型。 如果我们要更新记录,则在这种情况下将自动设置该值。 span.input-group-addon
元素将根据输入的值显示选中或删除图标。
使用AJAX (Using AJAX)
OcotberCMS has a set of scripts that let you update your content using HTML5 data attributes and AJAX handlers. We may cover it in detail in another article, but you can refer to the documentation for more details right now, if you’re curious.
OcotberCMS具有一组脚本,使您可以使用HTML5数据属性和AJAX处理程序来更新内容。 我们可能会在另一篇文章中对其进行详细介绍,但是如果您感到好奇,可以立即参考文档以获取更多详细信息。
We’re going to check if the entered value is unique when the input value changes. First we need to add the data-request
attribute which specifies the backend method handler name.
当输入值更改时,我们将检查输入值是否唯一。 首先,我们需要添加data-request
属性,该属性指定后端方法处理程序名称。
// formwidgets/uniquevalue/partials/_uniquevalue.htm
// ...
<input
type="<?= $inputType ?>"
id="<?= $this->getId('input') ?>"
name="<?= $name ?>"
value="<?= $value ?>"
class="form-control unique_widget"
autocomplete="off"
data-request="onChange"
/>
// ...
Next, we specify the JS function that will handle a successful request’s response using the data-request-success
attribute. It will receive a list of parameters, but the most important ones are $el
, which refers to our input, and the data
parameter, which holds the request’s result.
接下来,我们使用data-request-success
属性指定JS函数来处理成功请求的响应。 它会收到一个参数列表,但是最重要的是$el
,它引用我们的输入,而data
参数则保存请求的结果。
// formwidgets/uniquevalue/partials/_uniquevalue.htm
// ...
<input
type="<?= $inputType ?>"
id="<?= $this->getId('input') ?>"
name="<?= $name ?>"
value="<?= $value ?>"
class="form-control unique_widget"
autocomplete="off"
data-request="onChange"
data-request-success="uniqueInputChanged($el, context, data, textStatus, jqXHR);"
/>
// ...
OctoberCMS’ AJAX framework provides a data-track-input
attribute to trigger the data-request
handler if the element has changed. It accepts an optional delay parameter which we can use to minimize the number of sent requests.
OctoberCMS的AJAX框架提供了data-track-input
属性,以在元素发生更改时触发data-request
处理程序。 它接受一个可选的delay参数,我们可以使用该参数来最小化已发送请求的数量。
// formwidgets/uniquevalue/partials/_uniquevalue.htm
// ...
<input
type="<?= $inputType ?>"
id="<?= $this->getId('input') ?>"
name="<?= $name ?>"
value="<?= $value ?>"
class="form-control unique_widget"
autocomplete="off"
data-request="onChange"
data-request-success="uniqueInputChanged($el, context, data, textStatus, jqXHR);"
data-track-input="500"
/>
// ...
We still didn’t define our onChange
handler method inside our form widget class. OctoberCMS will look for a handler with the same name inside the backend page controller or any other widgets used. To avoid conflicts, we use the fully prefixed handler name which will include our widget alias.
我们仍然没有在表单小部件类中定义onChange
处理程序方法。 OctoberCMS将在后端页面控制器或使用的任何其他小部件内查找具有相同名称的处理程序。 为了避免冲突,我们使用全前缀的处理程序名称,其中将包含我们的小部件别名。
// formwidgets/uniquevalue/partials/_uniquevalue.htm
// ...
<input
// ...
data-request="<?= $this->getEventHandler('onChange') ?>"
// ...
/>
// ...
// formwidgets/uniquevalue/UniqueValue.php
class UniqueValue extends FormWidgetBase
{
// ...
public function onChange()
{
$formFieldValue = post($this->formField->getName());
$modelRecords = $this->model->newQuery()->where($this->selectFrom, $formFieldValue);
return ['exists' => (boolean) $modelRecords->count()];
}
// ...
}
$this->formField->getName()
returns the input name that we use to get the input value from the post data. Then, we call the modelClass::where
method with the selectFrom
config value and the post data.
$this->formField->getName()
返回我们用来从发布数据中获取输入值的输入名称。 然后,我们使用selectFrom
config值和post数据调用modelClass::where
方法。
The only thing left is to process the request’s result using the JavaScript function defined in our data-request-success
attribute. Our CSS and JavaScript assets are loaded inside the UniqueValue@loadAsserts
method.
剩下的唯一事情就是使用我们在data-request-success
属性中定义JavaScript函数处理请求的结果。 我们CSS和JavaScript资产已加载到UniqueValue@loadAsserts
方法中。
// formwidgets/uniquevalue/UniqueValue.php
class UniqueValue extends FormWidgetBase
{
// ...
public function loadAssets()
{
// $this->addCss('css/uniquevalue.css', 'rafie.SitepointDemo');
$this->addJs('js/uniquevalue.js', 'rafie.SitepointDemo');
}
// ...
}
// formwidgets/uniquevalue/assets/js/uniquevalue.js
function uniqueInputChanged($el, context, data, textStatus, jqXHR)
{
var addon = $el.parents('.input-group').find('.input-group-addon');
if( !$el.val().trim() || data.exists )
{
addon.removeClass('oc-icon-check').addClass('oc-icon-remove');
return;
}
addon.removeClass('oc-icon-remove').addClass('oc-icon-check');
}
We query our addon element, test the return value, and set the appropriate icon class on the element. You can test the widget by inserting the below code inside your model fields configuration file.
我们查询addon元素,测试返回值,并在该元素上设置适当的图标类。 您可以通过在模型字段配置文件中插入以下代码来测试窗口小部件。
// fields.yaml
fields:
slug:
label: Slug
type: \Rafie\SitepointDemo\FormWidgets\UniqueValue
modelClass: \RainLab\Blog\Models\Post
selectFrom: slug
pattern: text
This is a final demo of the widget.
这是小部件的最终演示。
As a final step, we will register our form widget as a system widget (text
, checkboxlist
, etc).
最后一步,我们将表单小部件注册为系统小部件( text
, checkboxlist
等)。
// Plugin.php
// ...
/**
* Registers any form widgets implemented in this plugin.
*/
public function registerFormWidgets()
{
return [
'Rafie\SitepointDemo\FormWidgets\UniqueValue' => [
'label' => 'Unique Value',
'code' => 'uniquevalue'
],
];
}
// ...
Now, we can use our widget by using the registered code.
现在,我们可以使用注册的代码来使用小部件。
// fields.yaml
fields:
slug:
label: Slug
type: uniquevalue
modelClass: \RainLab\Blog\Models\Post
selectFrom: slug
pattern: text
结论 (Conclusion)
In this article, we explored the OcotberCMS backend form field widgets and we built a simple demo widget to test it. You can extend the final widget by adding new functionality, like adding a preventSubmit
option when the value is not unique, etc. You can check the final version on Github and if you have any questions or comments you can leave them below and I’ll do my best to answer them.
在本文中,我们探索了OcotberCMS后端表单字段小部件,并构建了一个简单的演示小部件对其进行测试。 您可以通过添加新功能来扩展最终的小部件,例如在值不唯一时添加preventSubmit
选项等。您可以在Github上检查最终版本,如果有任何疑问或意见,可以将其保留在下面,我将尽我所能回答他们。
翻译自: https://www.sitepoint.com/building-octobercms-form-field-widgets-like-a-pro/
隐藏表单字段