4

I am trying to submit a form with multiple table rows. I have found examples online and have managed to send the table data to the AngularJS controller but I cannot figure out how to send that data to the apiController.

The form is a Purchase Order that has a table with the Purchase Order Details. I have chained the submit button with the both the Purchase Order and Purchase Order Detail submit functions.

<table class="table" style="">
    <tbody>
        <tr class="pointer no_selection" ng-repeat="newJobItem in rows">
            <td style="width:50px"><input style="width:20px" type="checkbox" class="form-control"></td>
            <td style="width:200px">{{newJobItem.JobItemName}}</td>
            <td style="width:480px">{{newJobItem.JobItemDescription}}</td>
            <td style="width:100px">{{newJobItem.JobItemMatSize}}</td>
            <td style="width:150px">{{newJobItem.JobItemQuantity}}</td>
            <td style="width:50px">{{newJobItem.JobItemUOM}}</td>
            <td style="width:150px">${{newJobItem.JobItemPrice | number : fractionSize}}</td>
            <td style="width:20px"><input type="button" value="X" class="btn btn-primary btn-sm" ng-click="removeRow(newJobItem.JobItemName)" /></td>
        </tr>

    </tbody>
</table>


<input style="margin-right:30px" id="btn-width" type="button" class="btn btn-default" ng-click="submitPurchaseOrder();submitPurchaseOrderDetail()" value="Submit"/>

Controller

   //Post Purchase Order
$scope.PODate = new Date(); //Todays Date
$scope.POId = Math.floor(Math.random() * 1000000001) //PurchaseOrder Id Generator
$scope.submitPurchaseOrder = function () {;
    var data = {
        JobId: $scope.job.JobId,
        POId : $scope.POId,
        PONumber: $scope.currentItem.PONumber,
        PODate: $scope.PODate,
        POAmount: $scope.currentItem.POAmount,
        POLastPrintDate: $scope.currentItem.POLastPrintDate,
        POEmail: $scope.POEmail,
        POPrint: $scope.currentItem.POPrint,
        POFaxNumber: $scope.POFaxNumber,
        PONotes: $scope.currentItem.PONotes,
        POCreatedBy: $scope.currentItem.POCreatedBy,
        PODeliveryDate: $scope.currentItem.PODeliveryDate,
        POShipVia: $scope.currentItem.POShipVia,
        POShowPrices: $scope.currentItem.POShowPrices,
        POCostCode: $scope.currentItem.POCostCode,
        POApprovedNumber: $scope.currentItem.POApprovedNumber,
        POBackorder: $scope.currentItem.POBackorder,
       }
    $http.post('/api/apiPurchaseOrder/PostNewPurchaseOrder', data).success(function (data, status, headers) {
        console.log(data);
        var tmpCurrentItem = angular.copy($scope.currentItem);
        $scope.purchaseOrderArray.push(tmpCurrentItem)
        angular.copy({}, $scope.currentItem);
        //hide modal window
        $scope.openNewPurchaseOrderModal.then(function (m) {
            m.modal('hide');
        });

    });
};
//Post Purchase Order Detail
$scope.newJobItem = {};
$scope.submitPurchaseOrderDetail = function () {
    var index = 0;
    $scope.rows.forEach(function (newJobItem) {
        console.log('rows #' + (index++) + ': ' + JSON.stringify(newJobItem));
    });
    var data = {
        POId: $scope.POId,
        PODItem: $scope.newJobItem.JobItemName,
        PODDescription: $scope.newJobItem.JobItemDescription,
        PODNotes: $scope.PODNotes,
        PODUOM: $scope.newJobItem.JobItemUOM,
        PODPrice: $scope.newJobItem.JobItemPrice,
        PODQuantity: $scope.newJobItem.JobItemQuantity,
        PODAmount: $scope.PODAmount,
        PODMatSize: $scope.newJobItem.JobItemMatSize,
        PODSection: $scope.PODSection,
        PODMultiplier: $scope.PODMultiplier,
        PODBackOrder: $scope.PODBackOrder
    }
    $http.post('/api/apiPurchaseOrderDetail/PostNewPurchaseOrderDetail', data).success(function (data, status, headers) {
        console.log(data); window.top.location.reload();

    });
};

Purchase Order Detail ApiController

 // POST api/<controller>

    public async Task<IHttpActionResult> PostnewPurchaseOrderDetail([FromBody]PurchaseOrderDetail newPurchaseOrderDetail)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        using (var context = new ApplicationDbContext())
        {
            context.PurchaseOrderDetails.Add(newPurchaseOrderDetail);
            await context.SaveChangesAsync();
            return CreatedAtRoute("PurchaseOrderDetailApi", new { newPurchaseOrderDetail.PODId }, newPurchaseOrderDetail);
        }
    }

Update Changed as suggested

 // POST api/<controller>
    public HttpResponseMessage PostNewPurchaseOrderDetail(int id, PurchaseOrderDetail newPurchaseOrderDetail)
    {
        ApplicationDbContext db = new ApplicationDbContext();
        if (!ModelState.IsValid)
        {
            return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
        }

        if (id != newPurchaseOrderDetail.PODId)
        {
            return Request.CreateResponse(HttpStatusCode.BadRequest);
        }

        db.Entry(newPurchaseOrderDetail).State = EntityState.Modified;

        try
        {
            db.SaveChanges();
        }
        catch (DbUpdateConcurrencyException ex)
        {
            return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
        }

        return Request.CreateResponse(HttpStatusCode.OK);
    }
Graham
  • 7,431
  • 18
  • 59
  • 84
texas697
  • 5,609
  • 16
  • 65
  • 131

3 Answers3

3

You are executing two functions, each making an asyncronous request:

ng-click="submitPurchaseOrder();submitPurchaseOrderDetail()"

This doesn't feel right - both requests are sent in parallel and none is waiting for the other. Do you really mean it?

I would either package and send all data in a single request (also better experience for the user), then let the server deal with un-packaging. Or, if one request needs to wait for another, chain the Promises returned by $http:

$http.post(...)
     .then(function(){
         return $http.post(...);
     })
     .success(...)
     .fail(...);

or use $q.all(promises) instead.

EDIT.

Also a cleaner and more scalable approach is to use dedicated Angular Service to post your data, see e.g. example on Angular Homepage

Dmitri Zaitsev
  • 13,548
  • 11
  • 76
  • 110
  • I wasn't sure how to do it, but using the Promises makes sense. But I still do not know how to send the PurchaseOrderDetail data to the apiController? – texas697 Nov 08 '14 at 19:24
  • The only examples I found online that show how to submit multiple records are strongly typed projects. – texas697 Nov 08 '14 at 19:26
  • @texas697 Your ajax request looks fine, you can try http://requestb.in/ to see how your request arrives, then test separately your PHP endpoint. Many examples out there, look for Angular/PHP. – Dmitri Zaitsev Nov 11 '14 at 09:34
3

I'm not sure about your approach, to me it would be better to join both requests, purchaseOrder and the detail into a single call, you can still separate the data as you may feel convenient.

calling both functions at the same time could have unexpected behaviors since both are running asynchronously you may find 'race conditions'.

try to send a single request and organize how you are going to post the information like

var data = {
    JobId: $scope.job.JobId, //common data between the order and the detail
    POId: $scope.POId,
    Order:{

        PONumber: $scope.currentItem.PONumber,
        PODate: $scope.PODate,
        POAmount: $scope.currentItem.POAmount,
        POLastPrintDate: $scope.currentItem.POLastPrintDate,
        POEmail: $scope.POEmail,
        POPrint: $scope.currentItem.POPrint,
        POFaxNumber: $scope.POFaxNumber,
        PONotes: $scope.currentItem.PONotes,
        POCreatedBy: $scope.currentItem.POCreatedBy,
        PODeliveryDate: $scope.currentItem.PODeliveryDate,
        POShipVia: $scope.currentItem.POShipVia,
        POShowPrices: $scope.currentItem.POShowPrices,
        POCostCode: $scope.currentItem.POCostCode,
        POApprovedNumber: $scope.currentItem.POApprovedNumber,
        POBackorder: $scope.currentItem.POBackorder,
    },
    Detail:{
        PODItem: $scope.newJobItem.JobItemName,
        PODDescription: $scope.newJobItem.JobItemDescription,
        PODNotes: $scope.PODNotes,
        PODUOM: $scope.newJobItem.JobItemUOM,
        PODPrice: $scope.newJobItem.JobItemPrice,
        PODQuantity: $scope.newJobItem.JobItemQuantity,
        PODAmount: $scope.PODAmount,
        PODMatSize: $scope.newJobItem.JobItemMatSize,
        PODSection: $scope.PODSection,
        PODMultiplier: $scope.PODMultiplier,
        PODBackOrder: $scope.PODBackOrder
    }

}

you'll need to map the purchase order and the detail to a single dto object in your api controller.

just as a sidenote, I'd recommend you to use a stronger unique identifier rather than using a random number.

Community
  • 1
  • 1
pedrommuller
  • 15,741
  • 10
  • 76
  • 126
0

I think the trouble is with you controller try using this and also can you please elaborate the trouble.Does your APIcontroller is never found by your controller ?

public class Oders : ApiController // in your controller class
{
 public HttpResponseMessage Post(PurchaseOrderDetails newOrder)
 {
 //your code
 }

}
b k
  • 199
  • 1
  • 10
  • ok, I modified the apiController to HttpResponseMessage instead of async. But i still need to set the Angular Controller to Send back the data and "rows". right now its not doing that. I do not know how to combine the 2 – texas697 Nov 03 '14 at 03:29
  • but I am curious why you suggested I changed the async to HttpResponse? – texas697 Nov 03 '14 at 03:34
  • I am using the same thing where I am trying to add multiple entries and my controller makes a http request $http.post('/api/nameofcontroller/',this.newOrder).success... – b k Nov 03 '14 at 04:12
  • are you using Angular in the front end? I need to get that setup first so i can see what happens in the controller – texas697 Nov 03 '14 at 04:17
  • Yes I am using angular...but I thought you said earlier that you are getting data in your controller and the only problem was APIcontroller ? – b k Nov 03 '14 at 04:19
  • Sorry, i managed to get the view to pass the table rows data to the angular controller. But that is where i need help. I need to send that data along with the other form data to the api – texas697 Nov 03 '14 at 14:35