Http request service with Angular throwing an erro

2019-09-09 00:37发布

问题:

I am trying to write a service that makes a http request to my route (NodeJs) to add a user to the db.

If I just write it in the controller it works but then you won't see the user added until I refresh the browser:

my code in the controller:

//Function to add a user to the db
$scope.inviteUser = function(){
    $http.post('/api/users/invite', {
        'email': $scope.user.email,
        'role_id': $scope.user.role
    }, {
        headers: {
            "Content-Type": "text/plain"
        }
    })
    .success(function(data, status, headers, config) {
        console.log("Successfully saved a user to the DB", data);

        $scope.userInfo.push(data);


    })
    .error(function(data, status, headers, config) {
        console.log("Failed to add user to DB");
    });
}

The reason I need it in a service is because people on stack told me that it would resolve the issue that I am currently facing that is when a user is added you won't see it until the browser is refreshed. This is because I have a view with a button invite and when you click on it a popup shows (md-dialog -> angular material). This dialog has its own tmple.html file. In the view where the invite button resides is the $scope.userInfo linked to (defined in the function inviteUser - code from above)

Code for the view with the invite button and the list where the user get added:

<div id="sidebar" class="md-whiteframe-z4" ng-data-color="">
      <div style="height: 80px;"></div>
      <div class="userList">
        <li id="customLI" ng-repeat="user in userInfo" id="userPos" class="circular md-whiteframe-z2" style="background-color: {{ user.color }} " ng-click=" showPopUpDeletionConfirmation(); setDeleteId( user._id )" ng-data-id="{{ user._id }} ">
          <p class="initials" id="userValue" style="top: {{ user.top }};" >
              <custom id="user._id"></custom>
              {{user.initials}}
          </p>
        <md-tooltip>
        <!-- Delete this user -->  {{user.name}}
        </md-tooltip>
        </li>
      </div>
    </div>

Code of the dialog box :

  <md-dialog aria-label="" ng-controller="CalendarCtrl">
    <form name="form"  >
      <md-toolbar>
        <div class="md-toolbar-tools">
          <h1 class="customH1">Invite a user</h1>

          <span flex></span>
          <!-- <md-button class="md-icon-button" ng-click="closeDialog()">
            <md-icon md-svg-src="images/ic_close_24px.svg" aria-label="Close dialog"></md-icon>
          </md-button> -->
        </div>
      </md-toolbar>
      <md-dialog-content>
        <div id="containerForm">
            <div layout="row">
              <md-input-container flex="">
                <div class="form-group" ng-class="{ 'has-success': form.email.$valid && submitted,'has-error': form.email.$invalid && submitted }">
                  <label>Enter the user's e-mail</label>
                  <input type="email" name="email" id="to" class="form-control" ng-model="user.email" required mongoose-error/>
                  <p class="help-block" ng-show="form.email.$error.email && submitted">
                    Doesn't look like a valid email.
                  </p>
                  <p class="help-block" ng-show="form.email.$error.required && submitted">
                    What's your email address?
                  </p>
                  <p class="help-block" ng-show="form.email.$error.mongoose">
                    {{ errors.email }}
                  </p>
                </div>
              </md-input-container>
            </div>  

            <br /><br />

            <div ng-show="form.email.$dirty && form.email.$valid">
              <h5>Assign one of the following role's:</h5>

              <div id="wrapperRadioButtons">
                <md-radio-group ng-model="user.role">
                  <md-radio-button ng-repeat="userrole in roleInfo" value="{{userrole.id}}" class="md-primary">{{userrole.role}}</md-radio-button>
                </md-radio-group>
              </div>
              </div>

            <br />

        </div>
      </md-dialog-content>
      <div class="md-actions" layout="row" >
        <md-button ng-click="closeDialog()" class="md-primary">Cancel</md-button>

        <md-button id="send_email" ng-click="inviteUser(); closeDialog()" class="md-primary">Invite</md-button>
      </div>
    </form>
  </md-dialog>

This is the service I wrote and tried to link to the function inviteUsers:

zazzleApp.factory('UserService', ['$q', '$http', function ($q, $http) {
            var service = {};

            service.get = function() {
              var deferred = $q.defer();

              deferred.resolve(service.data);
              return deferred.promise;
            }

            service.save = function(data) {
                var promise = $http({
                    method: 'POST',
                    url: 'api/users/invite'
                })

                var deferred = $q.defer();

                service.data.push(data);
                deferred.resolve();
                return deferred.promise;
            }

            return service;
        }
    ]);

Part of my controller:

angular.module('zazzleToolPlannerApp')
    .controller('CalendarCtrl', function ($scope, $mdDialog, $http, $rootScope, $timeout, User, Auth, UserService) {

        //Function to add a user to the db
        $scope.inviteUser = function(){

           var obj = {
                'email': $scope.user.email,
                'role_id': $scope.user.role
           };
           UserService.save(obj).then(function(){
                $scope.getUsers();

           })
        }
});

Now when I try to add a user I get an error in my console -> https://gyazo.com/34b39d7eda18b8afd9ef11094b4f429a

So basically what I am asking is how to write a service that makes an http request and link it to a controller ....

Side note: I have never done this before so thats why its probably not working.

回答1:

The reason you get an error in the console is because service.data in service.data.push(data); does not exist. What you meant was probably to push the new user into an array of users which has not been created yet (and you seem confused about the "data" in the code:P).

Anyway, the solution for your problem is much simpler: in the service you can return the $http.post() to the controller and process the request in the controller on the .success() callback. Further, the list of users that you need updated should reside in the service and you bind to it from your controller; this way it will keep the template updated after you add a new user without refreshing the browser. You just have to retrieve the list of users on the $http callback from the service.

I can write a fiddle if you still find this confusing.

EDIT: here is the fiddle: http://jsfiddle.net/bosch/8pnL23k7/. Hope it will help you understand the concepts better



回答2:

all I can see is that in your log it says

typeError can not read property 'push' of undefined at object.service.save

I think this does not have anything to do with your HTTP request. You have not defined your service.data.push(data); and that is where he dumps

Try defining the data property of service object as an array before you push values to it (it doesnt know that its an array yet, so it cant access the arrays prototyp functions)

do this

service = { data: [] };

hope this helped.