jsViews $.observable(arr).insert() 不触发 DOM 更新

jsViews $.observable(arr).insert() not triggering DOM update

我正在使用 $.observable(array).insert() 将项目附加到列表中。这正在更新我的视图,因为它应该:新列表项呈现给 DOM。但是,我想在新的 DOM 节点上发出一个点击事件(我依靠该事件添加一个 class 来扩展该项目并将另一个侦听器附加到主体,以便该区域可以关闭)。

我都试过了

$.observable(_model.leadTimes).insert(leadTime);
$leadTimes.find('.lead-time-data').last().find('.start-editing').click();

...和 ​​

function watchLeadTimes() {

    var changeHandler = function (ev, eventArgs) {
        if (eventArgs.change === 'insert') {

            $leadTimes.find('.lead-time-data').last().find('.start-editing').click();

        }
    };

    $.observe(_model.leadTimes, changeHandler);

}

而且它们都不起作用,但是,如果我将 jQuery 方法包装在 setTimout 中,例如 setTimeout(function () { $leadTimes.find('.lead-time-data').last().find('.start-editing').click(); }, 400);,它 是否有效,让我相信这是一个时间问题,DOM 渲染在我的 jQuery click() 方法被调用之前不知何故没有完成。

既然你看到这个的可能性很大,Borris,感谢你的图书馆和你所做的一切!我认为 jsViews 是单一框架和普通旧 jQuery noodling 之间的绝佳中间地带!


编辑 2017 年 2 月 9 日

事实证明,我的问题是重叠的点击事件——我无意中处理了点击以在选择元素后立即取消选择它。然而,我借此机会重写了一些东西,以按照 Borris 的链接示例使用更具声明性的方法。

现在在我的模板中,我正在使用计算的可观察对象,isSelected 来切换 .editing class:

{^{for leadTimes}}
    <tr class="lead-time-data" data-link="class{merge:~isSelected() toggle='editing'}">
        <span>{^{:daysLead}}</span>
    </tr>
{{/for}}

还有这个 JS:

function addNewLeadTimeClickHandler() {

    var onNewLeadTimeClick = function () {

        e.stopPropagation();  // this is what I was missing

        var leadTime = {
            daysLead: 1,
            description: ''
        };

        $.observable(_model.activityMapping.leadTimes).insert(leadTime);
        selectLeadtime(_model.activityMapping.leadTimes.length -1);

    }
    $leadTimes.on('click', '.add', onNewLeadTimeClick);

}

function selectLeadtime(index) {

    var addStopEditingClickHandler = function () {

        var onClickHandler = function (event) {
            if ($(event.target).closest('tr').hasClass('editing')) {
                setHandler();
                return;
            }

            selectLeadtime(-1)

        };

        function setHandler() {
            var clickEvent = 'click.ActivityChangeRequestDetailController-outside-edit-row';
            $('html:not(.edit)').off(clickEvent).one(clickEvent, onClickHandler);
        };

        setHandler();

    }

    if (_model.selectedLeadtimeIndex !== index) {
        $.observable(_model).setProperty('selectedLeadtimeIndex', index)
        addStopEditingClickHandler();
    }

}
function isSelected() {
    var view = this;
    return this.index === _model.selectedLeadtimeIndex;
}
// isSelected.depends = ["_model^selectedLeadtimeIndex"];
// for some reason I could not get the above .depends syntax to work
// ...or "_model.selectedLeadtimeIndex" or "_model.selectedLeadtimeIndex"
// but this worked ...
isSelected.depends = function() {return [_model, "selectedLeadtimeIndex"]};

observable insert() 方法是同步的。如果您的列表项仅使用 {^{for}} 呈现,那么这也是同步的,因此您不需要使用 setTimeout 或回调。 (有这样的回调可用,但您在这种情况下不需要它们。)

参见示例 http://www.jsviews.com/#samples/editable/tags (code here):

$.observable(movies).insert({...});
// Set selection on the added item
app.select($.view(".movies tr:last").index);

选择被同步添加到新插入的项目上。

您的渲染中是否还有其他异步代码?

顺便说一句,如果您使用委托模式,通常不需要向添加的元素添加新的点击处理程序。例如,在同一个示例中,用于删除电影的点击处理程序最初添加到容器 "#movieList" 中,并带有委托选择器 ".removeMovie"(参见 code)。这甚至适用于稍后添加的电影。

相同的场景使用 {{on}}http://www.jsviews.com/#link-events"The selector argument can target elements that are added later"