ng-disabled 在数据更改后不评估
Posted
技术标签:
【中文标题】ng-disabled 在数据更改后不评估【英文标题】:ng-disabled not evaluating after data change 【发布时间】:2014-11-06 00:14:27 【问题描述】:我正在编写一个应用程序,用户可以在其中升级用游戏币支付的组件。按下“升级”按钮后,将向服务器发送 ajax 请求并升级组件。之后,我发出另一个 ajax 请求来检索新的组件页面。但是当数据更新时,不会再次检查 ng-disabled ,因此升级按钮在不应该点击时仍然可以点击。重新加载页面或路线可以解决此问题。但是重新加载页面并没有很好的用户体验。
我做这个项目是为了学习 Angularjs 的方式,所以如果我的设置有什么问题或者我是怎么做的,请告诉我!
我尝试包含所有相关代码,如果缺少某些内容,您可以在this link 下查看,用户名和密码为“test”。
首先,在machine-overview.html
中,按钮调用upgradeComponent
在controller.js
控制器MachineOverviewCtrl
发出Ajax 请求并成功更新$scope.user
和$scope.machine
,更改的数据将反映在视图中(@ 987654329@) 但按钮 ng-disabled
未评估并保持旧状态。
我做错了什么?如何强制评估或以 Angularjs 喜欢的方式进行更新?
编辑:
@jack.the.ripper 的回答没有抓住重点,即有多个按钮,每个 ng-repeat 一个,但这些按钮只是不评估它们的 ng-disable 指令。
//编辑
index.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
<!--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 变量及其来源:
$scope.user.x //hacksUserCtrl
$scope.machine.x //MachineOverviewCtrl
app.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
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();
);
]);
【问题讨论】:
【参考方案1】:您的主要问题是您插入 ng-disabled
而不是为其提供角度表达式。请参阅 documentation 中的参数定义。对表达式进行插值(使用 )会使表达式在
ng-disabled
指令中只计算一次。
简单的改变:
<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>
到
<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>
【讨论】:
哇,我现在觉得有点傻!明天试试,然后接受你的回答,谢谢:)【参考方案2】:在阅读 $scope.$apply 和 $scope.$watch 时,我找到了解决方案:当我更改请求的顺序时,一切正常。因为在更新用户数据(如金钱)时,没有为机器表触发更新。将代码更改为首先更新 $scope.user,然后 $scope.machine 解决了这个问题。我正在制作这个社区维基。
【讨论】:
【参考方案3】:您的情况: 当用户单击一个按钮时,您将其禁用,然后当您的操作完成后,您希望返回到启用的按钮。
我应该做的是创建一个指令,在按钮执行操作时管理按钮的状态,不管你在做什么操作......!
baign 说,对您的问题的一个可能的答案可能是使用承诺并在您的“点击”事件中返回一个承诺,这样您就可以在用户单击它时将按钮设置为禁用 true,并在当你的承诺得到了解决。
看看这个指令:
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);
);
);
;
]);
用法:
<button click-state="updateMachine()" type="submit">submit</button>
控制者:
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()
【讨论】:
首先:感谢您的代码!但这听起来有点复杂,可悲的是影响了可用性。如果用户想升级 3 次,他只需点击 3 次。它将更新数据 3 次,并且至少第三次更新获得最新状态。我的特殊问题是,评估ng-disabled="(component.price_next <= 0) || (component.price_next > user.values.euro) || (user.values.energy_remaining < (component.energy_next-component.energy))"
在数据更新后不会评估。它仍然评估旧数据,所以我认为。这与按钮禁用动作无关。
不要忘记绑定点击中的指令 clickState 中的 $scope.$apply()
@Kostronor,尝试将表达式移动到控制器,创建一个变量并将表达式分配给它,将布尔值绑定到 ng-disabled,对组件对象执行 $watch 并查看如何它去
我目前正在阅读 $scope.apply 和 $watch。感谢您的提示!
@jack.the.ripper 我无法将它移动到控制器,因为它依赖于 ng-repeat。每个组件都有一个按钮。 f.e. i.imgur.com/nuHOall.jpg 我可以手动启动应用程序,看看是否有效...编辑:我的更新代码已经在应用程序中运行,所以应该有更新...以上是关于ng-disabled 在数据更改后不评估的主要内容,如果未能解决你的问题,请参考以下文章