2

我正在为 Bitbucket 创建自定义合并检查。我从遵循本教程开始: https ://developer.atlassian.com/server/bitbucket/how-tos/hooks-merge-checks-guide/

我希望视图是动态的,例如具有创建多个相似输入字段(具有指定 ID)的按钮,这些字段最终存储在配置中。

首先,我为此使用了soy——我创建了一个调用例如.textField 的静态模板。它工作正常,但我无法即时创建新的类似字段(按下“添加新”按钮后)。

所以我使用 JavaScript 从 soy 的配置中获取数据。我将整个配置重写为 JS “map”,然后动态渲染所有字段(通过将它们附加到 HTML 代码),用配置中的值填充它们或通过按下按钮创建新字段。

它有效 - 我将所有数据保存在配置中,用于字段_[id]等键,例如字段_1、字段_2等。

但是有一个错误。当我按下“保存”按钮并再次查看弹出窗口进行编辑时,我可以看到 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 会执行两次?有没有其他方法可以创建这样的动态视图?

4

1 回答 1

2

每当您单击以编辑配置时,大豆模板将再次加载并执行。因此,javascript 也将再次执行。simpleHook-config.soy为了防止这种情况,您可以创建一个 javascript 文件并将其放在具有相同文件名的模板文件旁边,因此simpleHook-config.js. javascript 文件将与您的大豆模板一起自动加载,但只加载一次。因此,您可以在新引入的 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);
    }
};

于 2019-07-30T18:26:42.367 回答