Pregunta

I am trying to update and then get the update value of an AngularJs factory, I am setting the value in one scope and trying to get it in another, I am setting a factory to handle the pop up messages in my app so instead of repeating my self I want just one factory to handle the messages.

myApp.factory('msg',function ($modal) {
    factory = {};

    factory.text = '';
    factory.modal;
    factory.response;

    factory.window = function () {
        this.modal = $modal.open({
            templateUrl:'partials/message/confirm.html',
            controller:'cms'
        });
    }

    factory.setText = function (text) {
        this.text = text;
    }

    factory.getResponse = function () {
        return this.response;
    }

    factory.confirm = function () {
        this.modal.close();
        this.response = true;
    }

    factory.cancel = function () {
        this.modal.close();
        this.response = false;
    }

    factory.confirmSave = function () {
        this.text = 'save';
        this.window();
    }

    factory.confirmUpdate = function () {
        this.text = 'update';
        this.window();
    }

    factory.confirmDelete = function () {
        this.text = 'delete';
        this.window();
    }


    return factory;
});

the users controller

myApp.controller('users',function ($scope,$location,$http,msg) {
    $http.get('api/v1/users')
    .success(function (data,status) {
        $scope.user = data;
    })
    .error(function (data,status) {
        $location.path('/login');
    });

    $scope.showWrite = function () {
        $scope.write = true;
    }

    $scope.closeWrite = function () {
        $scope.write = false;
        $scope.newUser = '';
    }

    $scope.save = function () {
        $http.post('api/v1/users/store',$scope.newUser)
        .success(function (data,status) {

            $scope.user.unshift({
                first_name: $scope.newUser.first_name,
                last_name: $scope.newUser.last_name,
                email: $scope.newUser.email,
                role: $scope.newUser.role
            });

            $scope.write = false;
            $scope.newUser = '';
        })
        .error(function (data,status) {
            alert('failed');
        });
    }

    $scope.confirmDelete = function (index,id) {
        msg.confirmDelete();
        if(msg.getResponse() === true){
            $http.get('api/v1/users/destroy/'+id)
            .success(function (data,status) {
                $scope.user.splice(index,1);
            })
            .error(function (data,status) {
                alert('failed');
            });
        };
        console.log(msg.getResponse());
    }

    $scope.showUserInfo = function () {

    }

});
¿Fue útil?

Solución

It seems that the code you provided working fine and the problem is somewhere else, probably in cms controller or in confirm.html template. I've made a plunker with your factory where you can see it live.

index.html

<div ng-controller="ctrl1">
  <button ng-click="msg.confirmSave()">confirm save</button>
  <span ng-if="msg.getResponse() !== undefined">Response: {{msg.getResponse()}}</span>
</div>

confirm.html

<h1>{{msg.text}}</h1>
<button ng-click="msg.confirm()">Confirm</button>
<button ng-click="msg.cancel()">Cancel</button>

JavaScript

angular.module('app',['ui.bootstrap']).
  controller('cms', ['$scope', 'msg', function($scope, msg){
    $scope.msg = msg;
  }]).
  controller('ctrl1', ['$scope', 'msg', function($scope, msg) {
    $scope.msg = msg;
  }]).
  factory('msg',['$modal', function ($modal) {
    // The same code as in the question
  }]);

Some tips:

  • Use var factory = {}; instead of factory = {} in order to declare local variable and not to override global factory occasionally.
  • factory.modal; and factory.response; do not declare relevant properties in factory object as you expect, but return undefined instead, so just remove them, because they are useless
  • factory.setText and facory.getResponse are redundant, since factory.text and factory.response are public properties of factory. If you want to make them private to the factory, declare them as var text; and var response; and change the accessor methods accordingly. It will be also useful to addgetText to your factory in that case.
  • If you plan to access factory.modal only from you factory, it is better to incapsulate it to your factory (make it private) as described in the previous bullet.
  • Expose only public API from the factory (don't expose window for example)

After applying all tips your factory may look like the following:

factory('msg',['$modal', function ($modal) {
    var text = '',
        modal,
        response;

    function window () {
        modal = $modal.open({
            templateUrl:'confirm.html',
            controller:'cms'
        });
    }

    return {
      setText: function (_text_) {
        text = _text_;
      },
      getText: function() {
        return text;
      },
      getResponse: function () {
        return response;
      },
      confirm: function () {
        modal.close();
        response = true;
      },
      cancel: function () {
        modal.close();
        response = false;
      },
      confirmSave: function () {
        text = 'save';
        window();
      },
      confirmUpdate: function () {
        text = 'update';
        window();
      },
      confirmDelete: function () {
        text = 'delete';
        window();
      }
    };
  }]);

Here is a plunker.

EDIT:

After you updated the post with controller code everything is clear to me: the real problem is that you use confirmDelete() synchronously, but it is asynchronous (since returns value in the future, once user clicks confirm or cancel)! To deal with asynch staff angular has a $q service. In order to use it, you should create deferred object in factory.confirmSave(), factory.confirmUpdate() and factory.confirmDelete(), return it's promise and resolve/reject it in factory.confirm() and factory.cancel(). Once promise is resolved or rejected you can fetch the value from factory or get it directly as argument of relevant callback.

factory

function confirmDelete() {
  deferred = $q.defer();
  text = this;
  window();
  return deferred.promise;
}

controller

msg.confirmDelete().then(function(value) {
    // Resolved
    $scope.response = value;
}, function(value) {
    // Rejected
    $scope.response = value;
});

Full example see in the following plunker.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top