19

I am a seasoned Flex Developer that is learning AngularJS. This is so confusing!!!

Anyway, I am trying to make a service call to my backend (on the same domain) server via a SOAP WSDL Request, and populate the data with an AngularJS model object. I was trying Ajax but was having some issues with getting the actual data back. I think there is something wrong with the way I created the SOAP tag. I was getting a successful response back, but no data.

After not being able to figure out the Ajax method, I came across soapclient.js and found it to be extremely easy, with less code than Ajax. soapclient.js does most of the work for you, similar to the Ajax method, which makes much less code. Additionally, using soapclient.js I am able to make the SOAP call and also get data back the XML formatted response.

http://javascriptsoapclient.codeplex.com

My issue is that I am trying to use AngularJS to dump the XML response into an AnularJS model object. I am not sure how to setup the AngularJS project for what I am doing, but I would really like to know the best method in order to keep what I am working on decoupled. I have been searching Google like crazy, but most examples seem overly complicated for a beginner.

Here is what I have:

<html>
<head>
    <script language="JavaScript" type="text/javascript" src="jquery-1.10.1.js"></script>
    <script language="JavaScript" type="text/javascript" src="soapclient.js"></script>

    <script type="text/javascript">
        function getData() {
            var url2 = "https://myService";
            var pl = new SOAPClientParameters();

            pl.add("arg0", false);

            SOAPClient.invoke(url2, "methodToCall", pl, true, getDataCallback);
        }

        function getDataCallback(r, soapResponse) {
            alert(r.contents.payeeMailName);
        }
    </script>
</head>

<body>
<form>
    <input type="button" value="Click Here to Call Web Service" onClick="getData()" style="width: 192px">
</form>
<div id="result">Result?</div>
</body>
</html>

Now, the SOAP service returns the data like this:

 <return>
    <contents>
       <eftAcctType>S</eftAcctType>
       <id>
          <djNumber>201-16-39063</djNumber>
          <djSequence>1</djSequence>
       </id>
       <payeeAddrLine1>124 Agate Drive</payeeAddrLine1>
    </contents>
    <contents>
       <eftAcctType/>
       <id>
          <djNumber>201-16-39201</djNumber>
          <djSequence>1</djSequence>
       </id>
       <payeeAddrLine1>c/o Kevin Martinez, Attorney at Law</payeeAddrLine1>
    </contents>
    <contents>
       <eftAcctType>C</eftAcctType>
       <id>
          <djNumber>201-16-38561</djNumber>
          <djSequence>1</djSequence>
       </id>
       <payeeAddrLine1>1360 South Highway 191</payeeAddrLine1>
    </contents>
    <status>0</status>
 </return>

What is the "proper" way in AngularJS to make the service call, assuming the way I did it is ok, if not let me know the best way, and then in the result, how do I loop through the data in the XML response and parse it into an Angular model object? I eventually want to use this data in a DataGrid.

Any help will be much appreciated.

anad2312
  • 787
  • 2
  • 8
  • 20

3 Answers3

19

Two years late, but I have built a Angular module specifically for working with SOAP web services that is on GitHub.

https://github.com/andrewmcgivery/angular-soap

Here is a blog post on how to use it: http://mcgivery.com/soap-web-services-angular-ionic/

Long story short, it allows you to do something like this:

angular.module('myApp', ['angularSoap'])

.factory("testService", ['$soap',function($soap){
    var base_url = "http://www.cooldomain.com/SoapTest/webservicedemo.asmx";

    return {
        HelloWorld: function(){
            return $soap.post(base_url,"HelloWorld");
        }
    }
}])

.controller('MainCtrl', function($scope, testService) {

  testService.HelloWorld().then(function(response){
    $scope.response = response;
  });

})
Andrew McGivery
  • 1,350
  • 8
  • 20
  • Would this work with the soap server in this [question](http://stackoverflow.com/questions/24516280/where-is-the-correct-place-to-enable-cors)? – C R May 15 '15 at 02:14
  • @Andrew I'm getting error on this line angular.module('myApp', ['angularSoap']) Error : Uncaught ReferenceError: angular is not defined – Naila Akbar Dec 11 '15 at 13:18
  • 1
    Did you include the angular soap scripts AFTER your angular script? – Andrew McGivery Dec 13 '15 at 00:44
  • Hi @AndrewMcGivery, is there a way to change node prefixes in request xml? I need these prefixes `` instead of `` that are currently produced by your module. Thanks. – BorisR Jul 13 '16 at 09:34
  • @AndrewMcGivery: I am using https://www.crcind.com/csp/samples/SOAP.Demo.cls but getting CORS issue. – Rahul Razdan May 27 '20 at 18:51
8

I guess the best way would be to implement it as a $http interceptor. I did it in our project and it worked great because the angular $http calls stay the same.

This is a link to the provider I created for our project : http://jsfiddle.net/gqp9m/
I did some copy-paste from the soapclient library and moved it into a provider. I also changed a bit of the syntax so the code will pass jsHint. Most of the modified function are commented with documentation notes. It also requires jQuery (for the $.parseXML function - you can refactor it to remove dependency in jQuery).

The biggest difference is that my code does not load the wsdl on first request, but rather needs you to cache it before making any call, like so :

myModule.service(['myModule.soap-interceptor', function(soap){
    $http.get('http://www.myveryfakedomain.com/CRMAPIWS74?wsdl', 
    { isJSON: true }).then(function(result){
        soap.setWSDL('http:/www.myveryfakedomain.com/CRMAPIWS74', result.data);
    });
}]);

soap is the injected soap-interceptor instance. You call the wsdl and then call soap.setWSDL passing it the base url and the resolved wsdl. Also note the isJSON argument passed to the $http call. This is there because by default my code treats every call as a SOAP request. That's what interceptors do. isJSON:true will allow you to use $http as god intended ;)

After calling setWSDL just call $http like you always do:

$http.get('http:/www.myveryfakedomain.com/CRMAPIWS74/action').then(function(result){
    // do something...
});

Please remember that this code was written for our project and it's not a supported open source project or something. It may need of some level of maintenance or refactoring before you can use it, but it's a good start.

Yair Tavor
  • 2,538
  • 1
  • 20
  • 16
  • Thanks for that. Was difficult, but I got a wsdl from the soap server. How do I run a command getPrice() in it? ` ` – Evgeniy Tkachenko Jan 17 '14 at 13:23
  • I'm no SOAP expert, javascript is more my thing, but you usually call SOAP actions by referring to the url of the SOAP service and adding the action at the end - like so: http//www.fakedomain.com/api/getPriceRequest You do so using POST, and send the message described in the WSDL inside the request body. – Yair Tavor Jan 19 '14 at 10:36
  • Thanks. How do you pass data with the SOAP call? – anad2312 Feb 26 '14 at 19:21
  • Would you happen to have a small project that contains this? I am new to AngularJS and I am a Flex Developer... banging my head on the wall trying to piece this all together while learning AngularJS. Thanks – anad2312 Feb 27 '14 at 01:03
  • Sorry, my implementation is project-specific, so I can't give you a generic working solution. Regarding data in soap call, send the request as POST and pass the soap arguments in the $http options.data – Yair Tavor Mar 02 '14 at 06:46
  • Is there any example usage for this interceptor? – makeitmorehuman Sep 10 '14 at 14:33
  • Again, this is not a generic solution, it code from a project I'm working on so any samples I'll provide would also be specific for my project. The idea of using an interceptor is that you don't have to change you regular $http calls. There are some samples for that in https://docs.angularjs.org/api/ng/service/$http – Yair Tavor Sep 11 '14 at 10:51
  • @YairTavor thanks for this. What would be the license for code you posted at http://jsfiddle.net/gqp9m/ ? Thanks! – Philippe Ombredanne Aug 21 '18 at 12:44
  • @Philippe - no license. Feel free to use it – Yair Tavor Aug 23 '18 at 05:54
  • @YairTavor thank you.... but no license means ... no rights to use this at all. Can you be a bit more explicit, such as with an MIT or BSD license? – Philippe Ombredanne Aug 24 '18 at 08:11
  • Dude, just do whatever you want with it. I'm not going to sue you ;) – Yair Tavor Aug 25 '18 at 10:43
0

You can achieve this without any SOAP wsdl libraries. import your wsdl into SOAP UI and copy the envelope. below is the example in AngularJS how to handle SOAP Web Service.

Service:

app.service('service', function($http) {
this.soapService = function(_anydata) {
    var _url = 'soap_service_endpoint_url';
    var soapRequest = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:jn=""><soapenv:Header/><soapenv:Body><=== xxx ===></soapenv:Body></soapenv:Envelope>';
    var soapAction = '<=== soap action ===>';
    var headers = {
        'SOAPAction': soapAction,
        'Content-Type': 'text/xml; charset=utf-8'
    };
    return $http.post(_url, soapRequest, {
        "headers": headers
    });
}
});

call the service and handle the XML output. you can capture the attributes you want:

service.soapService(data).then(function success(response) {
var _dataArr = [];
$(response.data).find('Transaction').each(function() {
    _dataArr.push({
        name: $(this).find('<=== your attributes ===>').text()
    });
});
return _dataArr;
}, function error(response) {
console.log('<==== soap error: ' + response);
return response;
});