<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.5.0/ui-bootstrap-tpls.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<script src="example.js"></script>
</head>
<body ng-app="plunker">
<script type="text/ng-template" id="customTemplate.html">
<a>
<div>{{match.label.code}}</div>
<span ng-bind-html="match.label.display | uibTypeaheadHighlight:query"></span>
</a>
</script>
<div class="container-fluid" style="margin-bottom:5rem;">
<h2>Using the FHIR $translate operation</h2>
<img style="float:right" src="https://ontoserver.csiro.au/docs/4.1/images/network-cloud-internet-small.png">
<p>Example demonstrating FHIR's <tt><a href="http://hl7.org/fhir/conceptmap-operations.html#translate">ConceptMap/$translate</a></tt>.
</p>
<p>
Select a <i>Map</i> from the drop-down, then search for a <i>Source</i> code to translate.
</p>
</div>
<div ng-controller="Main as main">
<!-- ENDPOINT -->
<div class="container-fluid">
<label class="label label-default" for="endpoint">Endpoint</label>
<input class="form-control" id="endpoint" type="text" ng-model="endpoint" ng-init="endpoint='https://r4.ontoserver.csiro.au/fhir'" placeholder="FHIR Server base URL">
</div>
<!-- ConceptMap -->
<div class="container-fluid">
<label class="label label-default" for="conceptmap">Map</label>
<select class="form-control" id="conceptmap" ng-model="selected" ng-options="item as item.name for item in conceptmaps(endpoint)">
</select>
<pre ng-show="selected.id">{{selected.description}}
From: {{selected.sourceUri}}
To: {{selected.targetUri}}</pre>
</div>
<!-- SOURCE CODE -->
<div class="container-fluid" ng-controller="TypeaheadCtrl">
<label class="label label-default" for="source">Source : {{$parent.selected.sourceName}}</label>
<input id="source" class="form-control" placeholder="Find codes..." type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" ng-model="result" uib-typeahead="suggestion for suggestion in concepts($viewValue)"
typeahead-loading="loading" typeahead-template-url="customTemplate.html" typeahead-input-formatter="result.display" />
<pre>{{loading && 'Searching...' || ''}} {{result | json}}</pre>
<p><a href="{{endpoint}}/ConceptMap/$translate?url={{selected.url}}&target={{selected.targetUri}}&system={{result.system}}&code={{result.code}}" target="_blank"><tt ng-if="result.code">[base]/ConceptMap/$translate?url={{selected.url}}&target={{selected.targetUri}}&system={{result.system}}&code={{result.code}}</tt></a></p>
<!-- TRANSLATION -->
<label class="label label-default" for="translation">Translation</label>
<pre ng-show="result && translate(result.code, result.system).result" id="translation">{{result && translation | json}}</pre>
<!-- ERRORS -->
<table class="table table-sm" ng-if="error">
<tr ng-repeat="item in error.issue">
<td>{{item.code}}</td><td>{{item.diagnostics}}</td>
</tr>
</table>
</div>
</div>
<nav style="position:fixed;bottom:0;width:100%;background-color:#eee;" class="navbar navbar-light bg-light">
<div class="small">
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons Licence" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a>
<br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">This $validate-code exemplar</span> by <span xmlns:cc="http://creativecommons.org/ns#" property="cc:attributionName">CSIRO</span> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.
</div>
</nav>
</body>
</html>
angular
.module('plunker', ['ui.bootstrap'])
.controller('Main', ['$scope', '$http', function($scope, $http) {
// console.log('EP', $scope.endpoint);
function flattenP(params) {
var m = {};
params.forEach(function(p) {
var v;
if (p.part) {
v = flattenP(p.part);
} else {
v = p.valueCode || p.valueCoding || p.valueString || p.valueBoolean;
}
if (m[p.name]) {
if (!Array.isArray(m[p.name])) {
m[p.name] = [m[p.name]];
}
m[p.name].push(v);
} else {
m[p.name] = v;
}
});
return m;
}
$scope.selected = {}
$scope.sourceName = undefined;
var x = true,
maps = [];
$scope.conceptmaps = function(endpoint) {
$scope.error = undefined;
// console.log('EP', endpoint);
if (x !== endpoint) {
x = endpoint;
maps.splice(0, maps.length); // delete existing list
$scope.selected = undefined;
// return
$http({
method: 'GET',
url: endpoint + '/ConceptMap/_search',
params: {
'_elements': 'id,name,url,source,target,description',
'_count': 200,
'_format': 'json'
},
responseType: 'json'
})
.then(function(response) {
response.data.entry
.map(function(e) {
return e.resource;
})
.filter(function(e) {
return !(false && e.sourceUri || '').startsWith('urn:') &&
(e.targetUri || '').startsWith('http://snomed.info/sct') && e.targetUri;
})
.forEach(e => maps.push(e));
$scope.selected = maps[0] || {};
// $scope.sourceName = $scope.resName('ValueSet',$scope.selected.sourceUri);
return maps;
})
.then(function (maps) {
maps.forEach(m => {
sourceName = $scope.resName('ValueSet', m.sourceUri)
.then(name => m.sourceName = name);
});
});
}
return maps;
};
var cache = {};
$scope.translate = function(code, system) {
console.log('TRANSLATE', code, system);
if (code && system) {
var key =
$scope.selected.url + '|' + code + '|' + system + '|' + $scope.selected.targetUri;
// console.log(code, system);
return cache[key] || $http({
method: 'GET',
url: $scope.endpoint + '/ConceptMap/$translate',
params: {
'url': $scope.selected.url,
'code': code,
'system': system,
'target': $scope.selected.targetUri,
'_format': 'json'
},
responseType: 'json'
})
.then(function(response) {
var params = flattenP(response.data.parameter);
cache[key] = params;
console.log('P', params);
$scope.translation = params;
return params.result;
}, function (response) {
console.log('ERROR', response);
cache[key] = 'ERROR';
$scope.translation = response.data;
});
}
};
$scope.resName = function(resourceType, system, version) {
// selected.sourceUri
console.log(resourceType, system);
if (system) {
return $http({
method: 'GET',
url: $scope.endpoint + '/' + resourceType,
params: {
'url': system,
'version': version,
'_format': 'json'
},
responseType: 'json'
})
.then(function (response) {
var name = system;
if (response.data.total && response.data.entry) {
response.data.entry.forEach(e => {name = e.resource.name;})
}
console.log('Name', name);
return name;
}, function (response) {
console.log('ERROR', response);
return system;
})
}
};
}])
.controller('TypeaheadCtrl', ['$scope', '$http', function($scope, $http) {
$scope.concepts = function(term, endpoint) {
// console.log(term);
$scope.error = undefined;
var valueSet = $scope.selected.sourceUri;
endpoint = $scope.endpoint || 'https://tx.ontoserver.csiro.au/fhir';
return $http({
method: 'GET',
url: endpoint + '/ValueSet/$expand',
params: {
'url': valueSet,
'filter': term,
'count': 15,
'_format': 'json'
},
responseType: 'json'
})
.then(function(response) {
// console.log(response.data.expansion);
return response.data.expansion.contains || [{
display: term
}];
}, function (response) {
console.log('ERROR', response.status, JSON.stringify(response.data));
var res = response.data;
if (res && res.resourceType === 'OperationOutcome') {
$scope.error = res;
} else {
$scope.error = JSON.stringify(response.data);
}
});
};
}]);
# An example for FHIR ConceptMap/$translate
This is a simple example of how to connect up UI Bootstrap's Typeahead control to the [ConceptMap/$translate](http://hl7.org/fhir/STU3/conceptmap-operations.html#translate) operation.
This provides a simple way to find and select a code in one CodeSystem / ValueSet, and then use a ConceptMap to translate it.
Uses a public sandbox [endpoint](https://stu3.ontoserver.csiro.au/fhir/) of [Ontoserver](https://ontoserver.csiro.au/).