├── 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]) + ""; 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]) + "" 95 | } 96 | else // associative array 97 | s += "<" + p + ">" + SOAPClientParameters._serialize(o[p]) + "" 98 | } 99 | } 100 | // Object or custom function 101 | else 102 | for(var p in o) 103 | s += "<" + p + ">" + SOAPClientParameters._serialize(o[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 | ""; 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 | --------------------------------------------------------------------------------