自定义 Bitbucket 合并检查 - 动态字段在提交配置后呈现两次
Custom Bitbucket Merge Check - dynamic fields render twice after submitting the configuration
我正在为 Bitbucket 创建自定义合并检查。我开始遵循本教程:
https://developer.atlassian.com/server/bitbucket/how-tos/hooks-merge-checks-guide/
我希望视图是动态的,例如具有创建多个相似输入字段(指定 ID)的按钮,这些输入字段最终存储在配置中。
首先,我为此使用了 soy - 我创建了静态模板并调用了一个模板,例如。文本域。它工作正常,但我无法即时创建新的类似字段(按下 'Add new' 按钮后)。
所以我使用JavaScript从soy的配置中获取数据。我将整个配置重写为 JS "map",然后动态呈现所有字段(通过将它们附加到 HTML 代码),用配置中的值填充它们或通过按下按钮创建新字段。
有效 - 我将所有数据保存在配置中,用于字段_[id] 等键,例如 field_1、field_2 等
但是有一个错误。当我按下 "Save" 按钮并再次查看弹出窗口进行编辑时,我可以看到 JavaScript 被执行了两次:我将我的所有字段渲染了两次 - 第一次在第一次执行期间,第二次第二个时间,几秒钟后出现。当我保存配置,刷新页面,然后再次查看弹窗时,就没有这个问题了。
这是我在 atlassian-plugin.xml
文件中的合并检查配置:
<repository-merge-check key="isAdmin" class="com.bitbucket.plugin.MergeCheck" name="my check" configurable="true">
<config-form name="Simple Hook Config" key="simpleHook-config">
<view>hook.guide.example.hook.simple.myForm</view>
<directory location="/static/"/>
</config-form>
</repository-merge-check>
还有我简化的 .soy 模板代码:
{namespace hook.guide.example.hook.simple}
/**
* @param config
* @param? errors
*/
{template .myForm}
<script type="text/javascript">
var configuration = new Object();
{foreach $key in keys($config)}
configuration["{$key}"] = "{$config[$key]}";
{/foreach}
var keys = Object.keys(configuration);
function addNewConfiguration() {lb}
var index = keys.length;
addNewItem(index);
keys.push("field_" + index);
{rb}
function addNewItem(id) {lb}
var html = `<label for="field_${lb}id{rb}">Field </label><input class="text" type="text" name="field_${lb}id{rb}" id="branch_${lb}id{rb}" value=${lb}configuration["field_" + id] || ""{rb}><br>`;
document.getElementById('items').insertAdjacentHTML('beforeend', html);
{rb}
keys.forEach(function(key) {lb}
var id = key.split("_")[1];
addNewItem(id);
{rb});
var button = `<button style="margin:auto;display:block" id="add_new_configuration_button">Add new</button>`;
document.getElementById('add_new').innerHTML = button;
document.getElementById('add_new_configuration_button').addEventListener("click", addNewConfiguration);
</script>
<div id="items"></div>
<div id="add_new"></div>
<div class="error" style="color:#FF0000">
{$errors ? $errors['errors'] : ''}
</div>
{/template}
为什么在这种情况下 JavaScript 被执行了两次?有没有其他方法可以创建这样的动态视图?
每当您单击编辑配置时,soy 模板将被加载并再次执行。因此 javascript 也将再次执行。为防止这种情况,您可以创建一个 javascript 文件并将其放在具有相同文件名的 simpleHook-config.soy
模板文件旁边,因此 simpleHook-config.js
。 javascript 文件将与您的 soy 模板一起自动加载,但一次。因此,您可以在新引入的 js 对象中保持全局初始化状态。
此外,即使您动态添加字段,您仍然可以并且应该已经在 soy 模板中构建保存的配置,而不是使用 javascript 构建它。
对我来说这种方法效果很好(我或多或少是盲目写的代码,所以也许你需要稍微调整一下):
在 .soy 文件中:
{namespace hook.guide.example.hook.simple}
/**
* @param config
* @param? errors
*/
{template .myForm}
<div id="merge-check-config">
<div id="items">
{foreach $key in keys($config)}
{let $id: strSub($key, strIndexOf($key, "_") + 1) /}
{call .field}
{param id: $id /}
{param value: $config[$key] /}
{/foreach}
</div>
<div id="add_new">
<button style="margin:auto; display:block" id="add_new_configuration_button">Add new</button>
</div>
<div class="error" style="color:#FF0000">
{$errors ? $errors['errors'] : ''}
</div>
<script>
myPluginMergeCheck.init();
</script>
</div>
{/template}
/**
* @param id
* @param? value
*/
{template .field}
<div>
<label for="field_${id}">Field</label>
<input class="text" type="text" name="field_${id}" id="branch_${id}" value="${value}">
</div>
{/template}
在 .js 文件中:
myPluginMergeCheck = {
initialized: false,
init: function () {
if (this.initialized) {
return;
}
var me = this;
AJS.$(document).on("click", "div#merge-check-config button#add_new_configuration_button"), function (event) {
me.addNewItem();
}
this.initialized = true;
},
addNewItem: function() {
var itemsDiv = AJS.$("div#merge-check-config div#items");
var newId = itemsDiv.children("div").length;
var html = hook.guide.example.hook.simple.field({id: newId});
itemsDiv.append(html);
}
};
我正在为 Bitbucket 创建自定义合并检查。我开始遵循本教程: https://developer.atlassian.com/server/bitbucket/how-tos/hooks-merge-checks-guide/
我希望视图是动态的,例如具有创建多个相似输入字段(指定 ID)的按钮,这些输入字段最终存储在配置中。
首先,我为此使用了 soy - 我创建了静态模板并调用了一个模板,例如。文本域。它工作正常,但我无法即时创建新的类似字段(按下 'Add new' 按钮后)。
所以我使用JavaScript从soy的配置中获取数据。我将整个配置重写为 JS "map",然后动态呈现所有字段(通过将它们附加到 HTML 代码),用配置中的值填充它们或通过按下按钮创建新字段。
有效 - 我将所有数据保存在配置中,用于字段_[id] 等键,例如 field_1、field_2 等
但是有一个错误。当我按下 "Save" 按钮并再次查看弹出窗口进行编辑时,我可以看到 JavaScript 被执行了两次:我将我的所有字段渲染了两次 - 第一次在第一次执行期间,第二次第二个时间,几秒钟后出现。当我保存配置,刷新页面,然后再次查看弹窗时,就没有这个问题了。
这是我在 atlassian-plugin.xml
文件中的合并检查配置:
<repository-merge-check key="isAdmin" class="com.bitbucket.plugin.MergeCheck" name="my check" configurable="true">
<config-form name="Simple Hook Config" key="simpleHook-config">
<view>hook.guide.example.hook.simple.myForm</view>
<directory location="/static/"/>
</config-form>
</repository-merge-check>
还有我简化的 .soy 模板代码:
{namespace hook.guide.example.hook.simple}
/**
* @param config
* @param? errors
*/
{template .myForm}
<script type="text/javascript">
var configuration = new Object();
{foreach $key in keys($config)}
configuration["{$key}"] = "{$config[$key]}";
{/foreach}
var keys = Object.keys(configuration);
function addNewConfiguration() {lb}
var index = keys.length;
addNewItem(index);
keys.push("field_" + index);
{rb}
function addNewItem(id) {lb}
var html = `<label for="field_${lb}id{rb}">Field </label><input class="text" type="text" name="field_${lb}id{rb}" id="branch_${lb}id{rb}" value=${lb}configuration["field_" + id] || ""{rb}><br>`;
document.getElementById('items').insertAdjacentHTML('beforeend', html);
{rb}
keys.forEach(function(key) {lb}
var id = key.split("_")[1];
addNewItem(id);
{rb});
var button = `<button style="margin:auto;display:block" id="add_new_configuration_button">Add new</button>`;
document.getElementById('add_new').innerHTML = button;
document.getElementById('add_new_configuration_button').addEventListener("click", addNewConfiguration);
</script>
<div id="items"></div>
<div id="add_new"></div>
<div class="error" style="color:#FF0000">
{$errors ? $errors['errors'] : ''}
</div>
{/template}
为什么在这种情况下 JavaScript 被执行了两次?有没有其他方法可以创建这样的动态视图?
每当您单击编辑配置时,soy 模板将被加载并再次执行。因此 javascript 也将再次执行。为防止这种情况,您可以创建一个 javascript 文件并将其放在具有相同文件名的 simpleHook-config.soy
模板文件旁边,因此 simpleHook-config.js
。 javascript 文件将与您的 soy 模板一起自动加载,但一次。因此,您可以在新引入的 js 对象中保持全局初始化状态。
此外,即使您动态添加字段,您仍然可以并且应该已经在 soy 模板中构建保存的配置,而不是使用 javascript 构建它。
对我来说这种方法效果很好(我或多或少是盲目写的代码,所以也许你需要稍微调整一下):
在 .soy 文件中:
{namespace hook.guide.example.hook.simple}
/**
* @param config
* @param? errors
*/
{template .myForm}
<div id="merge-check-config">
<div id="items">
{foreach $key in keys($config)}
{let $id: strSub($key, strIndexOf($key, "_") + 1) /}
{call .field}
{param id: $id /}
{param value: $config[$key] /}
{/foreach}
</div>
<div id="add_new">
<button style="margin:auto; display:block" id="add_new_configuration_button">Add new</button>
</div>
<div class="error" style="color:#FF0000">
{$errors ? $errors['errors'] : ''}
</div>
<script>
myPluginMergeCheck.init();
</script>
</div>
{/template}
/**
* @param id
* @param? value
*/
{template .field}
<div>
<label for="field_${id}">Field</label>
<input class="text" type="text" name="field_${id}" id="branch_${id}" value="${value}">
</div>
{/template}
在 .js 文件中:
myPluginMergeCheck = {
initialized: false,
init: function () {
if (this.initialized) {
return;
}
var me = this;
AJS.$(document).on("click", "div#merge-check-config button#add_new_configuration_button"), function (event) {
me.addNewItem();
}
this.initialized = true;
},
addNewItem: function() {
var itemsDiv = AJS.$("div#merge-check-config div#items");
var newId = itemsDiv.children("div").length;
var html = hook.guide.example.hook.simple.field({id: newId});
itemsDiv.append(html);
}
};