我正在寻找一种创建自定义操作按钮的方法,该按钮允许我使用来自另一个数据对象的预填充内容创建新的数据对象。举个简单的例子:当我收到一封电子邮件并单击电子邮件客户端中的"回答"按钮时,我会得到一个新窗口,其中包含之前电子邮件中预先填充的内容。我的按钮正是需要此功能。此按钮应显示在网格字段中的每个数据对象旁边。
所以我知道如何制作一个按钮并将其添加到我的 GridField (--> https://docs.silverstripe.org/en/3.2/developer_guides/forms/how_tos/create_a_gridfield_actionprovider/),并且我知道如何转到新的数据对象:
Controller::curr()->redirect($gridField->Link('item/new'));
我还发现数据对象有一个重复的函数:
public function duplicate($doWrite = true) {
$className = $this->class;
$clone = new $className( $this->toMap(), false, $this->model );
$clone->ID = 0;
$clone->invokeWithExtensions('onBeforeDuplicate', $this, $doWrite);
if($doWrite) {
$clone->write();
$this->duplicateManyManyRelations($this, $clone);
}
$clone->invokeWithExtensions('onAfterDuplicate', $this, $doWrite);
return $clone;
}
也许这比我想象的要容易,但目前我只是不知道如何重写它以获得我需要的东西。有人可以给我一个提示吗?
这肯定不是最干净的解决方案,但我认为它应该可以解决问题。
首先,让我们创建自定义网格字段操作。在这里,我们将在一个会话中保存所有可访问的记录,并向 url 添加一个查询字符串,以便我们知道我们要"克隆"哪个对象
public function getColumnContent($gridField, $record, $columnName) {
if(!$record->canEdit()) return;
$field = GridField_FormAction::create(
$gridField,
'clone'.$record->ID,
'Clone',
'clone',
array('RecordID' => $record->ID)
);
$values = Session::get('ClonedData');
$data = $record->data()->toMap();
if($arr = $values) {
$arr[$record->ID] = $data;
} else {
$arr = array(
$record->ID => $data
);
}
Session::set('ClonedData', $arr);
return $field->Field();
}
public function getActions($gridField) {
return array('clone');
}
public function handleAction(GridField $gridField, $actionName, $arguments, $data) {
if($actionName == 'clone') {
$id = $arguments['RecordID'];
Controller::curr()->redirect($gridField->Link("item/new/?cloneID=$id"));
}
}
将此新组件添加到我们的网格字段后,
$gridField->getConfig()->addComponent(new GridFieldCustomAction());
我们需要将数据引入新表单。为此,请将此代码直接添加到getCMSFields函数的"return $fields"上方,以便每次我们打开此类对象时都会执行它。
$values = Session::get('ClonedData');
if($values) {
Session::clear('ClonedData');
$json = json_encode($values);
$fields->push(LiteralField::create('ClonedData', "<div id='cloned-data' style='display:none;'>$json</div>"));
}
最后,我们需要将内容带回田间。我们将使用一些 javascript 来做到这一点,因此首先您需要创建一个新的 script.js 文件并将其包含在 ss 后端中(或仅使用现有文件)。
(function($) {
$('#cloned-data').entwine({
onmatch: function() {
var data = JSON.parse($(this).text()),
id = getParameterByName('cloneID');
if(id && data) {
var obj = data[id];
if(obj) {
$.each(obj, function(i, val) {
$('[name=' + i + ']').val(val);
});
}
}
}
});
// http://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript#answer-901144
function getParameterByName(name) {
name = name.replace(/[[]/, "\[").replace(/[]]/, "\]");
var regex = new RegExp("[\?&]" + name + "=([^&#]*)"),
results = regex.exec(location.search);
return results === null ? "" : decodeURIComponent(results[1].replace(/+/g, " "));
}
})(jQuery);
就是这样...相当棘手。希望它能解决你的问题。