【问题标题】:knockout.js - help dealing with UI state changes when polling for updatesknockout.js - 在轮询更新时帮助处理 UI 状态更改
【发布时间】:2014-08-10 12:29:03
【问题描述】:

在我的 observables 更改后,我在丢失 UI 状态更改时遇到了问题,我希望得到一些建议。

首先,我正在轮询我的服务器以获取更新。这些消息在我的视图模型中,并且

    完美呈现:

    当我的用户点击“回复”或“分配给”按钮时,我会显示一个小表单来执行这些操作:

    此时我的问题是,当我的下一个轮询调用返回时,列表重新绑定并且我失去了应该打开表单的状态。我为“currentQuestionID”添加了视图模型属性,这样我就可以使用可见的:绑定并在绑定后重新显示表单。

    一旦完成,重新绑定后表单会正确显示在“当前项目”上,但表单值会丢失。也就是说,它重新绑定、重建表单元素、显示它们,但任何用户输入都消失了(这当然是有道理的,因为 HTML 刚刚重新生成)。

    我尝试遵循相同的模式(使用 value: binding 来设置 value 和 event: {change: responseChanged} binding 来更新带有值的可观察对象)。 HTML 片段如下所示:

<form action="#" class="tb-reply-form" data-bind="visible: $root.showMenu($data, 'reply')">
    <textarea id="tb-response" data-bind="value: $root.currentResponse, event: {keyup: $root.responseChanged}"></textarea>
    <input type="button" id="tb-submitResponse" data-bind="click: $root.submitResponse, clickBubble: false" value="Send" />
</form>
<form action="#" class="tb-assign-form" data-bind="visible: $root.showMenu($data, 'assign')">
    <select id="tb-assign" class="tb-assign" data-bind="value: $root.currentAssignee, options: $root.mediators, optionsText: 'full_name', optionsValue: 'access_token', optionsCaption: 'Select one...', event: {change: $root.assigneeChanged}">
    </select>
    <input type="button" id="tb-submitAssignment" data-bind="click: $root.submitAssignment, clickBubble: false" value="Assign"/>
</form>

现在,我最终得到了一个看起来像无限循环的东西,其中设置值会导致发生变化,进而导致值......等等。

我认为“搞砸”只是将其移出 foreach...通过将表单移到 foreach 中的每个

  • 之外:绑定并进行一些 DOM 操作以将表单移入“当前项” ,我认为我不会丢失用户输入。
    replyForm.appendTo(theContainer).show();
    

    它一直有效,直到第一次投票返回并重新绑定。由于 HTML 是为

      重新生成的,所以 DOM 不再有我的表单,我尝试抓取它并执行 .appendTo(container) 什么也没做。我想在这里,我也许可以将元素复制到活动项目中而不是移动它?

      所以,这一切似乎我错过了一些基本的东西,因为有人必须在淘汰赛中将表单放入 foreach 循环中!

      有没有人有策略在淘汰赛中保持绑定项目内的表单状态?

      或者,可能,有没有办法让淘汰赛不绑定任何已经绑定的东西,只生成“新”元素。

      最后,我是否应该为此取消淘汰赛,并在每次轮询调用返回时自己手动生成“新项目”。

      最后一点信息;如果我将轮询间隔设置为 30 秒左右,那么它提交、保存、重新绑定等所有位都会“工作”。我只需要表单及其内容即可通过重新绑定。

      非常感谢您的帮助!

  • 【问题讨论】:

    • 请发布您的视图模型代码
    • 你能在jsfiddle.net上调一下吗

    标签: forms data-binding knockout.js


    【解决方案1】:

    嗯,我自己想出来的。而且很尴尬。

    这是我的部分虚拟机代码:

    function TalkbackViewModel( id ) {
       var self = this;
    
       talkback.state.currentTalkbackId = "";
       talkback.state.currentAction = "";
       talkback.state.currentResponse = "";
       talkback.state.currentAssignee = "";
    
       self.talkbackQueue = ko.observableArray([]);
       self.completeQueue = ko.observableArray([]);
       self.mediators = ko.observableArray([]);
    
       self.currentTalkbackId = ko.observable(talkback.state.currentTalkbackId);
       self.currentAction = ko.observable(talkback.state.currentAction);
       self.currentResponse = ko.observable(talkback.state.currentResponse);
       self.currentAssignee = ko.observable(talkback.state.currentAssignee);
    
    self.showActionForm = function(data, action) {
        return ko.computed(function() {
            var sameAction = (self.currentAction() == action);
            var sameItem = (self.currentTalkbackId() == data.talkback_id());
    
            return (sameAction && sameItem);
        }, this);
    };
    
        self.replyToggle = function(model, event) {
        // we're switching from one item to another. clear input values.
        if (self.currentTalkbackId() != model.talkback_id() || self.currentAction() != "reply") {
            self.currentResponse("");
            self.currentAssignee("");
            self.currentTalkbackId(model.talkback_id());
        }
    

    我的第一个错误是试图将 textarea 和下拉列表视为相同。我注意到下拉菜单正在保存价值并重新加载,但愚蠢地试图保持代码与 textarea 相同并导致我自己的问题。

    所以...

    首先,我回到使用 $root 视图模型属性的 currentAssignee 和 currentResponse 来存储关闭值并使用 value: 绑定这些控件重新绑定。

    接下来,我需要删除事件处理程序:

    event: { change: xxxChanged }
    

    因为它们没有意义(双向绑定!!!!)。下拉值通过使用值自动更改和更新:绑定。

    textarea 仅在模糊时更新,导致我认为我需要 onkeyup、onkeydown 等。我摆脱了这些处理程序,因为它们 1) 错误,2) 搞砸了值:绑定创建了一个无限循环。

    我只需要在 textarea 上使用它来获取我的 viewmodel 属性的最新值更新:

    valueUpdate: 'input'
    

    此时一切都保存并重新绑定,我没有丢失我的值,但我的插入符号位置在文本区域中不正确。我添加了一些代码来处理它:

    var item = element.find(".tb-assign");
    var oldValue = item.val();
    item.val('');
    item.focus().val(oldValue);
    

    如果您只执行 item.focus().val(item.val());但是在我的情况下,我实际上需要使值“更改”以在最后获得插入符号,因此我保存了该值,将其清除,然后将其恢复。当事件数据返回到浏览器时,我在事件处理程序中执行了此操作:

        $(window).on("talkback.retrieved", function(event, talkback_queue, complete_queue) {
            var open_mappings = ko.mapping.fromJS(talkback_queue);
            self.talkbackQueue(open_mappings);
            if (talkback_queue) self.queueLength(talkback_queue.length);
    
            var completed_mappings = ko.mapping.fromJS(complete_queue);
            self.completeQueue(completed_mappings);
    
            if (self.currentTalkbackId()) {
                var element = $("li[talkbackId='" + self.currentTalkbackId() + "']");
                if (talkback.state.currentAction == "assign") {
                    var item = element.find(".tb-assign");
                    var oldValue = item.val();
                    item.val('');
                    item.focus().val(oldValue);
                } else {
                    var item = element.find(".tb-response");
                    var oldValue = item.val();
                    item.val('');
                    item.focus().val(oldValue);
                }
            }
        }
    );
    

    所以,我的最后一个问题是,如果我在选择新的“当前项目”(replyToggle 和 assignToggle)时“清除”值的方法中使用我的 observable,它们似乎不起作用。

    self.currentResponse("");
    self.currentAssignee("");
    

    我无法清除这些值。我不得不做一些 hack-fu 并在下面添加了一行以暂时解决它:

    $(".tb-assign").val("");
    

    【讨论】:

    • 我的问题的全部原因是重新绑定轮询的每一次返回以获取新项目。我用调用 ObservableArray 上的 push() 来替换所有旧项目的代码: self.talkbackQueue.push(new_item);所以,现在,整个列表没有重新绑定,我能够删除一堆废话。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-22
    • 2021-12-29
    • 1970-01-01
    • 2017-04-16
    • 1970-01-01
    相关资源
    最近更新 更多