1

Ok, название может быть немного запутанным, так что я объясню ...Нокаут: пользовательские привязки для observableArray, который делает только тогда, когда полный

Я пишу пользовательские привязки, к которому я буду передать observableArray. Этот наблюдаемый массив заполняется асинхронно, а элементы задвигаются один за другим.

Проблема заключается в том, что моя пользовательская привязка называется (метод update) каждый раз, когда наблюдаемыйArray мутирован. Что имеет смысл, но что не полезно в этом случае, потому что это означает, что первый элемент получает визуализированный n раз, где n - длина наблюдаемого массива, а второй элемент визуализируется n-1 раз, с только nth элемент визуализируется один раз.

Может кто-нибудь объяснить, аккуратный метод, имеющие обязательную силу только делать что-то, когда либо

  • observableArray полностью заполнен, или
  • , когда был добавлен элемент, который еще не был вынесен обычаем пользовательская привязка?

Я могу придумать пару способов обойти это, используя дополнительное свойство/наблюдаемое в качестве флага родительской модели представления, в которой говорится, что «полностью заполнено, вы можете отображать элементы сейчас» или свойство на каждом из элементы, которые говорят «вы меня уже оказали». Тем не менее, это неловко, особенно, поскольку объекты внутри наблюдаемого массива также обладают свойством observableArray.

Нет ли лучшего решения для нокаута/MVVM для этой проблемы?

UPDATE: Для ясности, что я строю на вершине что-то вроде этого

<domElmnt data-bind="myBinding: { collection: TypeGroups }" /> 

где

TypeGroups = ko.observableArray(); 

и где элементы, содержащиеся в TypeGroups являются экземплярами другого вид-модель с наблюдаемыми свойствами.

Каждый раз, когда я вызываю TypeGroups.push(obj), пользовательская привязка вызывается еще раз.

+0

Наблюдаемый массив не должен переписывать элементы, которые не менялись. Попробуйте добавить привязку, которая отображает 'new Date()', чтобы проверить, действительно ли это происходит. Что-то вроде '' –

+0

Пользовательская привязка находится на наблюдаемом массиве или элементах? –

+0

Наблюдаемый массив не является рендерингом; происходит то, что каждый раз, когда наблюдаемыйArray мутирует, он вызывает пользовательскую привязку, которая затем перебирает все элементы в наблюдаемом массиве - даже те, которые уже обработаны. – awj

ответ

2

Не могу сказать точно, если это необходимо, но вот как я это сделаю, если customBinding должно быть помещено в наблюдаемый массив.

Что вы хотите сделать, это атомное обновление. Существует метод splice, как и обычный сплайс.

yourArray.splice(atIndex, 0, elem1, elem2, elem3 ...) 

Но нравится, что это не очень полезно:

yourArray.splice.apply(yourArray, [index, 0, elem1, elem2, elem3 ...]) 

Это на самом деле не очень так, но мы можем сделать лучше.

function append(array, values) { 
    var params = [array().length, 0]; 
    params.push.apply(params, values); 
    array.splice.apply(array, params); 
} 

Я уверен, что использование сплайсинга будет добавлять все элементы атомарно, не вызывая обновления несколько раз.С другой стороны, вызова array.push.apply(array, values) может быть достаточно, и сращивание не требуется.

Но!

Если бы я был в вашем положении, я бы переместил привязку из obserableArray к элементам внутри наблюдаемого массива. Я не знаю, почему вы повторяете все свои вещи после обновления. Если элементы обрабатывались один раз, есть ли причина обрабатывать обработанные элементы несколько раз? Если нет, пользовательская привязка может не использоваться там, где должна.

Не зная больше о вашей проблеме, трудно сказать, что является лучшим способом справиться с вашей проблемой.

+0

Боюсь, я не понимаю, что вы предлагаете. Возможно, это связано с тем, что в голове у меня другое изображение того, над чем я работаю, поэтому я добавил дополнительную информацию в свой вопрос. – awj

+0

Тем не менее, ваш ответ дал мне пару идей: (1) Каждый раз, когда вызывается пользовательская привязка, я могу объединить массив, используя количество ранее обработанных элементов, чтобы «сращивание» вернуло бы все-таки- be-rendered elements, или (2) я мог бы просто очистить ранее обработанные элементы при каждом вызове, поскольку последний вызов всегда выполняется, когда наблюдаемый массив выполнен и перечисление его элементов в это время будет поэтому правильным. Извините, если (1) в значительной степени соответствует вашему ответу. – awj

0

Посмотрите на ko.utils.arrayPushAll().

Вы сбрасываете все объекты в массив и нажимаете их на одну транзакцию. Это будет обновлять пользовательский интерфейс один раз.

проверить эту статью Райан Нимейер Utility Functions

+0

Это хорошее предложение, @Matthew. Однако, поскольку мы будем использовать эту настраиваемую привязку в нескольких местах, я не хочу, чтобы было требование, связанное с тем, как заполняется наблюдаемый массив. Я бы скорее поставил эту логику в пользовательскую привязку. Кроме того, ссылка, которую вы указали, не содержит упоминаний arrayPushAll(). – awj

0

Вот как я решил эту проблему: каждый раз, когда пользовательский связывание называется I (безопасно) подсчитать, сколько детей уже были добавлены в контекст элемента:

var childCount = 0, 
    children = element.childNodes, 
    childMax = children.length; 
for (var c = 0; c < childMax; c++) { 
    if (children[c].nodeType != 3) { 
     childCount++; 
    } 
} 

Затем, когда я цикл через указанный observableArray я использую childCount - которая начинается в предыдущего элемента подсчета - в качестве исходного индекса, и петли из этого индекса и далее:

var coll = groupsCollection(); // groupsCollection is the specified observableArray 
childMax = coll.length; 
for (; childCount < childMax; childCount++) { 
    // do something with coll[childCount ], such as using it to add a DOM node 
}