Ho sezionato ng-repeat ed estratto i blocchi di codice allegati, visto che questi comprendono la logica che gestisce l'algoritmo che ripete (che voglio capire come funziona).Come funziona ng-repeat?
Ho alcune domande, ma dal momento che riguardano tutti gli aspetti interni di ng-repeat, ho scelto di chiedere loro tutti qui. Non vedo alcun motivo per separarli in domande SO diverse. Ho segnato in linea a quale riga (s) di codice fa riferimento ogni domanda.
- Perché hanno bisogno per assicurarsi che
trackById
non è la funzione nativahasOwnProperty
? (Questo è quello che la funzioneassertNotHasOwnProperty
fa, parte di API interna di angolare) - Per quanto riguarda la mia intuizione andare, questo codice viene eseguito su elementi già nel ripetitore, quando si deve aggiornare la collezione - è appena li raccoglie e li spinge nella lista per l'elaborazione, giusto?
- Questo blocco di codice cerca ovviamente i duplicati nella raccolta ripetitori. Ma come esattamente ciò è al di là di me. Spiega per favore.
- Perché Angular deve memorizzare l'oggetto del blocco sia
nextBlockMap
e innextBlockOrder
? - Cosa sono
block.endNode
eblock.startNode
? - Suppongo che la risposta alla domanda sopra chiarirà come funziona questo algoritmo, ma per favore spiegate perché deve verificare se lo
nextNode
è stato (stato)'$$NG_REMOVED'
? - Cosa succede qui? Di nuovo, presumo che la domanda 6 fornirà già una risposta a questo. Ma continui a farlo notare.
Come ho detto, ho scavato attraverso ng-repeat per trovare il codice che ritenevo rilevante per il meccanismo di ripetizione. Inoltre, capisco il resto della direttiva. Quindi, senza ulteriori indugi, ecco il codice (da v1.2.0):
length = nextBlockOrder.length = collectionKeys.length;
for (index = 0; index < length; index++) {
key = (collection === collectionKeys) ? index : collectionKeys[index];
value = collection[key];
trackById = trackByIdFn(key, value, index);
// question #1
assertNotHasOwnProperty(trackById, '`track by` id');
// question #2
if (lastBlockMap.hasOwnProperty(trackById)) {
block = lastBlockMap[trackById];
delete lastBlockMap[trackById];
nextBlockMap[trackById] = block;
nextBlockOrder[index] = block;
// question #3
} else if (nextBlockMap.hasOwnProperty(trackById)) {
// restore lastBlockMap
forEach(nextBlockOrder, function(block) {
if (block && block.startNode) lastBlockMap[block.id] = block;
});
// This is a duplicate and we need to throw an error
throw ngRepeatMinErr('dupes', "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}",
expression, trackById);
// question #4
} else {
// new never before seen block
nextBlockOrder[index] = { id: trackById };
nextBlockMap[trackById] = false;
}
}
for (index = 0, length = collectionKeys.length; index < length; index++) {
key = (collection === collectionKeys) ? index : collectionKeys[index];
value = collection[key];
block = nextBlockOrder[index];
// question #5
if (nextBlockOrder[index - 1]) previousNode = nextBlockOrder[index - 1].endNode;
if (block.startNode) {
// if we have already seen this object, then we need to reuse the
// associated scope/element
childScope = block.scope;
// question #6
nextNode = previousNode;
do {
nextNode = nextNode.nextSibling;
} while(nextNode && nextNode[NG_REMOVED]);
if (block.startNode != nextNode) {
// existing item which got moved
$animate.move(getBlockElements(block), null, jqLite(previousNode));
}
previousNode = block.endNode;
} else {
// new item which we don't know about
childScope = $scope.$new();
}
// question #7
if (!block.startNode) {
linker(childScope, function(clone) {
clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
$animate.enter(clone, null, jqLite(previousNode));
previousNode = clone;
block.scope = childScope;
block.startNode = previousNode && previousNode.endNode ? previousNode.endNode : clone[0];
block.endNode = clone[clone.length - 1];
nextBlockMap[block.id] = block;
});
}
}
lastBlockMap = nextBlockMap;