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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 05:02:36  来源:igfitidea点击:

ng-disabled not evaluating after data change

javascripthtmlajaxangularjs

提问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.htmlthe button calls upgradeComponentin controller.jscontroller MachineOverviewCtrlissuing an Ajax request and on success updating $scope.userand $scope.machine, changed data is reflected in the view (ng-repeat) but the buttons ng-disabledis not evaluated and keeps the old state.

对于领先地位,在machine-overview.html该按钮的调用upgradeComponentcontroller.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 指令。

example image

示例图像

//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-disabledinstead 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-disableddirective.

您的主要问题是您正在插入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()
    }