GerM
GerM

Reputation: 169

Passing multiple arguments from controller to factory service making REST calls and returning (optional) data

I am trying to create code that uses services (factory) and ngResource to send a request to a RESTful service that performs and action and sends optional results back based on business logic.

I am aware of a question that talks about something similar found at Passing multiple parameters from controller to factory in angularjs . I'm having problems getting it to work for me and there also is a lack of explanation.

I'm writing this to understand how it works, best practice and so there's a repository that's good for newbies like myself in future. No disrespect to the author of the solution provided above but it probably assumes a level of cleverness I've not yet attained ;-)

Here goes:

My controller

swof.controller('scheduleController', ['$scope', '$log', '$http', '$filter','moment', 'scheduleServicePeriod', function($scope, $log, $http, $filter, moment, scheduleServicePeriod) {

  $scope.name = 'scheduleController::set default values and provide function to generate new schedule';
  $log.info('Controller: '+ $scope.name);
  $scope.years = ["2017", "2018", "2019","2020","2021","2022"];
  $scope.selectedYear = "2017";
  $scope.selectedPeriod = Math.ceil(moment().format('w')) | 1 ;
  $scope.genSchedule = function()
  {
    // when button is pressed function 'genSchedule' is called that either has default value for selectedYear and selectedPeriod or one user has selected. This bit works
    scheduleServicePeriod.post({ s_year: $scope.selectedYear, s_period: $scope.selectedPeriod }).$promise.then(function(data){
      $scope.schedulegen = data;
        $scope.genScheduleResponse=moment().format('h:mm:ss a') + " " + data.message;
    }, function(data) {
      $log.error();('Error: ' + data);
    })};

}]);

My factory service

swof.factory('scheduleServicePeriod', function($resource)
{
  var data = $resource('/api/schedules/period/:s_year/:s_period',{s_year: "@s_year",s_period: "@s_period" },
  {
    'post':
    {
      method: 'POST',
      params: {},
      isArray:true
    }
  });
  return data;
});

My RESTful Web Service

  router.route('/schedules/period/:schedule_year/:schedule_period')

    .post(function(req,res)
    {
      // create record
      var query =  getEngineerIDs();
      var jsonMessage = "Success: Generated schedule for year = " + req.params.schedule_year + " and period starting week number =   " + req.params.schedule_period ;

      console.log(parseInt(req.params.schedule_period%2),parseInt(req.params.schedule_period));

      query.exec(function(err,records)
      {
        if(err) return console.log(err);
        var results = SwfFn.populateCalendar(SwfFn.assignEngineers(records),+
                      req.params.schedule_year,req.params.schedule_period);
        if ( results.length == 0  ) {
          jsonMessage = "Failed: Start year/week in past";
        }
        console.log(jsonMessage);
        for (var count in results)
        {
          Schedule.findOneAndUpdate (
            { ymd: results[count].ymd, shift: results[count].shift },
            results[count],
            {upsert: true, new: true, runValidators: true},
            function (err,res) { if (err) res.send(err); }
          );
        }
        res.json({message: jsonMessage });
      });

    })

What happens

  1. The values (default or otherwise) reach the function genSchedule.
  2. The values that reach the RESTful service are 'undefined' 'undefined'
  3. The problem is with the factory service.
  4. There is a similar solution which I've not got to work (above)
  5. I am aware that you should only send one JSON from controller to service but I'm not sure how to handle it on the factory side.
  6. I can't (yet) get the retrieval part to work but that can wait for now.

Appreciate the help!

Upvotes: 0

Views: 26

Answers (1)

GerM
GerM

Reputation: 169

It actually worked! What I was doing wrong was printing out the wrong values when using console.log for debugging and the way I displayed the response message in the UI.

To summarise I want to make an API call along the lines of POST /api/schedules/period//

The call does a calculation and sends back a response I want to show the end-user on the screen.

Here's the working code which can still be improved but is a reasonably good example for basic use cases. The syntax for sending down the parameters is fairly straightforward if you follow the example to is logical conclusion.

Controller

swof.controller('scheduleController', ['$scope', '$log', '$http', '$filter','moment', 'scheduleServicePeriod', function($scope, $log, $http, $filter, moment, scheduleServicePeriod) {

  $scope.name = 'scheduleController::set default values and provide function to generate new schedule';
  $log.info('Controller: '+ $scope.name);
  $scope.years = ["2017", "2018", "2019","2020","2021","2022"];
  $scope.selectedYear = "2017";
  $scope.selectedPeriod = Math.ceil(moment().format('w')) | 1 ;

  $scope.genSchedule = function()
  {
    scheduleServicePeriod.post({ s_year: $scope.selectedYear, s_period: $scope.selectedPeriod }).$promise.then(function(data){
      $scope.schedulegen = data;
      $scope.genScheduleResponse=moment().format('h:mm:ss a') + " " + data.message;
    }, function(data) {
      $log.error();('Error: ' + data);
    })};

}]);

Factory Service

swof.factory('scheduleServicePeriod', function($resource)
{
  var data = $resource('/api/schedules/period/:s_year/:s_period',{s_year: "@s_year",s_period: "@s_period" },
  {
    'post':
    {
      method: 'POST'
    }
  });
  return data;
});

RESTful call

  router.route('/schedules/period/:schedule_year/:schedule_period')

    .post(function(req,res)
    {
      // create record
      var query =  getEngineerIDs();
      var jsonMessage = "Success: Generated schedule for year/period [" + req.params.schedule_year + "/" + req.params.schedule_period +"]" ;

      query.exec(function(err,records)
      {
        if(err) return console.log(err);
        var results = SwfFn.populateCalendar(SwfFn.assignEngineers(records),+
                      req.params.schedule_year,req.params.schedule_period);
        if ( results.length == 0  ) {
          jsonMessage = "Failed: Start year/week in past";
        }
        for (var count in results)
        {
          // Write record to Mongo using upsert; if records for future date already
          // here then overwrite them otherwise insert. This is ok since the period
          // is in the future
          Schedule.findOneAndUpdate (
            { ymd: results[count].ymd, shift: results[count].shift },
            results[count],
            {upsert: true, new: true, runValidators: true},
            function (err,res) { if (err) res.send(err); }
          );
        }
        res.json({message: jsonMessage });
        console.log(jsonMessage);
      });

Web Page

<div>
  <h3>Generate</h3>
<h4>Generate schedule for future periods</h4>
<p>Select year and week start period to generate a schedule for future support slots. Previously generated values will be lost. You cannot generate  a scheule for periods in the past or the current period we are in.</p>
<form name="scheduleGenerate">
   <select ng-model="selectedYear" ng-options="x for x in years"></select>
   Start Week (1-51 [odd numbers]):
   <input ng-model="selectedPeriod" type="number" name="genperiod" placeholder="1" min="1" max="51" step="2" onkeydown="return false">
   <input type="button" class="click" id="click" value="Generate" ng-click="genSchedule()">
   <label class="control-label">  {{ genScheduleResponse }}</label>
 </form>
</div>

Hope someone finds this useful.

Upvotes: 0

Related Questions