Угловое обновление переменной $scope после того, как ajax не отображается в пользовательском интерфейсе

Кажется, я не могу понять проблему здесь. При успешном ответе ajax я устанавливаю значение в текущем контроллере, которое не отражается в пользовательском интерфейсе. Общий ответ, который я нашел, состоит в том, чтобы работать с функциями Angular ajax и/или применять $apply или $digest к $scope. Ни один из них не работает.

Обратите внимание, что в коде угловые теги {{ и }} заменены на ‹% и %>, так как я использую механизм заманчивых лезвий, и эти теги конфликтуют.

Идея состоит в том, чтобы установить логическое значение обработки в контроллере. Установите значение true перед ajax и значение false после. Проблема в том, что значение не возвращается в ложное состояние. Запуск метода $apply или $digest возвращает Error: [$rootScope:inprog].

После ajax я бегу

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

Возвращение

undefind undefind И возвращает объект $scope. Однако в объекте $scope, выводимом в консоль, значение обработки такое, как должно быть (false).

Однако это не отражено в пользовательском интерфейсе, это все еще верно. При нажатии на кнопку-переключатель для значения обработки устанавливается значение false, и пользовательский интерфейс обновляется. Так что я очень запутался, где проблема...

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;
};
}]);



})();

person Shane    schedule 29.05.2015    source источник


Ответы (3)


переменная this внутри функции успеха $http.get может больше не быть 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.

person quocnguyen.clgt    schedule 29.05.2015
comment
Хорошо, это работает. Однако мне нужно было заменить $scope на vm в ответе http. Почему Фак это делает по-другому!?! Я не вижу логики... Это в основном означает, что "это" назначение было изменено? И вм всегда будет управляемым. - person Shane; 29.05.2015
comment
Вы были правы. На самом деле я считаю, что внутри функции успеха this ссылаются на сам $http. Все говорят о this stackoverflow.com/questions/ 3127429/ - person quocnguyen.clgt; 29.05.2015

Код вашего контроллера должен сбрасывать флаг 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
}]);
person Pankaj Parkar    schedule 29.05.2015
comment
Добавление this.processing = false не имеет никакого эффекта. Если я ввожу в консоль значение this.processing до и после его назначения, я получаю «неопределенное» и «ложное». Где он должен выводить «истина», а затем «ложь». Тем не менее, пользовательский интерфейс остается прежним. - person Shane; 29.05.2015
comment
@Шейн, ты заменил this на vm в своем контроллере? - person Pankaj Parkar; 29.05.2015
comment
@ Шейн, ты посмотрел мое обновление ... ответ, который ты принял, имеет то же самое, что я описал в своем ответе ... не могли бы вы проверить это ... - person Pankaj Parkar; 29.05.2015

Да, var vm = this; был бы способ.

Или вы можете использовать .bind(this) в своих методах успеха или ошибки. В ES6 вы можете использовать стрелочные функции.

Пожалуйста, взгляните на этот 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>

person AWolf    schedule 29.05.2015