javascript ng-disabled 在数据更改后不进行评估
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25797737/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ng-disabled not evaluating after data change
提问by reggaemuffin
I am writing an app where the user can upgrade components paying with ingame money. After pressing the "upgrade"-button an ajax request is send to the server and upgrades the component. After that I am issuing another ajax request to retrieve the new components page. But while the data gets updated, ng-disabled is not checked again, so the upgrade-button remains clickable when it should not. Reloading page or route fixes this. But reloading the page is no good user experience.
我正在编写一个应用程序,用户可以在其中升级使用游戏币支付的组件。按“升级”按钮后,ajax 请求将发送到服务器并升级组件。之后,我发出另一个 ajax 请求来检索新组件页面。但是当数据更新时,ng-disabled 不会再次检查,所以升级按钮在不应该点击的时候仍然可以点击。重新加载页面或路由可解决此问题。但是重新加载页面并不是很好的用户体验。
I am doing this project to learn the Angularjs way, so if there is anything wrong in my setup or how I do something, please tell me!
我正在做这个项目来学习 Angularjs 的方式,所以如果我的设置或我做某事有什么问题,请告诉我!
I try to include all relevant code, if something is missing, you can view it under this linkwith user and password "test".
我尝试包含所有相关代码,如果缺少某些内容,您可以在此链接下使用用户名和密码“test”查看它。
For a headstart, in machine-overview.html
the button calls upgradeComponent
in controller.js
controller MachineOverviewCtrl
issuing an Ajax request and on success updating $scope.user
and $scope.machine
, changed data is reflected in the view (ng-repeat
) but the buttons ng-disabled
is not evaluated and keeps the old state.
对于领先地位,在machine-overview.html
该按钮的调用upgradeComponent
在controller.js
控制器MachineOverviewCtrl
发出Ajax请求和上成功更新$scope.user
和$scope.machine
,改变的数据被反映在图(ng-repeat
),但该按键ng-disabled
不评估和保持旧状态。
What am I doing wrong? How can I force an evaluation or do the update in a way Angularjs likes it?
我究竟做错了什么?如何强制评估或以 Angularjs 喜欢的方式进行更新?
edit:
编辑:
@Hyman.the.ripper's answer is missing the point, that there are multiple buttons, one for every ng-repeat, but those buttons only don't evaluate their ng-disable directive.
@Hyman.the.ripper 的回答没有说明这一点,即有多个按钮,每个 ng-repeat 一个,但这些按钮只是不评估它们的 ng-disable 指令。
//edit
//编辑
index.html
索引.html
<!DOCTYPE html>
<html lang="de" ng-app="hacksApp">
<head>
<!--ommited includes (angularjs, bootstrap etc)-->
</head>
<body ng-controller="hacksUserCtrl">
<!--ommited navbar-->
<div ng-view></div>
</body>
</html>
machine-overview.html
机器概述.html
<!--ommited divs-->
<table class="table table-bordered">
<!--ommited thead-->
<tbody>
<tr ng-repeat="component in machine | object2Array | orderBy:'ComponentID'"><!--converting objects to arrays, issue appears with and without filter-->
<!--ommited other irrelevant td-->
<td>
<button
ng-disabled="
{{
(component.price_next <= 0) || (component.price_next > user.values.euro) ||
(user.values.energy_remaining < (component.energy_next-component.energy))
}}"
ng-click="upgradeComponent(component)" class="btn btn-danger" role="button">
Upgrade {{component.text}} for <span class="glyphicon glyphicon-euro"></span> {{component.price_next}}
</button>
</td>
</tr>
</tbody>
</table>
<!--ommited divs-->
javascript vars and their origin:
javascript vars 及其起源:
$scope.user.x //hacksUserCtrl
$scope.machine.x //MachineOverviewCtrl
app.js
应用程序.js
var hacksApp = angular.module('hacksApp', [
'ngRoute',
'hacksControllers',
'hacksFilters',
]);
hacksApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/machine', {
templateUrl: 'html/machine-overview.html',
controller: 'MachineOverviewCtrl',
activetab: 'machine'
}).
when('/jobs', {
templateUrl: 'html/jobs-overview.html',
controller: 'JobsOverviewCtrl',
activetab: 'jobs'
}).
when('/phones/:phoneId', {
templateUrl: 'html/phone-detail.html',
controller: 'PhoneDetailCtrl',
activetab: 'phone'
}).
otherwise({
redirectTo: '/machine'
});
}]);
controller.js
控制器.js
var hacksControllers = angular.module('hacksControllers', ['hacksFilters']);
hacksControllers.controller('hacksUserCtrl', ['$scope', '$http', '$interval', '$route',
function ($scope, $http, $interval, $route) {
$scope.$route = $route;
$scope.updateUser = function() {
$http.get('api/user.php').success(function(data) {
$scope.user = data;
if(!$scope.user.loggedIn){
window.location = "index.php";
}
});
}
$scope.updateUser();
$interval($scope.updateUser, 60000);
}]);
hacksControllers.controller('MachineOverviewCtrl', ['$scope', '$http', '$interval',
function ($scope, $http, $interval) {
$scope.machine = [];
$scope.updateMachine = function() {
$http.get('api/machine.php').success(function(data) {
$scope.machine = data;
});
}
$scope.updateMachine();
$interval($scope.updateMachine, 60000);
$scope.upgradeComponent = function(component){
var params = {name: component.name};
$http({
method: 'POST',
url: 'api/machine-upgrade.php',
data: $.param(params),
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).success(function(data) {
$scope.updateMachine();
$scope.updateUser();
});
}
}]);
采纳答案by reggaemuffin
While reading up on $scope.$apply and $scope.$watch I found the solution to this: When I change the order of my requests, everything works. Because on updating the userdata (like money) there is no update triggered for the machine table. Changing the code to first update $scope.user and after that $scope.machine solves this problem. I am making this community wiki.
在阅读 $scope.$apply 和 $scope.$watch 时,我找到了解决方案:当我更改请求的顺序时,一切正常。因为在更新用户数据(如货币)时,不会触发机器表的更新。将代码更改为首先更新 $scope.user,然后 $scope.machine 解决了这个问题。我正在制作这个社区维基。
回答by ryeballar
Your main problem is you are interpolating ng-disabled
instead of providing it an angular expression. See the arguments definition in the documentation. Interpolating (using {{}}
) the expression makes the expression evaluated only once within the ng-disabled
directive.
您的主要问题是您正在插入ng-disabled
而不是为其提供角度表达式。请参阅文档中的参数定义。插入(使用{{}}
)表达式会使表达式在ng-disabled
指令中只计算一次。
Simply change:
只需更改:
<button ng-disabled="
{{
(component.price_next <= 0) || (component.price_next > user.values.euro) ||
(user.values.energy_remaining < (component.energy_next-component.energy))
}}"
ng-click="upgradeComponent(component)" class="btn btn-danger" role="button">
Upgrade {{component.text}} for <span class="glyphicon glyphicon-euro"></span>
{{component.price_next}}
</button>
to
到
<button ng-disabled="(component.price_next <= 0) || (component.price_next > user.values.euro) ||
(user.values.energy_remaining < (component.energy_next-component.energy))"
ng-click="upgradeComponent(component)" class="btn btn-danger" role="button">
Upgrade {{component.text}} for <span class="glyphicon glyphicon-euro"></span>
{{component.price_next}}
</button>
回答by Hyman.the.ripper
your scenario: when a user click on a button you disable it, then when your operation is complete you want to return to the button to enabled.
您的场景:当用户单击一个按钮时,您将其禁用,然后当您的操作完成时,您希望返回该按钮以启用。
what I should do is to create a directive that manage the state of the button while the button is performing the operation, it doesn't matter what operation you are doing....!
我应该做的是创建一个指令,在按钮执行操作时管理按钮的状态,不管你在做什么操作......!
baign said that, a possible answer to your issue could be to use promises and return a promise in your 'click' events, in that way you can set the button to disabled true when the user click it and enable it again when your promise gets resolved.
baign 说,你的问题的一个可能的答案可能是使用承诺并在你的“点击”事件中返回一个承诺,这样你就可以在用户点击按钮时将按钮设置为禁用 true 并在你的承诺得到时再次启用它解决。
take a look to this directive:
看看这个指令:
angular.module('app').directive('clickState', [
function() {
return {
priority:-1,
restrict: 'A',
scope: {
clickState: '&'
},
link: function postLink(scope, element, attrs) {
element.bind('click', function(){
element.prop('disabled', true);
scope.clickState().finally(function() {
element.prop('disabled', false);
});
});
}
};
}
]);
usage:
用法:
<button click-state="updateMachine()" type="submit">submit</button>
controller:
控制器:
var p = $q.defer()
$scope.updateMachine = function() {
$http.get('api/machine.php').success(function(data) {
$scope.machine = data;
p.resolve(); //it could be p.resolve(data); to pass the data with the promise
});
return p.promise()
}