Search code examples
javascriptangularjsangular-resource

Angular model is null inside resource promise


I am trying actualize an angular model inside a resource promise, but the problem is that this model is undefined.

Basically I have list of products that are showing on the page and for all products I have a delete action. I want, after successfully deleting the product, to actualize the list of products on the page.

My resource definition:

angular.module('bookshop').factory('productsFactory', function($resource, serverUrlValue) {
  return $resource(serverUrlValue + '/bookshop/products/:id', {
    id: '@id',
    query: '@query'
  }, {
    update: {method: 'PUT'},
    search: {method: 'GET', params: '@query', url: serverUrlValue + '/bookshop/products/search', isArray: true}
  });
});

My controller definition:

angular.module('bookshop').controller('cmsProductsController', function($state, $stateParams, utilService, productsFactory, categoriesFactory) {
  this.products = productsFactory.query();
  //skipped methods
  this.remove = function(productId) {
    //here object looks good
    console.log(this.products);
    this.result = productsFactory.delete({id: productId}).$promise.then(function() {
        //here object is undefined
        console.log(this.products);
        this.products = productsFactory.query();
    })
  }
});

My HTML:

<tr ng-repeat="product in cmsProductsCtrl.products track by $index">
  <td>{{product.name}}</td>
  <td>{{product.price | currency}}</td>
  <td>
    <a ng-click="cmsProductsCtrl.remove(product.id)" href="">
      <span class="glyphicon glyphicon-trash icon-sm"></span>
    </a>
  </td>
</tr>

Also for managing controllers and views I am using ui-router.

My route definition:

angular.module('bookshop').config(function($stateProvider, $urlRouterProvider, $locationProvider) {
  $stateProvider.state('cms.products', {
    url: '/products',
    controller: 'cmsProductsController',
    controllerAs: 'cmsProductsCtrl',
    templateUrl: 'core/cms/products/cms-products.tpl.html'
  });
});

Screen from debugger:

Screenshot of the console in developer tools, showing a collapsed Resource object with a $promise and $resolved proerty. Underneath is the string undefined, printed from the above code

UPDATE

Thanks to the @Jesus Carrasco I solved my problem, by these changes in controller

Solution:

angular.module('bookshop').controller('cmsProductsController', function($state, $stateParams, utilService, productsFactory, categoriesFactory) {
  this.products = productsFactory.query();
  //skipped methods
  this.remove = function(productId) {
    var model = this;
    //object looks good
    console.log(model.products);
    productsFactory.delete({id: productId}).$promise.then(function() {
      //object also looks good
      console.log(model.products);
      model.products = productsFactory.query();
    });
  }
});

Solution

  • The problem is the ambit of this, its better using $scope or even better the alias like vmSomething = this; to avoid this kind of problems. Try this example.

    State Config Phase

    $stateProvider.
    state('yourstate',{
     url:'yoururl',
     controller:'cmsProductsController',
     controllerAs:'vm',
     templateUrl:'yourhtmlroute'
    });
    

    Controller Avoid using this. try better use of controllerAs

    angular.module('bookshop').controller('cmsProductsController', 
    function($state, $stateParams, utilService, productsFactory, 
    categoriesFactory) {
      //skipped methods
      var vm = this;
      vm.remove = function(productId) {
    //here object looks good
    console.log(vm.products);
        vm.result = productsFactory.delete({id: productId}).$promise.then(function() {
        //here object is undefined
        console.log(vm.products);
        vm.products = productsFactory.query();
        })
      }
    });
    

    HTML

    <tr ng-repeat="product in vm.products track by $index">
      <td>{{product.name}}</td>
      <td>{{product.price | currency}}</td>
      <td>
        <a ng-click="vm.remove(product.id)" href="">
          <span class="glyphicon glyphicon-trash icon-sm"></span>
        </a>
      </td>
    </tr>
    

    if you ar using ui-router in state use controllerAs:'vm' if not in your ng-controller add 'controllerName as vm'