Какую точную версию ExtJS4 вы используете?
В моей ситуации с ext-4.0.7-gpl я немного отладил, обнаружив, что метод appendChild
создает узел из объекта и объекта изатем выполняет некоторые операции обновления, касающиеся положения узла в дереве, такие как установка следующего брата, родителя и т. д., см. [1].
При синхронизации хранилище использует методы getUpdatedRecords
и getNewRecords
[2], чтобы определить, какую операцию запустить.обновить или создать.Каким-то образом наши добавленные дочерние элементы оказываются обновленными, а не созданными.
Обратите внимание, что метод не проверяет, были ли загружены дочерние элементы родительского узла, просто помещает новый узел в пустой массив childNodes
;после завершения всех этих операций другие дочерние элементы родительского узла никогда не отображаются в дереве;и если операция обновления вызвала генерацию на сервере нового id
, код разрывается на строку original = me.tree.getNodeById(record.getId());
- такого узла со старым id
, сгенерированным на стороне клиента, не существует.
Проще говоряЯ думаю, что это ошибка.
[1] http://docs.sencha.com/ext-js/4-0/source/NodeInterface.html#Ext-data-NodeInterface-method-appendChild [2] http://docs.sencha.com/ext-js/4-0/source/AbstractStore.html#Ext-data-AbstractStore-method-getUpdatedRecords
Добавить : ExtJS 4.1 beta 2 не работает для меня лучше
Обновление с временным решением : Я немного взломал и думаю, что решил проблему, переопределив метод appendChild
для NodeInterface
, как показано ниже (просто для установки свойства phantom
, чтобы создать запись, не обновляется).
Обратите внимание: 1) Вы должны включить свой вызов appendChild
в обратный вызов метода NodeInterface
expand
, иначе ошибка с нажатием на пустое childNodes
останется: новый узел где-то появитсяв неправильном месте;2) Мне также пришлось переопределить updateIndexes
из AbstractView
, постарайтесь не делать этого, и, возможно, вы поймете, почему;3) есть некоторые проблемы, когда хранилище пытается удалить наш вновь созданный узел при следующей синхронизации - пока не может отследить его;0) Я никоим образом не ExtJS и даже не гуру JS, поэтому не стесняйтесь исправлять этот взлом)
Ext.data.NodeInterface.oldGpv = Ext.data.NodeInterface.getPrototypeBody;
Ext.data.NodeInterface.getPrototypeBody = function(){
var ret = Ext.data.NodeInterface.oldGpv.apply(this, arguments);
ret.appendChild = function(node, suppressEvents, suppressNodeUpdate) {
var me = this,
i, ln,
index,
oldParent,
ps;
if (Ext.isArray(node)) {
for (i = 0, ln = node.length; i < ln; i++) {
me.appendChild(node[i]);
}
} else {
node = me.createNode(node);
if (suppressEvents !== true && me.fireEvent("beforeappend", me, node) === false) {
return false;
}
index = me.childNodes.length;
oldParent = node.parentNode;
if (oldParent) {
if (suppressEvents !== true && node.fireEvent("beforemove", node, oldParent, me, index) === false) {
return false;
}
oldParent.removeChild(node, null, false, true);
}else{
node.phantom = true;
}
if(me.isLoaded()){
index = me.childNodes.length;
if (index === 0) {
me.setFirstChild(node);
}
me.childNodes.push(node);
node.parentNode = me;
node.nextSibling = null;
me.setLastChild(node);
ps = me.childNodes[index - 1];
if (ps) {
node.previousSibling = ps;
ps.nextSibling = node;
ps.updateInfo(suppressNodeUpdate);
} else {
node.previousSibling = null;
}
node.updateInfo(suppressNodeUpdate);
}
//console.log('appendChild was called');
// I don't know what this code mean even given the comment
// in ExtJS native source, commented out
// As soon as we append a child to this node, we are loaded
//if (!me.isLoaded()) {
// me.set('loaded', true);
//}
// If this node didnt have any childnodes before, update myself
//else
//if (me.childNodes.length === 1) {
// me.set('loaded', me.isLoaded());
//}
if (suppressEvents !== true) {
me.fireEvent("append", me, node, index);
if (oldParent) {
node.fireEvent("move", node, oldParent, me, index);
}
}
return node;
}
};
return ret;
};
Это мой код для добавления узла по значениям, взятым из формы domainForm
.Форма открывается нажатием на значок в actioncolumn
нашей древовидной сетки:
var node = grid.store.getAt(rowIndex);
node.expand(false, function(){
var newDomain = domainForm.getValues();
newDomain.parent = {id: node.raw.id}; // i don't know whether you'll need this
var newNode = node.appendChild(newDomain);
me.store.sync();
});
и updateIndexes
переопределитель:
Ext.override(Ext.view.AbstractView, {
updateIndexes : function(startIndex, endIndex) {
var ns = this.all.elements,
records = this.store.getRange(),
i;
startIndex = startIndex || 0;
endIndex = endIndex || ((endIndex === 0) ? 0 : (ns.length < records.length?(ns.length - 1):records.length-1) );
for(i = startIndex; i <= endIndex; i++){
ns[i].viewIndex = i;
ns[i].viewRecordId = records[i].internalId;
if (!ns[i].boundView) {
ns[i].boundView = this.id;
}
}
}
});