Привязка ng-click теряется, если элемент DOM удаляется и снова добавляется

Мне нужно повторно добавить ранее скомпилированный angular html обратно в дерево DOM после его удаления (см. здесь по справочным причинам).

Привязки содержимого по-прежнему работают должным образом. например когда переменная области видимости изменяется, любые привязки {{someVariable}} обновляются новым значением.

Однако привязки ng-click перестают работать. Связанная функция на контроллере просто перестает вызываться.

Посмотрите эту скрипту для воспроизведения. Сначала нажав кнопку +, вы увидите приращение счетчика. Но после двойного нажатия кнопки «Переключить» кнопка + больше не работает, однако привязка {{count}} по-прежнему обновляется.

Пожалуйста, игнорируйте манипуляции с DOM внутри контроллера. Это просто для упрощения воспроизведения. Обычно вы делаете это в директиве. См. мой исходный вопрос и ответ Джо для более реалистичной реализации.


person Tyson    schedule 23.02.2015    source источник


Ответы (4)


Я так долго не использовал jquery, что забыл о некоторых ошибках.

Метод .detach() аналогичен .remove(), за исключением того, что .detach() сохраняет все данные jQuery, связанные с удаленными элементами. Этот метод полезен, когда удаленные элементы должны быть повторно вставлены в DOM позднее.

http://api.jquery.com/detach/

И, конечно же, jqlite в angular следует тем же соглашениям. Таким образом, вызов replaceWith удаляет обработчики событий, которые были прикреплены ng-click. Вместо этого использование detach и append сохраняет обработчики событий, и все работает как положено:

http://jsfiddle.net/sxm22w3b/17/

person Tyson    schedule 23.02.2015
comment
Не думал о решении jQuery - пошел прямо в Angular :) - person andyw_; 23.02.2015

Используйте отсоединение().

  old.before( new ).detach()

эквивалентно replaceWith()

;)

person Joe Enzminger    schedule 23.02.2015
comment
хахаха, и вы рассчитали это так же, как я тоже опубликовал свой собственный ответ :) - person Tyson; 23.02.2015

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

См. здесь: http://fiddle.jshell.net/andyw_/72NYm/

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

var targetFn = $compile(target);

Вы можете обратиться к документации для получения дополнительной информации — https://docs.angularjs.org/guide/compiler#how-directives-are-compiled

person andyw_    schedule 23.02.2015
comment
Ничего себе, я не знал, что вы можете перекомпилировать существующий элемент DOM таким образом (я думал, что это только для html-строк и файлов шаблонов). Спасибо! - person Tyson; 23.02.2015

Вы можете сослаться на следующее решение:

HTML:

<div ng-controller="Ctrl">
    <button ng-click="toggle()">Toggle</button>
    <div ng-show="showContent" id="toggleTarget">
        Some content = {{myContent}}
        <button ng-click="inc()">+</button>
    </div>
    <div id="placeholder" ng-show="showplaceholder">Placeholder</div>
</div>

JS:

function Ctrl($rootScope, $scope, $element) {
    $scope.myContent = 1;

    var target = angular.element(document.getElementById("toggleTarget"));
    var placeholder = angular.element(document.getElementById("placeholder"));

    var removed = false;
    $scope.showContent = true;
    $scope.placeholder = false;

    $scope.toggle = function(){
        $scope.myContent += 1;

        if (removed) {
            $scope.showContent = true;
            $scope.placeholder = false;
            removed = false;
        }
        else {
            $scope.showContent = false;
            $scope.placeholder = true;
            removed = true;
        }    
    }

    $scope.inc = function(){
        $scope.myContent += 1;
    };
}

angular.module('app', []);

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

person dipendra    schedule 23.02.2015