【问题标题】:jsViews $.observable(arr).insert() not triggering DOM updatejsViews $.observable(arr).insert() 不触发 DOM 更新
【发布时间】:2017-02-07 23:51:08
【问题描述】:

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

我都试过了

$.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);,它确实起作用,让我相信这是在调用我的 jQuery click() 方法之前,DOM 渲染的计时问题以某种方式无法完成。

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


编辑 02/09/17

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

现在在我的模板中,我使用计算的 observable isSelected 来切换 .editing 类:

{^{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"]};

【问题讨论】:

    标签: javascript jquery dom jsviews


    【解决方案1】:

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

    例如见http://www.jsviews.com/#samples/editable/tags(代码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:“选择器参数可以定位稍后添加的元素”

    【讨论】:

    • 感谢指导;我会调查的!我想添加/删除的点击事件在正文上。这个想法是我在新项目上触发一个单击事件,以便它在添加时展开,并且用户可以在外部(在正文上)单击以关闭它。我正在寻找一种类似于您上面链接的示例的更具声明性的方法。
    猜你喜欢
    • 1970-01-01
    • 2022-01-19
    • 1970-01-01
    • 1970-01-01
    • 2011-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多