Использование $scope.$destroy устраняет утечку памяти, но нарушает директиву

У меня есть дочерняя директива, которая довольно динамично работает в приложении TypeScript AngularJS. Шаблон и контроллер подключаются во время выполнения в зависимости от того, что ему нужно делать в данной ситуации, а сам шаблон содержит ряд директив. Мне нужно иметь возможность отображать несколько директив на странице, поэтому я использую изолированную область между каждой из них. У меня есть еще одна директива, которая отвечает за отслеживание того, какие из этих дочерних директив должны быть на странице в любой момент времени (называемая родительской директивой).

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

var compiledDirective = this.$compile(myTemplate)(scope.$new(true, scope));
angular.element(".parent").append(compiledDirective);
_.defer(() => {
  scope.$apply();
});

Если я загружаю приложение, оно работает нормально, и я вижу, что оно создает каждого дочернего элемента, который работает так, как я и ожидал. Когда мне нужно удалить любого/всех этих дочерних элементов, этот родитель также обрабатывает это в следующей функции:

var destroyChild = (identifier: string) {
  this.$timeout(() => {
    var elem = angular.element(".parent").find(`li[ident='${identifier}']`);
    elem.scope().$destroy();
    elem.remove();
    _.defer(() => {
    });
  });
}

Теперь все элементы удаляются, как и ожидалось, и если я посмотрю на Бэтаранг, я увижу, что директивы исчезают из доступных областей. У меня есть обработчик события $destroy в дочерней директиве, поэтому я могу видеть сообщение консоли, когда директива уничтожается, и оно появляется, как и ожидалось, после запуска этой функции уничтожения.

Проблема здесь в том, что мне нужно иметь возможность добавлять больше этих дочерних директив на основе других действий на странице внутри родителя. После этого действия по уничтожению я обнаружил, что область не загружается должным образом, когда я выполняю этот процесс снова и снова во второй раз - скорее, я вижу несколько областей, созданных для дочерней директивы, но я обнаружил, что некоторые из них привязки больше не обновляются (например, я заметил, что ng-hide больше не обновляется, когда значения области видимости изменяются в дочерней директиве), и, таким образом, директива становится непригодной для использования.

В общем, я бы предположил, что это просто ошибка в логике, и что мне нужно найти ее, и она вполне может быть, за исключением того, что во время отладки я обнаружил, что в той родительской функции, которая обрабатывает уничтожение дочерних директив, если я закомментирую строку:

elem.scope().$destroy();

Все области остаются в Batarang, и все элементы DOM исчезают, как и следовало ожидать, так что это может показаться небольшой утечкой памяти, за исключением того, что если я запускаю триггер, чтобы снова загрузить директивы, они загружаются без проблема (теперь я просто сталкиваюсь со многими прицелами в представлении Batarang, которые никогда не очищаются).

Что может вызвать такое поведение, когда $destroying изолированной области действия директивы нарушает будущее использование директивы, но оставление ее там заставляет ее работать позже, но вызывает утечку памяти? Есть ли альтернативный способ очистить эти области без использования $destroy?

Редактировать: После дальнейшего изучения я обнаружил, что когда создается первая директива, она имеет должным образом созданную изолированную область, но при создании последующих директив их изолированные области создаются в Batarang, но если На самом деле я выполняю поиск с помощью angular.element('lookup-their-individual-idents').scope(), сообщаемый идентификатор на самом деле является идентификатором родителя, поэтому, когда я уничтожаю первый, он очищается, как и ожидалось. Когда я уничтожаю второй, он фактически стирает родительскую область (и, следовательно, всех дочерних элементов), поэтому он не точно размещается на родительском элементе в будущем.

Итак, я ожидаю, что мне просто нужно выяснить, как правильно привязать изолированные области к директивам, когда я добавляю их в DOM, а остальное разрешится само собой.


person Whit Waldo    schedule 19.12.2015    source источник
comment
Во-первых, fiddle/plunkr очень поможет лучше понять это. Глядя на ваш код, я вижу одну проблему: this.$timeout в двух местах - снаружи this, вероятно, будет ссылаться на контроллер, а внутри он, вероятно, будет ссылаться на объект window?   -  person FrailWords    schedule 19.12.2015
comment
@FrailWords Эта скрипка / plunkr определенно находится в стадии разработки. Я думал то же самое, но мне нужно понять, как воспроизвести в таком масштабе.   -  person Whit Waldo    schedule 19.12.2015
comment
Одна вещь, которую стоит попробовать - сделать elem.remove(); в $destroy событии elem.scope(), а не сразу в следующей строке.   -  person FrailWords    schedule 19.12.2015
comment
@FrailWords Только что попробовал. Приводит к той же проблеме, в которой я воссоздаю ее, и дочерние области по-прежнему заполняются ожидаемыми значениями, но поскольку их функции связи манипулируют значениями в отношении своих изолированных областей (внутри дочерней директивы), привязки HTML не обновляются, как они это делали. первый раз.   -  person Whit Waldo    schedule 19.12.2015
comment
@FrailWords, глядя на созданные и уничтоженные области видимости, я заметил, что, несмотря на этот селектор, angular.element(.parent).find(li[ident='${identifier}']); выбирая соответствующее значение на странице, когда оно удаляется и область уничтожается, она берет родительскую область на одну выше нее, и я ожидаю, что она будет принадлежать ее родительскому элементу. Возможно, здесь дело в этом.   -  person Whit Waldo    schedule 19.12.2015
comment
Не удалось понять, что вы имеете в виду, говоря, что он берет родительскую область на один уровень выше, и я ожидаю, что он будет принадлежать его родительскому элементу.? Родительская область должна остаться прежней, не так ли?   -  person FrailWords    schedule 19.12.2015


Ответы (1)


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

Скорее, хотя приведенный выше код использовался для создания новых директив, которых не было на странице, мне нужно было обновить код, фактически отвечающий за размещение более одной директивы на странице в рамках этой родительской директивы, чтобы он создавал изолированные области. для каждого из новых детей, например:

var child = this.templateGenerator.addChild(applicableData);
var compiledChild = this.$compile(child)(scope.$new(true));
element.append(compiledChild);

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

person Whit Waldo    schedule 19.12.2015