所以我一直在阅读控制器中的jQuery操作是不好的做法,但我不清楚为什么或如何纠正。
以下是来自Youtube教程的代码,即使是视频创建者的评论也是一个坏主意,但无法解释原因并继续使用不良行为。
来自https://www.youtube.com/watch?v=ilCH2Euobz0#t=553s:
$scope.delete = function() {
var id = this.todo.Id;
Todo.delete({id: id}, function() {
$('todo_' + id).fadeOut();
});
};
解:
根据兰登在下面给出的答案,我已经为自己的工作找到了以下工作代码,这些代码与上面的示例代码略有不同:
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)
}
});
}
}
});
这与兰登在某些方面的答案不同。我想避免在ngClick
回调中添加参数,因此我将其存储在thisProject
中。此外,示例和我的代码需要在destroy
成功回调中调用$http
,而不是this
不再相关,我将点击的元素存储在{{1 }}
更新2 :
进一步更新了我的解决方案,以反映funcComplete实际上并未修改原始$ scope。
答案 0 :(得分:9)
处理此问题的Angular方法是通过指令。我找到了一个完美的例子来涵盖你在下面提到的内容,虽然它并不像我想的那样干净。我们的想法是创建一个用作HTML属性的指令。当元素绑定到控制器的范围时,将触发link
函数。该函数淡化元素(完全可选)并为您的控制器公开一个destroy方法以便稍后调用。
更新:根据评论修改实际影响范围。对解决方案并不感到兴奋,因为原作者在他的destroy回调中调用了complete.apply(scope)
,但在回调函数中没有使用this
,所以它甚至更加笨拙。
更新2:由于该指令是使回调异步的指令,因此在那里使用scope.$apply
可能更好一点,但请记住,如果您在指令中使用隔离范围,那可能会变得奇怪。
<强> http://jsfiddle.net/langdonx/K4Kx8/114/ 强>
HTML:
<div ng-controller="MyCtrl">
<ul>
<li ng-repeat="item in items" fadey="500">
{{item}}
<a ng-click="clearItem(item)">X</a>
</li>
</ul>
<hr />
<button ng-click="items.push(items.length)">Add Item</button>
</div>
JavaScript的:
var myApp = angular.module('myApp', []);
//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});
function MyCtrl($scope) {
$scope.items = [0, 1, 2];
$scope.clearItem = function(item) {
var idx = $scope.items.indexOf(item);
if (idx !== -1) {
//injected into repeater scope by fadey directive
this.destroy(function() {
$scope.items.splice(idx, 1);
});
}
};
}
myApp.directive('fadey', function() {
return {
restrict: 'A', // restricts the use of the directive (use it as an attribute)
link: function(scope, elm, attrs) { // fires when the element is created and is linked to the scope of the parent controller
var duration = parseInt(attrs.fadey);
if (isNaN(duration)) {
duration = 500;
}
elm = jQuery(elm);
elm.hide();
elm.fadeIn(duration)
scope.destroy = function(complete) {
elm.fadeOut(duration, function() {
scope.$apply(function() {
complete.$apply(scope);
});
});
};
}
};
});
至于为什么,我认为这仅仅是为了分离关注点和可能性。您的控制器应关注数据流和业务逻辑,而不是接口操作。理想情况下,你的指令应该是为了可用性而写的(就像fadey
这里的情况那样 - 注意:我不会称之为fadey;))。
答案 1 :(得分:0)
这篇文章中显示的代码非常有助于我理解关系控制器 - 指令,但它抛出了一个js错误。
TypeError: Object function (scope) {
$scope.items.splice(idx, 1);
console.log($scope.items)
} has no method '$apply'
我稍微更新了指令,现在它对我有用:
function MyCtrl($scope) {
$scope.items = [0, 1, 2, 3, 4, 5];
$scope.clearItem = function(item) {
var idx = $scope.items.indexOf(item);
if (idx !== -1) {
//injected into repeater scope by fadey directive
this.destroy(function(scope) {
$scope.items.splice(idx, 1);
//this now shows the expected results
console.log($scope.items)
});
}
};
}
myApp.directive('fadey', function() {
return {
restrict: 'A', // restricts the use of the directive (use it as an attribute)
// fires when the element is created and is linked to the scope of the parent controller
link: function(scope, elm, attrs) {
var duration = parseInt(attrs.fadey);
if (isNaN(duration)) {
duration = 500;
}
elm = jQuery(elm);
elm.hide();
elm.fadeIn(duration)
scope.destroy = function(complete) {
elm.fadeOut(duration, function() {
scope.$apply(function() {
//note the change here
complete(scope);
});
});
};
}
};
});