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

时间:2017-02-07 23:51:08

标签: javascript jquery dom jsviews

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

我试过了两次

$.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"]};

1 个答案:

答案 0 :(得分: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“选择器参数可以定位稍后添加的元素”