Last active
February 8, 2019 13:56
-
-
Save iwannabebot/67bbe0ec8502c4a5631427e0899f9be4 to your computer and use it in GitHub Desktop.
XRM Metadata SDK in TypeScript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export interface XrmMetaAttribute { | |
LogicalName: string; | |
MetadataId: string; | |
DisplayName: DisplayName; | |
Description: Description; | |
IsCustomizable: IsCustomizable; | |
IsAuditEnabled: IsAuditEnabled; | |
OptionsSet: any; | |
AttributeType: string; | |
HasChanged?: any; | |
AttributeOf?: any; | |
ColumnNumber: number; | |
DeprecatedVersion?: any; | |
IntroducedVersion: string; | |
EntityLogicalName: string; | |
IsCustomAttribute: boolean; | |
IsPrimaryId: boolean; | |
IsPrimaryName: boolean; | |
IsValidForCreate: boolean; | |
IsValidForRead: boolean; | |
IsValidForUpdate: boolean; | |
CanBeSecuredForRead: boolean; | |
CanBeSecuredForCreate: boolean; | |
CanBeSecuredForUpdate: boolean; | |
IsSecured: boolean; | |
IsRetrievable: boolean; | |
IsFilterable: boolean; | |
IsSearchable: boolean; | |
IsManaged: boolean; | |
LinkedAttributeId?: any; | |
IsValidForForm: boolean; | |
IsRequiredForForm: boolean; | |
IsValidForGrid: boolean; | |
SchemaName: string; | |
ExternalName?: any; | |
IsLogical: boolean; | |
IsDataSourceSecret: boolean; | |
InheritsFrom?: any; | |
SourceType: number; | |
AutoNumberFormat: string; | |
Format: string; | |
ImeMode: string; | |
MaxLength: number; | |
YomiOf?: any; | |
IsLocalizable: boolean; | |
DatabaseLength: number; | |
FormulaDefinition?: any; | |
SourceTypeMask: number; | |
AttributeTypeName: AttributeTypeName; | |
IsValidForAdvancedFind: IsValidForAdvancedFind; | |
RequiredLevel: RequiredLevel; | |
FormatName: FormatName; | |
Targets: string[]; | |
} | |
export interface XrmMetaEntity { | |
LogicalName: string; | |
MetadataId: string; | |
DisplayName: DisplayName; | |
Description: Description; | |
IsCustomizable: IsCustomizable; | |
IsAuditEnabled: IsAuditEnabled; | |
HasChanged: any; | |
ActivityTypeMask: number; | |
Attributes: XrmMetaAttribute[]; | |
DisplayCollectionName: DisplayCollectionName; | |
IsActivity: boolean; | |
IsActivityParty: boolean; | |
IsBusinessProcessEnabled: string; | |
IsChildEntity: boolean; | |
IsCustomEntity: boolean; | |
IsValidForAdvancedFind: boolean; | |
IsValidForQueue: IsValidForQueue; | |
ManyToManyRelationships: XrmMetaManyToManyRelation[]; | |
ManyToOneRelationships: XrmMetaOneToManyRelation[]; | |
ObjectTypeCode: number; | |
OneToManyRelationships: XrmMetaOneToManyRelation[]; | |
OwnershipType: string; | |
PrimaryIdAttribute: string; | |
PrimaryNameAttribute: string; | |
SchemaName: string; | |
CollectionSchemaName: string; | |
Keys: any; | |
EntitySetName: string; | |
_type: string; | |
} | |
export enum XrmEntityFilter { | |
Default = 1, | |
Entity = 1, | |
Attributes = 2, | |
Privileges = 4, | |
Relationships = 8, | |
All = 15 | |
} | |
export interface AttributeTypeName { | |
Value: string; | |
} | |
export interface FormatName { | |
Value: string; | |
} | |
export interface RequiredLevel { | |
Value: string; | |
CanBeChanged: boolean; | |
ManagedPropertyLogicalName: string; | |
} | |
export interface IsValidForAdvancedFind { | |
Value: boolean; | |
CanBeChanged: boolean; | |
ManagedPropertyLogicalName: string; | |
} | |
export interface LocalizedLabel { | |
MetadataId: string; | |
HasChanged?: any; | |
IsManaged: boolean; | |
Label: any; | |
LanguageCode: number; | |
_type: string; | |
} | |
export interface UserLocalizedLabel { | |
MetadataId: string; | |
HasChanged?: any; | |
IsManaged: boolean; | |
Label?: any; | |
LanguageCode: number; | |
} | |
export interface Description { | |
LocalizedLabels: LocalizedLabel[]; | |
UserLocalizedLabel: UserLocalizedLabel; | |
} | |
export interface LocalizedLabel { | |
Label: any; | |
MetadataId: string; | |
HasChanged?: any; | |
IsManaged: boolean; | |
LanguageCode: number; | |
_type: string; | |
} | |
export interface DisplayCollectionName { | |
LocalizedLabels: LocalizedLabel[]; | |
UserLocalizedLabel: UserLocalizedLabel; | |
} | |
export interface LocalizedLabel { | |
MetadataId: string; | |
HasChanged?: any; | |
IsManaged: boolean; | |
Label: any; | |
LanguageCode: number; | |
_type: string; | |
} | |
export interface DisplayName { | |
LocalizedLabels: LocalizedLabel[]; | |
UserLocalizedLabel: UserLocalizedLabel; | |
} | |
export interface IsAuditEnabled { | |
CanBeChanged: boolean; | |
ManagedPropertyLogicalName: string; | |
Value: boolean; | |
} | |
export interface IsCustomizable { | |
CanBeChanged: boolean; | |
ManagedPropertyLogicalName: string; | |
Value: boolean; | |
} | |
export interface IsValidForQueue { | |
CanBeChanged: boolean; | |
ManagedPropertyLogicalName: string; | |
Value: boolean; | |
} | |
export interface XrmMetaRelation { | |
IsCustomRelationship?: boolean; | |
IsValidForAdvancedFind?: boolean; | |
SchemaName: string; | |
RelationshipType?: XrmMetaRelationshipType; | |
} | |
export interface XrmMetaOneToManyRelation extends XrmMetaRelation { | |
ReferencedAttribute: string; | |
ReferencedEntity: string; | |
ReferencingAttribute: string; | |
ReferencingEntity: string; | |
ReferencedEntityNavigationPropertyName: string; | |
ReferencingEntityNavigationPropertyName: string; | |
} | |
export interface XrmMetaManyToManyRelation extends XrmMetaRelation { | |
Entity1LogicalName: string; | |
Entity2LogicalName: string; | |
IntersectEntityName: string; | |
Entity1IntersectAttribute: string; | |
Entity2IntersectAttribute: string; | |
Entity1NavigationPropertyName: string; | |
Entity2NavigationPropertyName: string; | |
} | |
export enum XrmMetaRelationshipType { | |
OneToManyRelationship = 0, | |
Default = 0, | |
ManyToManyRelationship = 1 | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
XrmMetaOneToManyRelation, | |
XrmMetaManyToManyRelation, | |
IQueryRelation, | |
QueryColumnType, | |
QueryRelationType, | |
IQueryTable, | |
XrmEntityFilter, | |
XrmMetaEntity, | |
DisplayName | |
XrmMetaAttribute } from "xrm-meta-models"; | |
import { Observable } from "rxjs"; | |
import { HttpClient, HttpHeaders } from "@angular/common/http"; | |
// tslint:disable:no-bitwise | |
// tslint:disable:max-line-length | |
export class XrmMetaSdk { | |
private _arrayElements = [ | |
"Attributes", | |
"ManyToManyRelationships", | |
"ManyToOneRelationships", | |
"OneToManyRelationships", | |
"Privileges", | |
"LocalizedLabels", | |
"Options", | |
"Targets" | |
]; | |
constructor(private http: HttpClient, private clientUrl: string) {} | |
public GetTables(): Observable<IQueryTable[]> { | |
const _this = this; | |
return new Observable<IQueryTable[]>(subscriber => { | |
if (_this.IsLocal()) { | |
this.http | |
.get<XrmMetaEntity[]>("http://localhost:54566/GetEntity") | |
.subscribe( | |
entities => { | |
subscriber.next(this.ParseTables(entities)); | |
}, | |
err => { | |
subscriber.error(err); | |
}, | |
() => { | |
subscriber.complete(); | |
} | |
); | |
} else { | |
_this.RetrieveAllEntities( | |
(entities: XrmMetaEntity[]) => { | |
subscriber.next(this.ParseTables(entities)); | |
subscriber.complete(); | |
}, | |
err => { | |
subscriber.error(err); | |
} | |
); | |
} | |
}); | |
} | |
public GetColumnsOfTable(table: IQueryTable): Observable<IQueryColumn[]> { | |
const _this = this; | |
return new Observable<IQueryColumn[]>(subscriber => { | |
if (_this.IsLocal()) { | |
this.http | |
.get<XrmMetaAttribute[]>( | |
"http://localhost:54566/GetAttribute/" + table.Id | |
) | |
.subscribe( | |
attributes => { | |
const columns = _this.ParseColumns(table.Id, attributes); | |
subscriber.next(columns); | |
}, | |
err => { | |
subscriber.error(err); | |
}, | |
() => { | |
subscriber.complete(); | |
} | |
); | |
} else { | |
const __this = _this; | |
_this.RetrieveAttributes( | |
table.Id, | |
(attributes: XrmMetaAttribute[]) => { | |
const columns = _this.ParseColumns(table.Id, attributes); | |
subscriber.next(columns); | |
subscriber.complete(); | |
}, | |
err => { | |
subscriber.error(err); | |
} | |
); | |
} | |
}); | |
} | |
public GetRelationsOfTable(table: IQueryTable): Observable<IQueryRelation[]> { | |
const _this = this; | |
return new Observable<IQueryRelation[]>(subscriber => { | |
if (_this.IsLocal()) { | |
_this.http | |
.get<XrmMetaEntity>( | |
"http://localhost:54566/GetRelationships/" + table.Id | |
) | |
.subscribe( | |
entity => { | |
const o2ms = entity.OneToManyRelationships; | |
const m2os = entity.ManyToOneRelationships; | |
const m2ms = entity.ManyToManyRelationships; | |
subscriber.next(this.ParseRelations(table.Id, o2ms, m2os, m2ms)); | |
}, | |
err => { | |
subscriber.error(err); | |
}, | |
() => { | |
subscriber.complete(); | |
} | |
); | |
} else { | |
const __this = _this; | |
__this.RetrieveRelations( | |
table.Id, null, | |
(entity) => { | |
const o2ms = entity.OneToManyRelationships; | |
const m2os = entity.ManyToOneRelationships; | |
const m2ms = entity.ManyToManyRelationships; | |
subscriber.next(this.ParseRelations(table.Id, o2ms, m2os, m2ms)); | |
subscriber.complete(); | |
}, (err) => { | |
subscriber.error(err); | |
} | |
); | |
} | |
}); | |
} | |
private ParseTables( | |
entities: XrmMetaEntity[]): IQueryTable[] { | |
const tables = entities.map(entity => { | |
return { | |
Alias: "", | |
Id: entity.LogicalName, | |
Name: this.readLabel(entity), | |
PrimaryKeyName: entity.PrimaryIdAttribute, | |
PrimaryName: entity.PrimaryNameAttribute | |
} as IQueryTable; | |
}); | |
return tables; | |
} | |
private ParseColumns( | |
tableId: string, | |
attributes: XrmMetaAttribute[] | |
): IQueryColumn[] { | |
const columns = attributes.map(att => { | |
return { | |
Alias: "", | |
Id: att.LogicalName, | |
Name: this.readLabel(att), | |
Table: tableId, | |
OptionSet: att.OptionsSet.Options.map(op => { | |
return { | |
Key: this.readOptionLabel(op), | |
Value: op.Value | |
} as IQueryOption; | |
}), | |
Type: this.readAttributeType(att.AttributeType), | |
Targets: att.Targets | |
} as IQueryColumn; | |
}); | |
return columns; | |
} | |
private ParseRelations( | |
tableId: string, | |
o2ms: XrmMetaOneToManyRelation[], | |
m2os: XrmMetaOneToManyRelation[], | |
m2ms: XrmMetaManyToManyRelation[], | |
): IQueryRelation[] { | |
const relations: IQueryRelation[] = []; | |
for (let i = 0; i < o2ms.length; i++) { | |
const o2m = o2ms[i]; | |
const relation: IQueryRelation = ({ | |
ParentColumn: o2m.ReferencedAttribute, | |
ParentTable: o2m.ReferencedEntity, | |
ChildColumn: o2m.ReferencingAttribute, | |
ChildTable: o2m.ReferencingEntity, | |
Id: o2m.SchemaName, | |
RelationType: QueryRelationType.OneToMany | |
} as any) as IQueryRelation; | |
relations.push(relation); | |
} | |
for (let i = 0; i < m2os.length; i++) { | |
const m2o = m2os[i]; | |
const relation: IQueryRelation = ({ | |
ChildColumn: m2o.ReferencedAttribute, | |
ChildTable: m2o.ReferencedEntity, | |
ParentColumn: m2o.ReferencingAttribute, | |
ParentTable: m2o.ReferencingEntity, | |
Id: m2o.SchemaName, | |
RelationType: QueryRelationType.ManyToOne | |
} as any) as IQueryRelation; | |
relations.push(relation); | |
} | |
for (let i = 0; i < m2ms.length; i++) { | |
const m2m = m2ms[i]; | |
let pC, cC, pT, cT, iP, iC; | |
if (m2m.Entity1LogicalName.toLowerCase() === tableId.toLowerCase()) { | |
pT = m2m.Entity1LogicalName; | |
cT = m2m.Entity2LogicalName; | |
iP = m2m.Entity1IntersectAttribute; | |
iC = m2m.Entity2IntersectAttribute; | |
} else { | |
pT = m2m.Entity2LogicalName; | |
cT = m2m.Entity1LogicalName; | |
iP = m2m.Entity2IntersectAttribute; | |
iC = m2m.Entity1IntersectAttribute; | |
} | |
// TODO: Add proper table id here | |
pC = pT + "id"; | |
cC = cT + "id"; | |
const relation: IQueryRelation = { | |
ChildColumn: cC, | |
ChildTable: cT, | |
ParentColumn: pC, | |
ParentTable: pT, | |
Id: m2m.SchemaName, | |
RelationType: QueryRelationType.ManyToMany, | |
IntermediateChildColumn: iC, | |
IntermediateParentColumn: iP, | |
IntermediateTable: m2m.IntersectEntityName | |
} as IQueryRelation; | |
relations.push(relation); | |
} | |
return relations; | |
} | |
//#region internal helpers | |
private readLabel(metaRecord: any): string { | |
try { | |
const disp = metaRecord.Label as DisplayName; | |
return disp.UserLocalizedLabel.Label; | |
} catch { | |
let label = null; | |
for (let i = 0; i < metaRecord.DisplayName.LocalizedLabels.length; i++) { | |
if (metaRecord.DisplayName.LocalizedLabels[i].LanguageCode === 1033) { | |
label = metaRecord.DisplayName.LocalizedLabels[i].Label; | |
} | |
} | |
if (label === null) { | |
if (metaRecord.DisplayName.LocalizedLabels.length > 0) { | |
label = metaRecord.DisplayName.LocalizedLabels[0].Label; | |
} else { | |
label = metaRecord.LogicalName; | |
} | |
} | |
return label; | |
} | |
} | |
private readOptionLabel(metaRecord: any): string { | |
try { | |
const disp = metaRecord.Label as DisplayName; | |
return disp.UserLocalizedLabel.Label; | |
} catch { | |
let label = null; | |
for (let i = 0; i < metaRecord.Label.LocalizedLabels.length; i++) { | |
if (metaRecord.Label.LocalizedLabels[i].LanguageCode === 1033) { | |
label = metaRecord.Label.LocalizedLabels[i].Label; | |
} | |
} | |
if (label === null) { | |
if (metaRecord.Label.LocalizedLabels.length > 0) { | |
label = metaRecord.Label.LocalizedLabels[0].Label; | |
} else { | |
label = "Option #"; | |
} | |
} | |
return label; | |
} | |
} | |
private readAttributeType(type: string): QueryColumnType { | |
switch (type) { | |
case "Lookup": { | |
return QueryColumnType.Lookup; | |
} | |
case "State": { | |
return QueryColumnType.State; | |
} | |
case "Memo": { | |
return QueryColumnType.Memo; | |
} | |
case "Boolean": { | |
return QueryColumnType.Boolean; | |
} | |
case "String": { | |
return QueryColumnType.String; | |
} | |
case "Integer": { | |
return QueryColumnType.Integer; | |
} | |
case "DateTime": { | |
return QueryColumnType.DateTime; | |
} | |
case "Status": { | |
return QueryColumnType.Status; | |
} | |
case "Uniqueidentifier": { | |
return QueryColumnType.Uniqueidentifier; | |
} | |
case "Picklist": { | |
return QueryColumnType.Picklist; | |
} | |
case "Owner": { | |
return QueryColumnType.Owner; | |
} | |
case "BigInt": { | |
return QueryColumnType.BigInt; | |
} | |
case "EntityName": { | |
return QueryColumnType.EntityName; | |
} | |
case "Virtual": { | |
return QueryColumnType.Virtual; | |
} | |
case "Decimal": { | |
return QueryColumnType.Decimal; | |
} | |
case "ManagedProperty": { | |
return QueryColumnType.ManagedProperty; | |
} | |
case "Customer": { | |
return QueryColumnType.Customer; | |
} | |
case "PartyList": { | |
return QueryColumnType.PartyList; | |
} | |
case "Double": { | |
return QueryColumnType.Double; | |
} | |
case "Money": { | |
return QueryColumnType.Money; | |
} | |
case "CalendarRules": { | |
return QueryColumnType.CalendarRules; | |
} | |
default: { | |
return QueryColumnType.None; | |
} | |
} | |
} | |
private IsLocal(): boolean { | |
return ( | |
window.location.hostname === "localhost" || | |
window.location.hostname === "127.0.01" | |
); | |
} | |
private getUrl() { | |
return this.clientUrl || window.location.hostname; | |
} | |
private getError(resp) { | |
if (resp.status === 12029) { | |
return new Error("The attempt to connect to the server failed."); | |
} | |
if (resp.status === 12007) { | |
return new Error("The server name could not be resolved."); | |
} | |
const faultXml = resp.responseXML; | |
let errorMessage = "Unknown (unable to parse the fault)"; | |
let faultstring = null; | |
let ErrorCode = null; | |
if (typeof faultXml === "object") { | |
const bodyNode = faultXml.firstChild.firstChild; | |
// Retrieve the fault node | |
for (let i = 0; i < bodyNode.childNodes.length; i++) { | |
const node = bodyNode.childNodes[i]; | |
// NOTE: This comparison does not handle the case where the XML namespace changes | |
if ("s:Fault" === node.nodeName) { | |
for (let j = 0; j < node.childNodes.length; j++) { | |
const testNode = node.childNodes[j]; | |
if ("faultstring" === testNode.nodeName) { | |
faultstring = this.getNodeText(testNode); | |
} | |
if ("detail" === testNode.nodeName) { | |
for (let k = 0; k < testNode.childNodes.length; k++) { | |
const orgServiceFault = testNode.childNodes[k]; | |
if ("OrganizationServiceFault" === orgServiceFault.nodeName) { | |
for (let l = 0; l < orgServiceFault.childNodes.length; l++) { | |
const ErrorCodeNode = orgServiceFault.childNodes[l]; | |
if ("ErrorCode" === ErrorCodeNode.nodeName) { | |
ErrorCode = this.getNodeText(ErrorCodeNode); | |
break; | |
} | |
} | |
} | |
} | |
} | |
} | |
break; | |
} | |
} | |
} | |
if (ErrorCode !== null && faultstring !== null) { | |
errorMessage = "Error Code:" + ErrorCode + " Message: " + faultstring; | |
} else { | |
if (faultstring !== null) { | |
errorMessage = faultstring; | |
} | |
} | |
return new Error(errorMessage); | |
} | |
private getRequest(entityFiltersValue: string): string { | |
return null; | |
} | |
private xmlEncode(strInput) { | |
let c: number; | |
let XmlEncode = ""; | |
if (strInput === null) { | |
return null; | |
} | |
if (strInput === "") { | |
return ""; | |
} | |
for (let cnt = 0; cnt < strInput.length; cnt++) { | |
c = strInput.charCodeAt(cnt); | |
if ( | |
(c > 96 && c < 123) || | |
(c > 64 && c < 91) || | |
c === 32 || | |
(c > 47 && c < 58) || | |
c === 46 || | |
c === 44 || | |
c === 45 || | |
c === 95 | |
) { | |
XmlEncode = XmlEncode + String.fromCharCode(c); | |
} else { | |
XmlEncode = XmlEncode + "&#" + c + ";"; | |
} | |
} | |
return XmlEncode; | |
} | |
private objectifyNode(node) { | |
// Check for null | |
if (node.attributes != null && node.attributes.length === 1) { | |
if ( | |
node.attributes.getNamedItem("i:nil") != null && | |
node.attributes.getNamedItem("i:nil").nodeValue === "true" | |
) { | |
return null; | |
} | |
} | |
// Check if it is a value | |
if (node.firstChild != null && node.firstChild.nodeType === 3) { | |
const nodeName = this.getNodeName(node); | |
switch (nodeName) { | |
// Integer Values | |
case "ActivityTypeMask": | |
case "ObjectTypeCode": | |
case "ColumnNumber": | |
case "DefaultFormValue": | |
case "MaxValue": | |
case "MinValue": | |
case "MaxLength": | |
case "Order": | |
case "Precision": | |
case "PrecisionSource": | |
case "LanguageCode": | |
return parseInt(node.firstChild.nodeValue, 10); | |
// Boolean values | |
case "AutoRouteToOwnerQueue": | |
case "CanBeChanged": | |
case "CanTriggerWorkflow": | |
case "IsActivity": | |
case "IsAIRUpdated": | |
case "IsActivityParty": | |
case "IsAvailableOffline": | |
case "IsChildEntity": | |
case "IsCustomEntity": | |
case "IsCustomOptionSet": | |
case "IsDocumentManagementEnabled": | |
case "IsEnabledForCharts": | |
case "IsGlobal": | |
case "IsImportable": | |
case "IsIntersect": | |
case "IsManaged": | |
case "IsReadingPaneEnabled": | |
case "IsValidForAdvancedFind": | |
case "CanBeSecuredForCreate": | |
case "CanBeSecuredForRead": | |
case "CanBeSecuredForUpdate": | |
case "IsCustomAttribute": | |
case "IsManaged": | |
case "IsPrimaryId": | |
case "IsPrimaryName": | |
case "IsSecured": | |
case "IsValidForCreate": | |
case "IsValidForRead": | |
case "IsValidForUpdate": | |
case "IsCustomRelationship": | |
case "CanBeBasic": | |
case "CanBeDeep": | |
case "CanBeGlobal": | |
case "CanBeLocal": | |
return node.firstChild.nodeValue === "true" ? true : false; | |
// OptionMetadata.Value and BooleanManagedProperty.Value and AttributeRequiredLevelManagedProperty.Value | |
case "Value": | |
// BooleanManagedProperty.Value | |
if ( | |
node.firstChild.nodeValue === "true" || | |
node.firstChild.nodeValue === "false" | |
) { | |
return node.firstChild.nodeValue === "true" ? true : false; | |
} | |
// AttributeRequiredLevelManagedProperty.Value | |
if ( | |
node.firstChild.nodeValue === "ApplicationRequired" || | |
node.firstChild.nodeValue === "None" || | |
node.firstChild.nodeValue === "Recommended" || | |
node.firstChild.nodeValue === "SystemRequired" | |
) { | |
return node.firstChild.nodeValue; | |
} | |
const numberValue = parseInt(node.firstChild.nodeValue, 10); | |
if (isNaN(numberValue)) { | |
// FormatName.Value | |
return node.firstChild.nodeValue; | |
} else { | |
// OptionMetadata.Value | |
return numberValue; | |
} | |
break; | |
// String values | |
default: | |
return node.firstChild.nodeValue; | |
} | |
} | |
// Check if it is a known array | |
if (this.isMetadataArray(this.getNodeName(node))) { | |
const arrayValue = []; | |
for (let i = 0; i < node.childNodes.length; i++) { | |
let objectTypeName; | |
if ( | |
node.childNodes[i].attributes != null && | |
node.childNodes[i].attributes.getNamedItem("i:type") != null | |
) { | |
objectTypeName = node.childNodes[i].attributes | |
.getNamedItem("i:type") | |
.nodeValue.split(":")[1]; | |
} else { | |
objectTypeName = this.getNodeName(node.childNodes[i]); | |
} | |
const b = this.objectifyNode(node.childNodes[i]); | |
b._type = objectTypeName; | |
arrayValue.push(b); | |
} | |
return arrayValue; | |
} | |
// Null entity description labels are returned as <label/> - not using i:nil = true; | |
if (node.childNodes.length === 0) { | |
return null; | |
} | |
// Otherwise return an object | |
const c: any = {}; | |
if (node.attributes.getNamedItem("i:type") != null) { | |
c._type = node.attributes.getNamedItem("i:type").nodeValue.split(":")[1]; | |
} | |
for (let i = 0; i < node.childNodes.length; i++) { | |
if (node.childNodes[i].nodeType === 3) { | |
c[this.getNodeName(node.childNodes[i])] = node.childNodes[i].nodeValue; | |
} else { | |
c[this.getNodeName(node.childNodes[i])] = this.objectifyNode( | |
node.childNodes[i] | |
); | |
} | |
} | |
return c; | |
} | |
private isMetadataArray(elementName) { | |
for (let i = 0; i < this._arrayElements.length; i++) { | |
if (elementName === this._arrayElements[i]) { | |
return true; | |
} | |
} | |
return false; | |
} | |
private selectNodes(node, XPathExpression): any[] { | |
if (typeof node.selectNodes != null) { | |
return node.selectNodes(XPathExpression); | |
} else { | |
const output = []; | |
const XPathResults = node.evaluate( | |
XPathExpression, | |
node, | |
this.NSResolver, | |
XPathResult.ANY_TYPE, | |
null | |
); | |
let result = XPathResults.iterateNext(); | |
while (result) { | |
output.push(result); | |
result = XPathResults.iterateNext(); | |
} | |
return output; | |
} | |
return []; | |
} | |
private selectSingleNodeText(node, xpathExpr) { | |
const x = this.selectSingleNode(node, xpathExpr); | |
if (this.isNodeNull(x)) { | |
return null; | |
} | |
if (typeof x.text != null) { | |
return x.text; | |
} else { | |
return x.textContent; | |
} | |
} | |
private selectSingleNode(node, xpathExpr) { | |
if (typeof node.selectSingleNode != null) { | |
return node.selectSingleNode(xpathExpr); | |
} else { | |
const xpe = new XPathEvaluator(); | |
const xPathNode = xpe.evaluate( | |
xpathExpr, | |
node, | |
this.NSResolver, | |
XPathResult.FIRST_ORDERED_NODE_TYPE, | |
null | |
); | |
return xPathNode != null ? xPathNode.singleNodeValue : null; | |
} | |
} | |
private getNodeText(node) { | |
if (typeof node.text !== "undefined") { | |
return node.text; | |
} else { | |
return node.textContent; | |
} | |
} | |
private isNodeNull(node) { | |
if (node == null) { | |
return true; | |
} | |
if ( | |
node.attributes.getNamedItem("i:nil") != null && | |
node.attributes.getNamedItem("i:nil").value === "true" | |
) { | |
return true; | |
} | |
return false; | |
} | |
private getNodeName(node: any) { | |
if (typeof node.baseName != null) { | |
return node.baseName; | |
} else { | |
return node.localName; | |
} | |
} | |
private setSelectionNamespaces(doc) { | |
const nameSpace = [ | |
'xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"', | |
'xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts"', | |
'xmlns:i="http://www.w3.org/2001/XMLSchema-instance"', | |
'xmlns:b="http://schemas.datacontract.org/2004/07/System.Collections.Generic"', | |
'xmlns:c="http://schemas.microsoft.com/xrm/2011/Metadata"' | |
]; | |
doc.setProperty("SelectionNamespaces", nameSpace.join(" ")); | |
} | |
private NSResolver(prefix) { | |
const nameSpace = { | |
s: "http://schemas.xmlsoap.org/soap/envelope/", | |
a: "http://schemas.microsoft.com/xrm/2011/Contracts", | |
i: "http://www.w3.org/2001/XMLSchema-instance", | |
b: "http://schemas.datacontract.org/2004/07/System.Collections.Generic", | |
c: "http://schemas.microsoft.com/xrm/2011/Metadata" | |
}; | |
return nameSpace[prefix] || null; | |
} | |
private evaluateEntityFilters(xrmFilter: XrmEntityFilter): string { | |
const entityFilterArray = []; | |
if ((1 & xrmFilter) === 1) { | |
entityFilterArray.push("Entity"); | |
} | |
if ((2 & xrmFilter) === 2) { | |
entityFilterArray.push("Attributes"); | |
} | |
if ((4 & xrmFilter) === 4) { | |
entityFilterArray.push("Privileges"); | |
} | |
if ((8 & xrmFilter) === 8) { | |
entityFilterArray.push("Relationships"); | |
} | |
return entityFilterArray.join(" "); | |
} | |
//#endregion | |
private RetrieveAllEntities(successCallBack, errorCallBack) { | |
const _this = this; | |
const entityFiltersValue = this.evaluateEntityFilters(1); | |
const request = [ | |
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">', | |
'<soapenv:Header><a:SdkClientVersion xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts">7.0</a:SdkClientVersion></soapenv:Header>', | |
"<soapenv:Body>", | |
'<Execute xmlns="http://schemas.microsoft.com/xrm/2011/Contracts/Services" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">', | |
'<request i:type="a:RetrieveAllEntitiesRequest" xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts">', | |
'<a:Parameters xmlns:b="http://schemas.datacontract.org/2004/07/System.Collections.Generic">', | |
"<a:KeyValuePairOfstringanyType>", | |
"<b:key>EntityFilters</b:key>", | |
'<b:value i:type="c:EntityFilters" xmlns:c="http://schemas.microsoft.com/xrm/2011/Metadata">' + | |
this.xmlEncode(entityFiltersValue) + | |
"</b:value>", | |
"</a:KeyValuePairOfstringanyType>", | |
"<a:KeyValuePairOfstringanyType>", | |
"<b:key>RetrieveAsIfPublished</b:key>", | |
'<b:value i:type="c:boolean" xmlns:c="http://www.w3.org/2001/XMLSchema">' + | |
this.xmlEncode("true") + | |
"</b:value>", | |
"</a:KeyValuePairOfstringanyType>", | |
"</a:Parameters>", | |
'<a:RequestId i:nil="true" />', | |
"<a:RequestName>RetrieveAllEntities</a:RequestName>", | |
"</request>", | |
"</Execute>", | |
"</soapenv:Body>", | |
"</soapenv:Envelope>" | |
].join(""); | |
const req = new XMLHttpRequest(); | |
req.open( | |
"POST", | |
this.getUrl() + "/XRMServices/2011/Organization.svc/web", | |
true | |
); | |
// try { | |
// req.responseType = "msxml-document"; | |
// } catch (e) {} | |
req.setRequestHeader("Accept", "application/xml, text/xml, */*"); | |
req.setRequestHeader("Content-Type", "text/xml; charset=utf-8"); | |
req.setRequestHeader( | |
"SOAPAction", | |
"http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute" | |
); | |
req.onreadystatechange = function() { | |
if (req.readyState === 4 /* complete */) { | |
req.onreadystatechange = null; // Addresses potential memory leak issue with IE | |
if (req.status === 200) { | |
// Success | |
const doc = req.responseXML; | |
try { | |
_this.setSelectionNamespaces(doc); | |
} catch (e) {} | |
const entityMetadataNodes = _this.selectNodes( | |
doc, | |
"//c:EntityMetadata" | |
); | |
const entityMetadataCollection: XrmMetaEntity[] = []; | |
for (let i = 0; i < entityMetadataNodes.length; i++) { | |
const a = _this.objectifyNode(entityMetadataNodes[i]); | |
a._type = "EntityMetadata"; | |
entityMetadataCollection.push(a); | |
} | |
successCallBack(entityMetadataCollection); | |
} else { | |
errorCallBack(_this.getError(req)); | |
} | |
} | |
}; | |
req.send(request); | |
} | |
private RetrieveAttributes(LogicalName, successCallBack, errorCallBack) { | |
let MetadataId = null; | |
const _this = this; | |
if (LogicalName == null) { | |
throw new Error( | |
"SDK.Metadata.RetrieveEntity requires either the LogicalName or MetadataId parameter not be null." | |
); | |
} | |
if (LogicalName != null) { | |
if (typeof LogicalName !== "string") { | |
throw new Error( | |
"SDK.Metadata.RetrieveEntity LogicalName must be a string value." | |
); | |
} | |
MetadataId = "00000000-0000-0000-0000-000000000000"; | |
} | |
if (MetadataId != null && LogicalName == null) { | |
if (typeof MetadataId !== "string") { | |
throw new Error( | |
"SDK.Metadata.RetrieveEntity MetadataId must be a string value." | |
); | |
} | |
} | |
if (typeof successCallBack !== "function") { | |
throw new Error( | |
"SDK.Metadata.RetrieveEntity successCallBack must be a function." | |
); | |
} | |
if (typeof errorCallBack !== "function") { | |
throw new Error( | |
"SDK.Metadata.RetrieveEntity errorCallBack must be a function." | |
); | |
} | |
const entityFiltersValue = this.evaluateEntityFilters(2); | |
let entityLogicalNameValueNode = ""; | |
if (LogicalName == null) { | |
entityLogicalNameValueNode = '<b:value i:nil="true" />'; | |
} else { | |
entityLogicalNameValueNode = | |
'<b:value i:type="c:string" xmlns:c="http://www.w3.org/2001/XMLSchema">' + | |
this.xmlEncode(LogicalName.toLowerCase()) + | |
"</b:value>"; | |
} | |
const request = [ | |
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">', | |
// Allows retrieval if ImageAttributeMetadata objects | |
'<soapenv:Header><a:SdkClientVersion xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts">6.0</a:SdkClientVersion></soapenv:Header>', | |
"<soapenv:Body>", | |
'<Execute xmlns="http://schemas.microsoft.com/xrm/2011/Contracts/Services" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">', | |
'<request i:type="a:RetrieveEntityRequest" xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts">', | |
'<a:Parameters xmlns:b="http://schemas.datacontract.org/2004/07/System.Collections.Generic">', | |
"<a:KeyValuePairOfstringanyType>", | |
"<b:key>EntityFilters</b:key>", | |
'<b:value i:type="c:EntityFilters" xmlns:c="http://schemas.microsoft.com/xrm/2011/Metadata">' + | |
this.xmlEncode(entityFiltersValue) + | |
"</b:value>", | |
"</a:KeyValuePairOfstringanyType>", | |
"<a:KeyValuePairOfstringanyType>", | |
"<b:key>MetadataId</b:key>", | |
'<b:value i:type="ser:guid" xmlns:ser="http://schemas.microsoft.com/2003/10/Serialization/">' + | |
this.xmlEncode(MetadataId) + | |
"</b:value>", | |
"</a:KeyValuePairOfstringanyType>", | |
"<a:KeyValuePairOfstringanyType>", | |
"<b:key>RetrieveAsIfPublished</b:key>", | |
'<b:value i:type="c:boolean" xmlns:c="http://www.w3.org/2001/XMLSchema">' + | |
this.xmlEncode("true") + | |
"</b:value>", | |
"</a:KeyValuePairOfstringanyType>", | |
"<a:KeyValuePairOfstringanyType>", | |
"<b:key>LogicalName</b:key>", | |
entityLogicalNameValueNode, | |
"</a:KeyValuePairOfstringanyType>", | |
"</a:Parameters>", | |
'<a:RequestId i:nil="true" />', | |
"<a:RequestName>RetrieveEntity</a:RequestName>", | |
"</request>", | |
"</Execute>", | |
"</soapenv:Body>", | |
"</soapenv:Envelope>" | |
].join(""); | |
const req = new XMLHttpRequest(); | |
req.open( | |
"POST", | |
this.getUrl() + "/XRMServices/2011/Organization.svc/web", | |
true | |
); | |
// try { | |
// req.responseType = "msxml-document"; | |
// } catch (e) {} | |
req.setRequestHeader("Accept", "application/xml, text/xml, */*"); | |
req.setRequestHeader("Content-Type", "text/xml; charset=utf-8"); | |
req.setRequestHeader( | |
"SOAPAction", | |
"http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute" | |
); | |
req.onreadystatechange = function() { | |
if (req.readyState === 4 /* complete */) { | |
req.onreadystatechange = null; // Addresses potential memory leak issue with IE | |
if (req.status === 200) { | |
const doc = req.responseXML; | |
try { | |
_this.setSelectionNamespaces(doc); | |
} catch (e) {} | |
const a: XrmMetaEntity = _this.objectifyNode( | |
_this.selectSingleNode(doc, "//b:value") | |
); | |
a._type = "EntityMetadata"; | |
successCallBack(a.Attributes); | |
} else { | |
// Failure | |
errorCallBack(_this.getError(req)); | |
} | |
} | |
}; | |
req.send(request); | |
} | |
private RetrieveRelations( | |
LogicalName, | |
MetadataId, | |
successCallBack, | |
errorCallBack | |
) { | |
const _this = this; | |
if (LogicalName == null && MetadataId == null) { | |
throw new Error( | |
"SDK.Metadata.RetrieveEntity requires either the LogicalName or MetadataId parameter not be null." | |
); | |
} | |
if (LogicalName != null) { | |
if (typeof LogicalName !== "string") { | |
throw new Error( | |
"SDK.Metadata.RetrieveEntity LogicalName must be a string value." | |
); | |
} | |
MetadataId = "00000000-0000-0000-0000-000000000000"; | |
} | |
if (MetadataId != null && LogicalName == null) { | |
if (typeof MetadataId !== "string") { | |
throw new Error( | |
"SDK.Metadata.RetrieveEntity MetadataId must be a string value." | |
); | |
} | |
} | |
if (typeof successCallBack !== "function") { | |
throw new Error( | |
"SDK.Metadata.RetrieveEntity successCallBack must be a function." | |
); | |
} | |
if (typeof errorCallBack !== "function") { | |
throw new Error( | |
"SDK.Metadata.RetrieveEntity errorCallBack must be a function." | |
); | |
} | |
// Attributes and entities | |
const entityFiltersValue = this.evaluateEntityFilters(8); | |
let entityLogicalNameValueNode = ""; | |
if (LogicalName == null) { | |
entityLogicalNameValueNode = '<b:value i:nil="true" />'; | |
} else { | |
entityLogicalNameValueNode = | |
'<b:value i:type="c:string" xmlns:c="http://www.w3.org/2001/XMLSchema">' + | |
this.xmlEncode(LogicalName.toLowerCase()) + | |
"</b:value>"; | |
} | |
const request = [ | |
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">', | |
// Allows retrieval if ImageAttributeMetadata objects | |
'<soapenv:Header><a:SdkClientVersion xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts">6.0</a:SdkClientVersion></soapenv:Header>', | |
"<soapenv:Body>", | |
'<Execute xmlns="http://schemas.microsoft.com/xrm/2011/Contracts/Services" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">', | |
'<request i:type="a:RetrieveEntityRequest" xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts">', | |
'<a:Parameters xmlns:b="http://schemas.datacontract.org/2004/07/System.Collections.Generic">', | |
"<a:KeyValuePairOfstringanyType>", | |
"<b:key>EntityFilters</b:key>", | |
'<b:value i:type="c:EntityFilters" xmlns:c="http://schemas.microsoft.com/xrm/2011/Metadata">' + | |
this.xmlEncode(entityFiltersValue) + | |
"</b:value>", | |
"</a:KeyValuePairOfstringanyType>", | |
"<a:KeyValuePairOfstringanyType>", | |
"<b:key>MetadataId</b:key>", | |
'<b:value i:type="ser:guid" xmlns:ser="http://schemas.microsoft.com/2003/10/Serialization/">' + | |
this.xmlEncode(MetadataId) + | |
"</b:value>", | |
"</a:KeyValuePairOfstringanyType>", | |
"<a:KeyValuePairOfstringanyType>", | |
"<b:key>RetrieveAsIfPublished</b:key>", | |
'<b:value i:type="c:boolean" xmlns:c="http://www.w3.org/2001/XMLSchema">' + | |
this.xmlEncode("true") + | |
"</b:value>", | |
"</a:KeyValuePairOfstringanyType>", | |
"<a:KeyValuePairOfstringanyType>", | |
"<b:key>LogicalName</b:key>", | |
entityLogicalNameValueNode, | |
"</a:KeyValuePairOfstringanyType>", | |
"</a:Parameters>", | |
'<a:RequestId i:nil="true" />', | |
"<a:RequestName>RetrieveEntity</a:RequestName>", | |
"</request>", | |
"</Execute>", | |
"</soapenv:Body>", | |
"</soapenv:Envelope>" | |
].join(""); | |
const req = new XMLHttpRequest(); | |
req.open( | |
"POST", | |
this.getUrl() + "/XRMServices/2011/Organization.svc/web", | |
true | |
); | |
// try { | |
// req.responseType = "msxml-document"; | |
// } catch (e) {} | |
req.setRequestHeader("Accept", "application/xml, text/xml, */*"); | |
req.setRequestHeader("Content-Type", "text/xml; charset=utf-8"); | |
req.setRequestHeader( | |
"SOAPAction", | |
"http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute" | |
); | |
req.onreadystatechange = function() { | |
if (req.readyState === 4 /* complete */) { | |
req.onreadystatechange = null; // Addresses potential memory leak issue with IE | |
if (req.status === 200) { | |
const doc = req.responseXML; | |
try { | |
_this.setSelectionNamespaces(doc); | |
} catch (e) {} | |
const a: XrmMetaEntity = _this.objectifyNode( | |
_this.selectSingleNode(doc, "//b:value") | |
); | |
a._type = "EntityMetadata"; | |
successCallBack(a); | |
} else { | |
// Failure | |
errorCallBack(_this.getError(req)); | |
} | |
} | |
}; | |
req.send(request); | |
} | |
private RetrieveAttribute( | |
EntityLogicalName, | |
LogicalName, | |
MetadataId, | |
successCallBack, | |
errorCallBack | |
) { | |
const _this = this; | |
if ( | |
EntityLogicalName == null && | |
LogicalName == null && | |
MetadataId == null | |
) { | |
throw new Error( | |
"SDK.Metadata.RetrieveAttribute requires either the EntityLogicalName and LogicalName parameters or the MetadataId parameter not be null." | |
); | |
} | |
if ( | |
MetadataId != null && | |
EntityLogicalName == null && | |
LogicalName == null | |
) { | |
if (typeof MetadataId !== "string") { | |
throw new Error( | |
"SDK.Metadata.RetrieveEntity MetadataId must be a string value." | |
); | |
} | |
} else { | |
MetadataId = "00000000-0000-0000-0000-000000000000"; | |
} | |
if (EntityLogicalName != null) { | |
if (typeof EntityLogicalName !== "string") { | |
{ | |
throw new Error( | |
"SDK.Metadata.RetrieveAttribute EntityLogicalName must be a string value." | |
); | |
} | |
} | |
} | |
if (LogicalName != null) { | |
if (typeof LogicalName !== "string") { | |
{ | |
throw new Error( | |
"SDK.Metadata.RetrieveAttribute LogicalName must be a string value." | |
); | |
} | |
} | |
} | |
if (typeof successCallBack !== "function") { | |
throw new Error( | |
"SDK.Metadata.RetrieveAttribute successCallBack must be a function." | |
); | |
} | |
if (typeof errorCallBack !== "function") { | |
throw new Error( | |
"SDK.Metadata.RetrieveAttribute errorCallBack must be a function." | |
); | |
} | |
let entityLogicalNameValueNode; | |
if (EntityLogicalName == null) { | |
entityLogicalNameValueNode = '<b:value i:nil="true" />'; | |
} else { | |
entityLogicalNameValueNode = | |
'<b:value i:type="c:string" xmlns:c="http://www.w3.org/2001/XMLSchema">' + | |
_this.xmlEncode(EntityLogicalName.toLowerCase()) + | |
"</b:value>"; | |
} | |
let logicalNameValueNode; | |
if (LogicalName == null) { | |
logicalNameValueNode = '<b:value i:nil="true" />'; | |
} else { | |
logicalNameValueNode = | |
'<b:value i:type="c:string" xmlns:c="http://www.w3.org/2001/XMLSchema">' + | |
_this.xmlEncode(LogicalName.toLowerCase()) + | |
"</b:value>"; | |
} | |
const request = [ | |
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">', | |
// Allows retrieval if ImageAttributeMetadata objects | |
'<soapenv:Header><a:SdkClientVersion xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts">6.0</a:SdkClientVersion></soapenv:Header>', | |
"<soapenv:Body>", | |
'<Execute xmlns="http://schemas.microsoft.com/xrm/2011/Contracts/Services" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">', | |
'<request i:type="a:RetrieveAttributeRequest" xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts">', | |
'<a:Parameters xmlns:b="http://schemas.datacontract.org/2004/07/System.Collections.Generic">', | |
"<a:KeyValuePairOfstringanyType>", | |
"<b:key>EntityLogicalName</b:key>", | |
entityLogicalNameValueNode, | |
"</a:KeyValuePairOfstringanyType>", | |
"<a:KeyValuePairOfstringanyType>", | |
"<b:key>MetadataId</b:key>", | |
'<b:value i:type="ser:guid" xmlns:ser="http://schemas.microsoft.com/2003/10/Serialization/">' + | |
_this.xmlEncode(MetadataId) + | |
"</b:value>", | |
"</a:KeyValuePairOfstringanyType>", | |
"<a:KeyValuePairOfstringanyType>", | |
"<b:key>RetrieveAsIfPublished</b:key>", | |
'<b:value i:type="c:boolean" xmlns:c="http://www.w3.org/2001/XMLSchema">' + | |
_this.xmlEncode("true") + | |
"</b:value>", | |
"</a:KeyValuePairOfstringanyType>", | |
"<a:KeyValuePairOfstringanyType>", | |
"<b:key>LogicalName</b:key>", | |
logicalNameValueNode, | |
"</a:KeyValuePairOfstringanyType>", | |
"</a:Parameters>", | |
'<a:RequestId i:nil="true" />', | |
"<a:RequestName>RetrieveAttribute</a:RequestName>", | |
"</request>", | |
"</Execute>", | |
"</soapenv:Body>", | |
"</soapenv:Envelope>" | |
].join(""); | |
const req = new XMLHttpRequest(); | |
req.open( | |
"POST", | |
_this.getUrl() + "/XRMServices/2011/Organization.svc/web", | |
true | |
); | |
// try { | |
// req.responseType = "msxml-document"; | |
// } catch (e) {} | |
req.setRequestHeader("Accept", "application/xml, text/xml, */*"); | |
req.setRequestHeader("Content-Type", "text/xml; charset=utf-8"); | |
req.setRequestHeader( | |
"SOAPAction", | |
"http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute" | |
); | |
req.onreadystatechange = function() { | |
if (req.readyState === 4 /* complete */) { | |
req.onreadystatechange = null; // Addresses potential memory leak issue with IE | |
if (req.status === 200) { | |
// Success | |
const doc = req.responseXML; | |
try { | |
_this.setSelectionNamespaces(doc); | |
} catch (e) {} | |
const a = _this.objectifyNode( | |
_this.selectSingleNode(doc, "//b:value") | |
); | |
successCallBack(a); | |
} else { | |
// Failure | |
errorCallBack(_this.getError(req)); | |
} | |
} | |
}; | |
req.send(request); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment