【问题标题】:How can I wait for an ajax call to complete without using 'async: false' and without using callbacks?如何在不使用“async:false”和不使用回调的情况下等待 ajax 调用完成?
【发布时间】:2016-09-13 13:38:10
【问题描述】:

我有以下 TypeScript 为我的视图上的可点击元素定义了一个 KnockoutJS 绑定处理程序:

module MyModule {
    export interface ICopyButtonParams {
        dataUrl: string;
    }

    ko.bindingHandlers.copyButton = {
        init: (element: HTMLElement, valueAccessor: () => ICopyButtonParams) => {
            var options: any = ko.utils.unwrapObservable(valueAccessor());
            if (!options.dataUrl) {
                return;
            }

            new Clipboard(element, {
                text: () => {
                    var clipboardData: string;

                    $.ajax({
                        url: options.dataUrl,
                        type: "GET",
                        contentType: "application/json",
                        cache: false,
                        async: false,
                        success: (result: SubmitResult) => {
                            clipboardData = result.Data;
                        }
                    });

                    return clipboardData;
                }
            });
        }
    };
}

此绑定处理程序的作用是将可单击元素转换为启用Clipboard.JS 的元素,该元素在单击时将字符串存储在剪贴板中。在我的例子中,我想利用 Clipboard.JS 的动态文本功能,您可以将一个函数传递给 Clipboard 构造函数,该构造函数返回要存储在剪贴板中的文本。在这个函数中,我想调用一个返回要存储的文本的 API。

由于这种架构的性质,我无法使用带有成功回调的标准 ajax 调用,因为这意味着剪贴板文本无法及时解析。

作为权宜之计,您会在我的代码中注意到我已使我的 ajax 调用异步(不好,我知道)。由于从 JQuery 1.8 开始不推荐使用“异步”标志,我正在尝试考虑另一种方法。

有什么想法吗?

【问题讨论】:

  • 为什么不先调用一个异步ajax,然后在成功回调中创建Cliboard对象呢?
  • 重点是我不想检索要放入剪贴板的数据,除非需要(即有人单击“复制到剪贴板”按钮)。页面上可能有 100 多个可以复制到剪贴板的内容,每个都包含许多文本字符。如果我要使用它应该存储的数据对每个剪贴板按钮进行预初始化,我不妨使用视图模型的其余部分检索剪贴板文本并完全取消 ajax 调用。值得指出的是,复制到剪贴板的内容绝不会显示在页面上。
  • 也许我不理解你的意思,但你应该只把 data-bind="copyButton: {}" 放在你想要这样行为的元素上,或者?
  • 正确,但我只希望这些元素在单击时加载其相应的剪贴板文本。
  • 在这种情况下,我可能只是创建一个函数,例如在按钮上单击绑定时调用该函数。

标签: ajax asynchronous knockout.js typescript clipboard.js


【解决方案1】:

我认为更好的方法是自己处理点击事件。

然后在您的 ajax 回调中创建一个 textarea,设置值,选择并调用 document.execCommand('copy'),就像 Clipboard.JS 一样。与此类似的东西(对不起,在打字稿上用 javascript 代替)

ko.bindingHandlers.copyButton = {
  init: function(element, valueAccessor) {
    var url = ko.utils.unwrapObservable(valueAccessor());

    $(element).click(function() {
      $.ajax({
        url: url,
        type: "GET",
        contentType: "application/json",
        cache: false,
        async: false,
        success: function(result) {
          var ta = document.createElement('textarea');
          document.body.appendChild(ta);
          ta.value = result;
          ta.select();
          var r = document.createRange();
          r.selectNode(ta);
          document.getSelection().addRange(r);
          document.execCommand('copy');
          document.body.removeChild(ta);
        }
      });
    });
  }
};

我有一个类似的工作示例 here(没有 ajax 请求)

【讨论】:

  • 是的,我最终自己采用了这种方法。 Clipboard.JS 的设计过于规范。很高兴它包装了所有“hacky”的东西,比如创建文本区域,但这不值得麻烦。感谢您的回复!
  • 这种方法不再适用于 Firefox,导致错误:document.execCommand(‘cut’/‘copy’) was denied because it was not called from inside a short running user-generated event handler. 拥有"clipboardWrite" 权限可能会解决该问题,根据developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/…
猜你喜欢
  • 1970-01-01
  • 2012-06-13
  • 2013-08-14
  • 2017-10-23
  • 1970-01-01
  • 2018-06-09
  • 1970-01-01
  • 1970-01-01
  • 2011-09-06
相关资源
最近更新 更多