Javascript 什么';从控制器中触发jQuery DOM操作的正确方法是什么?
所以我一直在读控制器中的jQuery操作是不好的做法,但我不清楚为什么,或者如何纠正 下面是Youtube教程中的代码,即使是视频创建者的评论也是一个坏主意,但没有解释为什么会这样做,而且还会继续使用这种坏行为 发件人: 解决方案: 根据Langdon在下面的回答,我为自己的工作得出了以下工作代码,它稍微源自上面的示例代码:Javascript 什么';从控制器中触发jQuery DOM操作的正确方法是什么?,javascript,angularjs,angularjs-controller,Javascript,Angularjs,Angularjs Controller,所以我一直在读控制器中的jQuery操作是不好的做法,但我不清楚为什么,或者如何纠正 下面是Youtube教程中的代码,即使是视频创建者的评论也是一个坏主意,但没有解释为什么会这样做,而且还会继续使用这种坏行为 发件人: 解决方案: 根据Langdon在下面的回答,我为自己的工作得出了以下工作代码,它稍微源自上面的示例代码: var ProjectListCtrl = function ($scope, Project) { $scope.projects = Project.query
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
中。此外,示例和我的代码需要在$http
成功回调中调用destroy
,因此我将单击的元素存储在thisElem
中,而不是不再相关的this
更新2:
进一步更新了我的解决方案,以反映funcComplete实际上没有修改原始的$scope。处理此问题的角度方法是通过指令。我找到了一个完美的例子来回答你下面的问题,虽然它没有我想要的那么干净。其思想是创建一个用作HTML属性的指令。当元素绑定到控制器的作用域时,将触发
链接
函数。该函数淡入元素(完全可选),并公开销毁方法供控制器稍后调用
更新:根据注释进行修改,以实际影响范围。对这个解决方案不感兴趣,甚至更为简捷,因为最初的作者在他的destroy回调中调用了complete.apply(scope)
,但在回调函数中没有使用this
更新2:由于指令是使回调异步的指令,因此最好使用scope.$apply
,但请记住,如果在指令中使用隔离作用域,这可能会变得奇怪
HTML:
至于原因,我认为这仅仅是为了分离关注点和可用性。控制器应该关注数据流和业务逻辑,而不是接口操作。理想情况下,您的指令应该是为可用性而编写的(比如这里的
fadey
——ed.注意:我不会称之为fadey;)。本文中显示的代码对我理解relationship controller-指令非常有帮助,但它抛出了一个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);
});
});
};
}
};
});
在角度控制器中没有正确的方法进行DOM操作。这就是指令的作用。请参阅。如果使用jQuery,请将其包含在angular.js之前,以便angular随后采用完整的jQuery库,而不是它自己的库。通过这样做,指令中的
elm
已经是一个jQuery对象,不必将其包装在jQuery(elm)
中,我使用console.log(这)在第10行中,它表示这是一个“子”对象。为什么?这个类是什么?这一切似乎都很好,但是我的原始示例包括一个Object.delete success回调,其中this
不再引用单击的元素,因此我不确定需要调用哪个对象destroy()
?(还有,抱歉,我过早地接受了答案,直到我意识到它似乎没有涵盖上面的例子)@AladdinHoms在这种情况下,我相信这是ng repeat中存在的范围(其中提供了物品和销毁功能)。实际上这里有一点问题,似乎拼接不会影响控制器的原始$scope。如果我像您一样从我的答案中省略了remove()
,那么LI仍然存在于DOM中,尽管它被fadeOut()隐藏了。因此,诸如之类的“空”行不会触发任何项目,因为尽管有拼接,项目
仍然具有长度。
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);
});
});
};
}
};
});
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);
});
});
};
}
};
});