¿Cuál es la manera correcta de activar la manipulación de DOM jQuery desde un controlador?

De modo que sigo leyendo que la manipulación de jQuery desde un controlador es una mala práctica, pero no tengo claro por qué ni cómo corregirlo.

A continuación se muestra el código de un tutorial de Youtube que incluso los comentarios del creador del video es una mala idea, pero no explica por qué y sigue utilizando el mal comportamiento de todos modos.

Desdehttps://www.youtube.com/watch?v=ilCH2Euobz0#t=553s :

$scope.delete = function() {
    var id = this.todo.Id;
    Todo.delete({id: id}, function() {
        $('todo_' + id).fadeOut();
    });
};

SOLUCIÓN:

Basándome en la respuesta de Langdon a continuación, he llegado al siguiente código de trabajo para mi propio trabajo, que se deriva ligeramente del código de ejemplo anterior:

var ProjectListCtrl = function ($scope, Project) {
    $scope.projects = Project.query();
    $scope.delete = function() {
        var thisElem = this;
        var thisProject = thisElem.project;
        var id = thisProject.id;
        Project.delete({id: id}, function() {
            var idx = $scope.projects.indexOf(thisProject);
            if (idx !== -1) {
                thisElem.destroy('removeItem('+idx+')');
            }
        });
    }

    $scope.removeItem = function(idx) {
        $scope.projects.splice(idx, 1);
    }

}

app.directive('fadeOnDestroy', function() {
    return function(scope, elem) {
        scope.destroy = function(funcComplete) {
            elem.fadeOut({
                complete: function() {
                    scope.$apply(funcComplete)
                }
            });
        }
    }
});

Esto difiere de la respuesta de Langdon de varias maneras. Quería evitar agregar un parámetro a langClick devolución de llamada, así que lo estoy almacenando enthisProject. Además, el ejemplo y mi código debe llamardestroy desde dentro de un$http devolución de llamada de éxito por lo que en lugar dethis que ya no es relevante, estoy almacenando el elemento pulsado enthisElem.

ACTUALIZACIÓN 2:

Actualicé mi solución aún más para reflejar que funcComplete en realidad no estaba modificando el alcance original de $.

Respuestas a la pregunta(2)

Su respuesta a la pregunta