├── README.md
├── angular.soap.js
├── bower.json
└── soapclient.js
/README.md:
--------------------------------------------------------------------------------
1 | angular-soap
2 | ============
3 |
4 | An Angular port of a JavaScript SOAP Client into a factory that has a similar syntax to $http.
5 |
6 | # Usage
7 | Before using the factory, you must import the two scripts and its module:
8 |
9 | ``` html
10 |
11 |
12 | ```
13 |
14 | ``` javascript
15 | angular.module('myApp', ['angularSoap']);
16 | ```
17 |
18 | Then, wherever you are going to consume it, make a reference to the $soap service for dependency injection:
19 |
20 | ``` javascript
21 | .factory("testService", ['$soap',function($soap){
22 | //use it here
23 | }])
24 | ```
25 |
26 | $soap has one method, post, which accepts the following paramaters:
27 |
28 | | Parameter |Description | Example |
29 | | ------------ | ------------ | ------------ |
30 | | url | The base URL of the service | "http://www.cooldomain.com/SoapTest/webservicedemo.asmx" |
31 | | action | The action you want to call | "HelloWorld" |
32 | | params | An object of parameters to pass to the service | { name: "Andrew" } |
33 |
34 | Syntax:
35 | ``` javascript
36 | $soap.post(url,action,params);
37 | ```
38 |
39 | Similar to $http methods, $soap.post returns a promise that you can act upon.
40 |
41 | ``` javascript
42 | $soap.post(url,action,params).then(function(response){
43 | //Do Stuff
44 | });
45 | ```
46 |
47 | NOTE: Response will be a javascript object containing the response mapped to objects. Do a console.log of response so you can see what you are working with.
48 |
49 | # Example 1: Hello World
50 | A basic "Hello World" with no parameters.
51 |
52 | ``` javascript
53 | angular.module('myApp', ['angularSoap'])
54 |
55 | .factory("testService", ['$soap',function($soap){
56 | var base_url = "http://www.cooldomain.com/SoapTest/webservicedemo.asmx";
57 |
58 | return {
59 | HelloWorld: function(){
60 | return $soap.post(base_url,"HelloWorld");
61 | }
62 | }
63 | }])
64 |
65 | .controller('MainCtrl', function($scope, testService) {
66 |
67 | testService.HelloWorld().then(function(response){
68 | $scope.response = response;
69 | });
70 |
71 | })
72 |
73 | ```
74 |
75 | # Example 2: Invoke with Parameters
76 | A basic method call with parameters.
77 |
78 | ``` javascript
79 | angular.module('myApp', ['angularSoap'])
80 |
81 | .factory("testService", ['$soap',function($soap){
82 | var base_url = "http://www.cooldomain.com/SoapTest/webservicedemo.asmx";
83 |
84 | return {
85 | CreateUser: function(firstName, lastName){
86 | return $soap.post(base_url,"CreateUser", {firstName: firstName, lastName: lastName});
87 | }
88 | }
89 | }])
90 |
91 | .controller('MainCtrl', function($scope, testService) {
92 |
93 | testService.CreateUser($scope.firstName, $scope.lastName).then(function(response){
94 | $scope.response = response;
95 | });
96 |
97 | })
98 |
99 | ```
100 |
101 | # Example 3: Get Single Object
102 | A basic method call to get a single object.
103 |
104 | ``` javascript
105 | angular.module('myApp', ['angularSoap'])
106 |
107 | .factory("testService", ['$soap',function($soap){
108 | var base_url = "http://www.cooldomain.com/SoapTest/webservicedemo.asmx";
109 |
110 | return {
111 | GetUser: function(id){
112 | return $soap.post(base_url,"GetUser", {id: id});
113 | }
114 | }
115 | }])
116 |
117 | .controller('MainCtrl', function($scope, testService) {
118 |
119 | testService.GetUser($scope.id).then(function(user){
120 | console.log(user.firstName);
121 | console.log(user.lastName);
122 | });
123 |
124 | })
125 |
126 | ```
127 |
128 | # Example 4: Get Many Objects
129 | A basic method call to get a collection of objects.
130 |
131 | ``` javascript
132 | angular.module('myApp', ['angularSoap'])
133 |
134 | .factory("testService", ['$soap',function($soap){
135 | var base_url = "http://www.cooldomain.com/SoapTest/webservicedemo.asmx";
136 |
137 | return {
138 | GetUsers: function(){
139 | return $soap.post(base_url,"GetUsers");
140 | }
141 | }
142 | }])
143 |
144 | .controller('MainCtrl', function($scope, testService) {
145 |
146 | testService.GetUsers().then(function(users){
147 | for(i=0;i"
7 | ],
8 | "description": "An angular port of a Javascript SOAP Client into a factory that has a similar syntax to $http.",
9 | "main": ["soapclient.js","angular.soap.js"],
10 | "keywords": [
11 | "soap",
12 | "angular",
13 | "web",
14 | "services"
15 | ],
16 | "license": "MIT",
17 | "ignore": [
18 | "**/.*",
19 | "node_modules",
20 | "bower_components",
21 | "test",
22 | "tests"
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/soapclient.js:
--------------------------------------------------------------------------------
1 | /*****************************************************************************\
2 |
3 | Javascript "SOAP Client" library
4 |
5 | @version: 2.4 - 2007.12.21
6 | @author: Matteo Casati - http://www.guru4.net/
7 |
8 | \*****************************************************************************/
9 |
10 | function SOAPClientParameters()
11 | {
12 | var _pl = new Array();
13 | this.add = function(name, value)
14 | {
15 | _pl[name] = value;
16 | return this;
17 | }
18 | this.toXml = function()
19 | {
20 | var xml = "";
21 | for(var p in _pl)
22 | {
23 | switch(typeof(_pl[p]))
24 | {
25 | case "string":
26 | case "number":
27 | case "boolean":
28 | case "object":
29 | xml += "<" + p + ">" + SOAPClientParameters._serialize(_pl[p]) + "" + p + ">";
30 | break;
31 | default:
32 | break;
33 | }
34 | }
35 | return xml;
36 | }
37 | }
38 | SOAPClientParameters._serialize = function(o)
39 | {
40 | var s = "";
41 | switch(typeof(o))
42 | {
43 | case "string":
44 | s += o.replace(/&/g, "&").replace(//g, ">"); break;
45 | case "number":
46 | case "boolean":
47 | s += o.toString(); break;
48 | case "object":
49 | // Date
50 | if(o.constructor.toString().indexOf("function Date()") > -1)
51 | {
52 |
53 | var year = o.getFullYear().toString();
54 | var month = (o.getMonth() + 1).toString(); month = (month.length == 1) ? "0" + month : month;
55 | var date = o.getDate().toString(); date = (date.length == 1) ? "0" + date : date;
56 | var hours = o.getHours().toString(); hours = (hours.length == 1) ? "0" + hours : hours;
57 | var minutes = o.getMinutes().toString(); minutes = (minutes.length == 1) ? "0" + minutes : minutes;
58 | var seconds = o.getSeconds().toString(); seconds = (seconds.length == 1) ? "0" + seconds : seconds;
59 | var milliseconds = o.getMilliseconds().toString();
60 | var tzminutes = Math.abs(o.getTimezoneOffset());
61 | var tzhours = 0;
62 | while(tzminutes >= 60)
63 | {
64 | tzhours++;
65 | tzminutes -= 60;
66 | }
67 | tzminutes = (tzminutes.toString().length == 1) ? "0" + tzminutes.toString() : tzminutes.toString();
68 | tzhours = (tzhours.toString().length == 1) ? "0" + tzhours.toString() : tzhours.toString();
69 | var timezone = ((o.getTimezoneOffset() < 0) ? "+" : "-") + tzhours + ":" + tzminutes;
70 | s += year + "-" + month + "-" + date + "T" + hours + ":" + minutes + ":" + seconds + "." + milliseconds + timezone;
71 | }
72 | // Array
73 | else if(o.constructor.toString().indexOf("function Array()") > -1)
74 | {
75 | for(var p in o)
76 | {
77 | if(!isNaN(p)) // linear array
78 | {
79 | (/function\s+(\w*)\s*\(/ig).exec(o[p].constructor.toString());
80 | var type = RegExp.$1;
81 | switch(type)
82 | {
83 | case "":
84 | type = typeof(o[p]);
85 | case "String":
86 | type = "string"; break;
87 | case "Number":
88 | type = "int"; break;
89 | case "Boolean":
90 | type = "bool"; break;
91 | case "Date":
92 | type = "DateTime"; break;
93 | }
94 | s += "<" + type + ">" + SOAPClientParameters._serialize(o[p]) + "" + type + ">"
95 | }
96 | else // associative array
97 | s += "<" + p + ">" + SOAPClientParameters._serialize(o[p]) + "" + p + ">"
98 | }
99 | }
100 | // Object or custom function
101 | else
102 | for(var p in o)
103 | s += "<" + p + ">" + SOAPClientParameters._serialize(o[p]) + "" + p + ">";
104 | break;
105 | default:
106 | break; // throw new Error(500, "SOAPClientParameters: type '" + typeof(o) + "' is not supported");
107 | }
108 | return s;
109 | }
110 |
111 | function SOAPClient() {}
112 |
113 | SOAPClient.username = null;
114 | SOAPClient.password = null;
115 |
116 | SOAPClient.invoke = function(url, method, parameters, async, callback)
117 | {
118 | if(async)
119 | SOAPClient._loadWsdl(url, method, parameters, async, callback);
120 | else
121 | return SOAPClient._loadWsdl(url, method, parameters, async, callback);
122 | }
123 |
124 | // private: wsdl cache
125 | SOAPClient_cacheWsdl = new Array();
126 |
127 | // private: invoke async
128 | SOAPClient._loadWsdl = function(url, method, parameters, async, callback)
129 | {
130 | // load from cache?
131 | var wsdl = SOAPClient_cacheWsdl[url];
132 | if(wsdl + "" != "" && wsdl + "" != "undefined")
133 | return SOAPClient._sendSoapRequest(url, method, parameters, async, callback, wsdl);
134 | // get wsdl
135 | var xmlHttp = SOAPClient._getXmlHttp();
136 | if (SOAPClient.username && SOAPClient.password){
137 | xmlHttp.open("GET", url + "?wsdl", async, SOAPClient.username, SOAPClient.password);
138 | // Some WS implementations (i.e. BEA WebLogic Server 10.0 JAX-WS) don't support Challenge/Response HTTP BASIC, so we send authorization headers in the first request
139 | xmlHttp.setRequestHeader("Authorization", "Basic " + SOAPClient._toBase64(SOAPClient.username + ":" + SOAPClient.password));
140 | }
141 | else
142 | xmlHttp.open("GET", url + "?wsdl", async);
143 | if(async)
144 | {
145 | xmlHttp.onreadystatechange = function()
146 | {
147 | if(xmlHttp.readyState == 4)
148 | SOAPClient._onLoadWsdl(url, method, parameters, async, callback, xmlHttp);
149 | }
150 | }
151 | xmlHttp.send(null);
152 | if (!async)
153 | return SOAPClient._onLoadWsdl(url, method, parameters, async, callback, xmlHttp);
154 | }
155 | SOAPClient._onLoadWsdl = function(url, method, parameters, async, callback, req)
156 | {
157 | var wsdl = req.responseXML;
158 | SOAPClient_cacheWsdl[url] = wsdl; // save a copy in cache
159 | return SOAPClient._sendSoapRequest(url, method, parameters, async, callback, wsdl);
160 | }
161 | SOAPClient._sendSoapRequest = function(url, method, parameters, async, callback, wsdl)
162 | {
163 | // get namespace
164 | var ns = (wsdl.documentElement.attributes["targetNamespace"] + "" == "undefined") ? wsdl.documentElement.attributes.getNamedItem("targetNamespace").nodeValue : wsdl.documentElement.attributes["targetNamespace"].value;
165 | // build SOAP request
166 | var sr =
167 | "" +
168 | "" +
172 | "" +
173 | "<" + method + " xmlns=\"" + ns + "\">" +
174 | parameters.toXml() +
175 | "" + method + ">";
176 | // send request
177 | var xmlHttp = SOAPClient._getXmlHttp();
178 | if (SOAPClient.username && SOAPClient.password){
179 | xmlHttp.open("POST", url, async, SOAPClient.username, SOAPClient.password);
180 | // Some WS implementations (i.e. BEA WebLogic Server 10.0 JAX-WS) don't support Challenge/Response HTTP BASIC, so we send authorization headers in the first request
181 | xmlHttp.setRequestHeader("Authorization", "Basic " + SOAPClient._toBase64(SOAPClient.username + ":" + SOAPClient.password));
182 | }
183 | else
184 | xmlHttp.open("POST", url, async);
185 | var soapaction = ((ns.lastIndexOf("/") != ns.length - 1) ? ns + "/" : ns) + encodeURIComponent(method);
186 | xmlHttp.setRequestHeader("SOAPAction", soapaction);
187 | xmlHttp.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
188 | if(async)
189 | {
190 | xmlHttp.onreadystatechange = function()
191 | {
192 | if(xmlHttp.readyState == 4)
193 | SOAPClient._onSendSoapRequest(method, async, callback, wsdl, xmlHttp);
194 | }
195 | }
196 | xmlHttp.send(sr);
197 | if (!async)
198 | return SOAPClient._onSendSoapRequest(method, async, callback, wsdl, xmlHttp);
199 | }
200 |
201 | SOAPClient._onSendSoapRequest = function(method, async, callback, wsdl, req)
202 | {
203 | var o = null;
204 | var nd = SOAPClient._getElementsByTagName(req.responseXML, method + "Result");
205 | if(nd.length == 0)
206 | nd = SOAPClient._getElementsByTagName(req.responseXML, "return"); // PHP web Service?
207 | if(nd.length == 0)
208 | {
209 | if(req.responseXML.getElementsByTagName("faultcode").length > 0)
210 | {
211 | if(async || callback)
212 | o = new Error(500, req.responseXML.getElementsByTagName("faultstring")[0].childNodes[0].nodeValue);
213 | else
214 | throw new Error(500, req.responseXML.getElementsByTagName("faultstring")[0].childNodes[0].nodeValue);
215 | }
216 | }
217 | else
218 | o = SOAPClient._soapresult2object(nd[0], wsdl);
219 | if(callback)
220 | callback(o, req.responseXML);
221 | if(!async)
222 | return o;
223 | }
224 | SOAPClient._soapresult2object = function(node, wsdl)
225 | {
226 | var wsdlTypes = SOAPClient._getTypesFromWsdl(wsdl);
227 | return SOAPClient._node2object(node, wsdlTypes);
228 | }
229 | SOAPClient._node2object = function(node, wsdlTypes)
230 | {
231 | // null node
232 | if(node == null)
233 | return null;
234 | // text node
235 | if(node.nodeType == 3 || node.nodeType == 4)
236 | return SOAPClient._extractValue(node, wsdlTypes);
237 | // leaf node
238 | if (node.childNodes.length == 1 && (node.childNodes[0].nodeType == 3 || node.childNodes[0].nodeType == 4))
239 | return SOAPClient._node2object(node.childNodes[0], wsdlTypes);
240 | var isarray = SOAPClient._getTypeFromWsdl(node.nodeName, wsdlTypes).toLowerCase().indexOf("arrayof") != -1;
241 | // object node
242 | if(!isarray)
243 | {
244 | var obj = null;
245 | if(node.hasChildNodes())
246 | obj = new Object();
247 | for(var i = 0; i < node.childNodes.length; i++)
248 | {
249 | var p = SOAPClient._node2object(node.childNodes[i], wsdlTypes);
250 | obj[node.childNodes[i].nodeName] = p;
251 | }
252 | return obj;
253 | }
254 | // list node
255 | else
256 | {
257 | // create node ref
258 | var l = new Array();
259 | for(var i = 0; i < node.childNodes.length; i++)
260 | l[l.length] = SOAPClient._node2object(node.childNodes[i], wsdlTypes);
261 | return l;
262 | }
263 | return null;
264 | }
265 | SOAPClient._extractValue = function(node, wsdlTypes)
266 | {
267 | var value = node.nodeValue;
268 | switch(SOAPClient._getTypeFromWsdl(node.parentNode.nodeName, wsdlTypes).toLowerCase())
269 | {
270 | default:
271 | case "s:string":
272 | return (value != null) ? value + "" : "";
273 | case "s:boolean":
274 | return value + "" == "true";
275 | case "s:int":
276 | case "s:long":
277 | return (value != null) ? parseInt(value + "", 10) : 0;
278 | case "s:double":
279 | return (value != null) ? parseFloat(value + "") : 0;
280 | case "s:datetime":
281 | if(value == null)
282 | return null;
283 | else
284 | {
285 | value = value + "";
286 | value = value.substring(0, (value.lastIndexOf(".") == -1 ? value.length : value.lastIndexOf(".")));
287 | value = value.replace(/T/gi," ");
288 | value = value.replace(/-/gi,"/");
289 | var d = new Date();
290 | d.setTime(Date.parse(value));
291 | return d;
292 | }
293 | }
294 | }
295 | SOAPClient._getTypesFromWsdl = function(wsdl)
296 | {
297 | var wsdlTypes = new Array();
298 | // IE
299 | var ell = wsdl.getElementsByTagName("s:element");
300 | var useNamedItem = true;
301 | // MOZ
302 | if(ell.length == 0)
303 | {
304 | ell = wsdl.getElementsByTagName("element");
305 | useNamedItem = false;
306 | }
307 | for(var i = 0; i < ell.length; i++)
308 | {
309 | if(useNamedItem)
310 | {
311 | if(ell[i].attributes.getNamedItem("name") != null && ell[i].attributes.getNamedItem("type") != null)
312 | wsdlTypes[ell[i].attributes.getNamedItem("name").nodeValue] = ell[i].attributes.getNamedItem("type").nodeValue;
313 | }
314 | else
315 | {
316 | if(ell[i].attributes["name"] != null && ell[i].attributes["type"] != null)
317 | wsdlTypes[ell[i].attributes["name"].value] = ell[i].attributes["type"].value;
318 | }
319 | }
320 | return wsdlTypes;
321 | }
322 | SOAPClient._getTypeFromWsdl = function(elementname, wsdlTypes)
323 | {
324 | var type = wsdlTypes[elementname] + "";
325 | return (type == "undefined") ? "" : type;
326 | }
327 | // private: utils
328 | SOAPClient._getElementsByTagName = function(document, tagName)
329 | {
330 | try
331 | {
332 | // trying to get node omitting any namespaces (latest versions of MSXML.XMLDocument)
333 | return document.selectNodes(".//*[local-name()=\""+ tagName +"\"]");
334 | }
335 | catch (ex) {}
336 | // old XML parser support
337 | return document.getElementsByTagName(tagName);
338 | }
339 | // private: xmlhttp factory
340 | SOAPClient._getXmlHttp = function()
341 | {
342 | try
343 | {
344 | if(window.XMLHttpRequest)
345 | {
346 | var req = new XMLHttpRequest();
347 | // some versions of Moz do not support the readyState property and the onreadystate event so we patch it!
348 | if(req.readyState == null)
349 | {
350 | req.readyState = 1;
351 | req.addEventListener("load",
352 | function()
353 | {
354 | req.readyState = 4;
355 | if(typeof req.onreadystatechange == "function")
356 | req.onreadystatechange();
357 | },
358 | false);
359 | }
360 | return req;
361 | }
362 | if(window.ActiveXObject)
363 | return new ActiveXObject(SOAPClient._getXmlHttpProgID());
364 | }
365 | catch (ex) {}
366 | throw new Error("Your browser does not support XmlHttp objects");
367 | }
368 | SOAPClient._getXmlHttpProgID = function()
369 | {
370 | if(SOAPClient._getXmlHttpProgID.progid)
371 | return SOAPClient._getXmlHttpProgID.progid;
372 | var progids = ["Msxml2.XMLHTTP.5.0", "Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"];
373 | var o;
374 | for(var i = 0; i < progids.length; i++)
375 | {
376 | try
377 | {
378 | o = new ActiveXObject(progids[i]);
379 | return SOAPClient._getXmlHttpProgID.progid = progids[i];
380 | }
381 | catch (ex) {};
382 | }
383 | throw new Error("Could not find an installed XML parser");
384 | }
385 |
386 | SOAPClient._toBase64 = function(input)
387 | {
388 | var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
389 | var output = "";
390 | var chr1, chr2, chr3;
391 | var enc1, enc2, enc3, enc4;
392 | var i = 0;
393 |
394 | do {
395 | chr1 = input.charCodeAt(i++);
396 | chr2 = input.charCodeAt(i++);
397 | chr3 = input.charCodeAt(i++);
398 |
399 | enc1 = chr1 >> 2;
400 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
401 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
402 | enc4 = chr3 & 63;
403 |
404 | if (isNaN(chr2)) {
405 | enc3 = enc4 = 64;
406 | } else if (isNaN(chr3)) {
407 | enc4 = 64;
408 | }
409 |
410 | output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) +
411 | keyStr.charAt(enc3) + keyStr.charAt(enc4);
412 | } while (i < input.length);
413 |
414 | return output;
415 | }
416 |
--------------------------------------------------------------------------------