Angular 在 ajax 之后更新 $scope 变量未反映在 UI 中

Angular updating $scope variable after ajax is not reflecting in UI

我似乎无法弄清楚这里的问题。 在 ajax 成功响应中,我在当前控制器中设置了一个未反映在 UI 中的值。我发现的一般答案是 运行 和 Angular ajax 函数 and/or 将 $apply 或 $digest 应用于 $scope。 None 个正在运行。

请注意代码中的 {{ 和 }} angular 标签被替换为 <% 和 %>,因为我使用的是 blade tempting 引擎并且这些标签冲突。

想法是在控制器中设置一个处理布尔值。在 ajax 之前设置为 true,之后设置为 false。问题是该值未 returned 到其 false 状态。 运行 $apply 或 $digest 方法都 return Error: [$rootScope:inprog].

之后ajax我运行

console.log($scope.processing); console.log(this.processing); console.log($scope);

返回

undefind undefind return 是 $scope 对象。 但是,在控制台输出的 $scope 对象中,处理的值是应该的 (false)。

然而在UI中并没有体现出来,这仍然是事实。单击切换按钮将处理值设置为 false,并更新 UI。 所以我对问题出在哪里感到非常困惑...

HTML

<div class="panel panel-default" ng-controller="UnitOfMeasureController as uom">
          <div class="panel-heading">
            <h3 class="panel-title">Create new Unit of Measure</h3>
          </div>
          <div class="panel-body">
            <div ng-hide="uom.processing">
           <form ng-submit="uom.processForm()" id="new_uom_form">
              <div class="form-group">
                <label for="uom_input01">Name</label>
                <input ng-model="uom.formData['name']" type="text" class="form-control" id="uom_input01" placeholder="" name="uom[input01]" value="{{\xsds::old('uom.input01',$values)}}">
              </div>
               <div style="text-align:right"><button type="submit" class="btn btn-primary" ><i class="fa fa-plus-square"></i> Create new Unit of Measure</button></div>
                </form> 
                </div>
                {!!\xsds::angularLoader('ng-show="uom.processing"')!!}
            </div>
            <button ng-click="uom.processing = false">Toggle</button>
            <%uom.processing%>
        </div>

app.js

(function( ){
var app = angular.module('ingredients',[], function($interpolateProvider) {
$interpolateProvider.startSymbol('<%');
$interpolateProvider.endSymbol('%>');
}); 


app.controller('UnitOfMeasureController', ['$scope','$http', function($scope,$http) {
formData = [];
this.processing = false;
this.processForm = function( ){
    this.processing = true;

    $http.get(document.js_root+'/recipe/ingredients/uom/ajax-create').
      success(function(data, status, headers, config) {
         /* $scope.$apply(function(){
              $scope.processing = false;
            });*/
          console.log($scope.processing);
          console.log(this.processing);
          console.log($scope);

          $scope.processing = false;
          if (!data.success) {  
              console.log(data.errors);
          } else {
              console.log('success');
          }

          //$scope.$digest();
          //$scope.$apply(); similar but slower
        /*  $scope.$apply(function() {
              $scope.processing = false;
            });*/
      }).
      error(function(data, status, headers, config) {
          $scope.processing = false;
         if(document.is_js_dev){
             alert(status+' ');
         }            
      });       

     return false;
};
}]);



})();

你的控制器代码应该重置标志 this.processing = false; 而不是 $scope.processing = false;,因为您使用的是 controllerAs 语法。

另外使用var vm = this;然后使用 vm 而不是 this

控制器

app.controller('UnitOfMeasureController', ['$scope','$http', function($scope,$http) {
   var vm = this;
   //then use this in your controller instead of this
}]);

是的,var vm = this; 是一种方式。

或者您可以在成功或错误方法中使用 .bind(this)。对于 ES6,您可以使用 arrow functions.

请看这个jsfiddle。与下面的演示相同。

var app = angular.module('ingredients', [], function ($interpolateProvider) {
    $interpolateProvider.startSymbol('<%');
    $interpolateProvider.endSymbol('%>');
});


app.controller('UnitOfMeasureController', ['$scope', '$http', function ($scope, $http) {
    formData = [];
    this.processing = false;
    this.processForm = function () {
        this.processing = true;
        
        var onSuccess = function (data, status, headers, config) {
            /* $scope.$apply(function(){
              $scope.processing = false;
            });*/
            //console.log($scope.processing);
            console.log(this.processing);
            //console.log($scope);

            this.processing = false;
            /*if (!data.success) {
                console.log(data.errors);
            } else {*/
            console.log('success', data);
            //}

            //$scope.$digest();
            //$scope.$apply(); similar but slower
            /*  $scope.$apply(function() {
              $scope.processing = false;
            });*/
        };
        
        var onError = function (data, status, headers, config) {
            this.processing = false;
            if (document.is_js_dev) {
                alert(status + ' ');
            }
        };
        
        $http.jsonp('http://www.mocky.io/v2/5568b30150223de60c64f24f/?callback=JSON_CALLBACK').//document.js_root + '/recipe/ingredients/uom/ajax-create').
        success(onSuccess.bind(this)).
        error(onError.bind(this));

        return false;
    };
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="panel panel-default" ng-app="ingredients" ng-controller="UnitOfMeasureController as uom">
    <div class="panel-heading">
         <h3 class="panel-title">Create new Unit of Measure</h3>

    </div>
    <div class="panel-body">
        <div ng-hide="uom.processing">
            <form ng-submit="uom.processForm()" id="new_uom_form">
                <div class="form-group">
                    <label for="uom_input01">Name</label>
                    <input ng-model="uom.formData['name']" type="text" class="form-control" id="uom_input01" placeholder="" name="uom[input01]" value="{{\xsds::old('uom.input01',$values)}}">
                </div>
                <div style="text-align:right">
                    <button type="submit" class="btn btn-primary"><i class="fa fa-plus-square"></i> Create new Unit of Measure</button>
                </div>
            </form>
        </div><!--{!!\xsds::angularLoader('ng-show="uom.processing"')!!}</div>-->
    <button ng-click="uom.processing = !uom.processing">Toggle</button>
    <%uom.processing%>
</div>

$http.get 的成功函数中的

变量 this 可能不再是您想要的 this。事实上 this 也许 somebody that you used to know 但现在你忘记了 !

我已经修改了你的代码用于演示

 app.controller('UnitOfMeasureController', [
    '$scope',
    '$http', 
    UnitOfMeasureController
]);

function UnitOfMeasureController($scope,$http) {
    var vm = this;
    vm.processing = false;
    vm.processForm  = processForm;

    function processForm(){
        vm.processing = true;

        var url = document.js_root+'/recipe/ingredients/uom/ajax-create';
        return $http
            .get(url)
            .success(function() {
                vm.processing = false;   
            })
            .error(function(err) {
                vm.processing = false;
            });        
    };
}

但我认为您应该将 $http.get 部分移至服务,例如 RecipeService 或任何您想要的名称。

查看 https://github.com/johnpapa/angular-styleguide 以获得最佳实践 angular 风格。这是最新的指南,甚至 google 本身也引用了它。