Пользовательская привязка для того, когда foreach закончил рендеринг

У меня есть наблюдаемый массив с элементами, привязанными к ul, Мне нужно рассчитать ширину всего набора li элементы, как только элементы были добавлены, чтобы я мог установить ширину ul элемент общей ширины дочернего элемента li элементы.

Как я могу сделать это с foreach связывание?

<div>
    <h2 data-bind="visible: items().length">Test</h2>
    <ul data-bind="foreach: { data: items, afterAdd: $root.myAfterAdd }">
        <li data-bind="text: name"></li>
    </ul>
</div>

И JavaScript:

var viewModel = {
    items: ko.observableArray([
        { name: "one" },
        { name: "two" },
        { name: "three" }
        ]),
    myAfterAdd: function(element) {
        if (element.nodeType === 1) {
           alert("myAfterAdd");   
        }
    },
    addItem: function() {
        this.items.push({ name: 'new' });
    }
};


ko.applyBindings(viewModel);

// once foreach has finished rendering I have to set the width 
// of the ul to be the total width of the children!

Я пытался с помощью afterAdd так что я могу "обновить" ширину ul после добавления каждого элемента, к сожалению, я обнаружил, что afterAdd не стреляет по начальным предметам! Он будет срабатывать только при нажатии дополнительных предметов...

Обратите внимание, что содержимое внутри li предметы будут неизвестной ширины:)

Смотрите эту скрипку для примера сценария.

3 ответа

Решение

После долгих поисков я нашел решение. Для достижения этого с помощью foreach слишком зарегистрировать пользовательский обработчик событий:

ko.bindingHandlers.runafter = {
    update: function (element, valueAccessor, allBindingsAccessor) {
        var value = valueAccessor();
        setTimeout(function (element, value) {
            if (typeof value != 'function' || ko.isObservable(value))
                throw 'run must be used with a function';

            value(element);
        }, 0, element, value);
    }
};

Этот обработчик будет запускаться всякий раз, когда происходит обновление (или только один раз, если значение не является наблюдаемым).

Что еще более важно он будет срабатывать после завершения цикла foreach!

Смотрите здесь.

У меня была похожая проблема. Вы можете использовать это для первоначального расчета:

ko.bindingHandlers.mybinding {
        init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
            var foreach = allBindings().foreach,
                subscription = foreach.subscribe(function (newValue) {
                // do something here (e.g. calculate width/height, use element and its children)
                subscription.dispose(); // dispose it if you want this to happen exactly once and never again.
            });
        }
}

Вы могли бы сделать что-то вроде этого:

var viewModel = {
    items: ko.observableArray([
        { name: "one" },
        { name: "two" },
        { name: "three" }
        ]),
    myAfterAdd: function(event) {
        if (event.originalEvent.srcElement.nodeType === 1) {
           alert("myAfterAdd");   
        }
    },
    addItem: function() {
        this.items.push({ name: 'new' });
    }
};


$('#bucket').bind('DOMNodeInserted DOMNodeRemoved', viewModel.myAfterAdd);

ko.applyBindings(viewModel);

Какое ведро является элементом ul

Смотри скрипку

Я надеюсь, что это помогает

Другие вопросы по тегам