dependencies, предотвращение рекурсивного вызова.
Если "повесить" зависимость некоторого атрибута на колонку, в методе-обработчике зависимости изменять значение колонки-зависимости - вполне предсказуемо получить рекурсивный вызов.
Но обычно цепочка рекурсивных вызовов пресекается установкой флага, или внедрением проверок, которые гарантированно не пройдут при повторном вызове, что в свою очередь обеспечит выполнение рекурсивного вызова без изменения целевого значения.
В данном случае, не зависимо от механики предусмотренной в методе-обработчике, его вызов уходит в рекурсию в том случае если во время его исполнения было изменено значение зависимой колонки.
н/п
...
"SameHandler": {
dependencies: [
{
//поле с типом "Дата-время"
columns: ["TargetColumn"],
methodName: "SameHandlerControl"
}
]
},
...
...
"SameHandlerControl": function() {
if (window.foo) {
window.foo = false;
} else {
window.foo = true;
this.set("TargetColumn", new Date());
}
},
так вот несмотря на то, что при повторном вызове обработчика, выполнение уходит в ветку
if (window.foo) {
window.foo = false;
...
после чего, рекурсивные вызовы, по идее, должны закончиться т.к. значение "TargetColumn" более не меняется, по факту вызовы SameHandlerControl уходят в бесконечную рекурсию
Как этого избежать ?
Почему так происходит ?
PS: классический кейс "самоконтроля поля ввода" - поле реагирует на изменение своего значения вызовом обработчика, который производит проверки и вычисления с введенным значением, по необходимости корректируя/восстанавливая свое собственное значение, предотвращая рекурсивный вызов обработчика.
Нравится
Здравствуйте
Интересный случай. Глубоко не копал, но причина вроде бы в последовательности вызова
меняя this.set("TargetColumn", new Date());, вы "дергаете" SameHandlerControl, т.к. атрибут связан с колонкой. И поскольку перед "самовызовом" метода вы меняете флаг выхода, то получается замкнутый цикл
попробуйте вызвать window.foo = true; ПОСЛЕ this.set("TargetColumn", new Date());
мой тестовый код, на котором нет вечного цикла
define("UsrSection1Page", [], function() { return { entitySchemaName: "UsrSection", attributes: { "SameHandler": { dependencies: [ { columns: ["UsrName"], methodName: "SameHandlerControl" } ] } }, methods: { "SameHandlerControl": function() { var n = this.get("UsrName"); if (window.foo) { window.foo = false; } else { //window.foo = true; this.set("UsrName", n + window.foo); window.foo = true; } } }, ...
Я решил, проблему "отложенным вызовом на 100 мс." смены атрибута который приводит к вызову обработчика в рекурсии
... setTimeout(function(){ this.set("TargetColumn", new Date()) }.bind(this), 100); ...
т.е. как только выполнение обработчика завершается корректно - повторный вызов из отложенной функции уже корректно ловит "флаг" и его обрабатывает.
PS: создается такое впечатление что срабатывание обработчиков - псевдосинхронное, т.е. this.set банально "стакает" текущий контекст, и функция вызывается повторно, не завершившись в предыдущий раз.