1

I cannot seem to figure out the issue here. On an ajax success response I set a value in the current controller that is not reflecting in the UI. The general answer I have found is to run with the Angular ajax functions and/or apply $apply or $digest to the $scope. None of these are working.

Please note in the code the {{ and }} angular tags are replaces with <% and %> as I'm using the blade tempting engine and these tags conflict.

The idea is to set a processing boolean in the controller. Set to true before ajax and the false after. The problem is the value is not returned to its false state. Running the $apply or $digest method both return Error: [$rootScope:inprog].

After the ajax I run

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

Returning

undefind undefind And returns the $scope object. However within the $scope object outputted in the console the value of processing is as it should be (false).

However it is not reflected in the UI it is still true. Clicking the toggle button sets the processing value to false and the UI is updated. So I'm super confused as to where the problem is...

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



})();
Shane
  • 2,055
  • 4
  • 19
  • 29

3 Answers3

0

You controller code should reset flag this.processing = false; instead of $scope.processing = false; as you are using controllerAs syntax.

Additionally use var vm = this; then use vm instead of this

Controller

app.controller('UnitOfMeasureController', ['$scope','$http', function($scope,$http) {
   var vm = this;
   //then use this in your controller instead of this
}]);
Pankaj Parkar
  • 127,691
  • 20
  • 213
  • 279
  • Adding 'this.processing = false` is not having any effect. If I log in the console the value of 'this.processing' before and after assigning it I get 'undefined' and 'false'. Where it should output 'true' and then 'false'. Still the UI remains the same.. – Shane May 29 '15 at 18:58
  • @Shane did you replaced `this` with `vm` in your controller – Pankaj Parkar May 29 '15 at 18:59
  • @Shane did you look at my update..the answer which you are accepted has same thing which i've cover in my answer..could you please check it.. – Pankaj Parkar May 29 '15 at 20:11
0

Yes, var vm = this; would be a way.

Or your could use .bind(this) at your success or error methods. With ES6 you could use arrow functions.

Please have a look at this jsfiddle. Same demo as below.

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>
AWolf
  • 8,062
  • 4
  • 29
  • 36
0

variable this inside the success function of $http.get may not be this you want anymore. In fact this maybe somebody that you used to know but now you forget !

I have modified your code for demonstration

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

But I think you should move the $http.get part to a service, like RecipeService or whatever name you want.

Take a look at https://github.com/johnpapa/angular-styleguide for best practice angular style. This is most up to date guide that even google itself refer to.

  • Ok well it work. However I needed to replace $scope with vm in the http return. Why the Fak does this make a different!?! I cannot see the logic... Is it basically meaning that 'this' assignment as been changed? And vm will always be the controlled. – Shane May 29 '15 at 19:12
  • You was correct. In fact I believe inside the success func, `this` refer to $http itself. Everybody talking about `this ` http://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work – quocnguyen.clgt May 29 '15 at 19:23