<\/span>)/,
"$1");
templateCache.put(docSummary, v);
}]);
This code is placed in the existing summonApp module as a run block, which is executed after the module has been initialized. The example shows how AngularJS implements dependency injection: access to the AngularJS templateCache[15] service is provided by listing the name $templateCache inside an array whose last element is the function into which the service is passed as an argument.[16]
Technique 2: Direct DOM Manipulation
In our second example, we wish to record when a user clicks on any of the links Summon 2.0 provides that lead to a discovered item. Summon 2.0 provides a fair number of such links, some of which are marked in red in the screenshot shown below:
Figure 3.
We needed to identify those links reliably and add event handlers that are invoked when they are clicked. This required special casing for each location where such links occur. Below we show the directive that handles the primary links occurring in the main and the preview panel.
function recordClicksOnPrimaryLinks() {
return {
link: function (scope, iElement, iAttrs, controller, transcludeFn) {
iElement.find("h1.customPrimaryLinkContainer").on("click", function (event) {
// find document id
var doc = scope.document || (scope.preview && scope.preview.doc);
var id = doc && doc.id;
if (id !== undefined)
recordClick(id);
});
}
}
}
angular.module('summonApp.directives')
.directive("documentSummary", recordClicksOnPrimaryLinks)
.directive("preview", recordClicksOnPrimaryLinks);
We use the same code in both cases and redefine the document-summary and the preview directives. In this case, the original, template-based document-summary and preview directives have already added the
element when the redefined directive’s postLink function is called, so an onclick event handler can be attached directly to that element. In the event handler, we retrieve the id of the document in question from the scope. If used inside the document summary, this id will be contained in the property document; for the preview pane, it will be in the preview.doc property. We found those by inspecting the scope object using the Chrome debugger. We used the same technique for the other links displayed on the results page.
The technique of using direct DOM manipulation inside a postLink() method comes with a big caveat, which is that the elements being manipulated must exist when the postLink() method is called. To see that this is not always true, consider the following failed attempt at implementing the COinS-hiding hack discussed earlier using direct DOM manipulation in a redefined document-summary definition:
angular.module('summonApp.directives').directive("documentSummary",
function() {
return {
link: function (scope, iElement, iAttrs, controller, transcludeFn) {
// does not work: iElement’s DOM is incomplete
var $invisible = $("").css("display", "none");
iElement.find(".Z3988").wrap($invisible);
}
}
});
Even though the original, template-expanding document-summary directive had already been applied, the processing of its template was not yet complete. Specifically, an ng-repeat clause ("
+" {{resource.name}}:"
+" "
+"",
link: function (scope, iElement, iAttrs, controller, transcludeFn) {
scope.$watch("type", function (type) {
switch (type) {
case "rta":
case "fulltext":
var doc = scope.avDoc;
if ('isbn' in doc)
$http.jsonp("http://libx.lib.vt.edu:4000/isbn/"
+ doc.isbn + "?callback=JSON_CALLBACK")
.success(function (data) {
scope.resources = data.resources;
});
}
break;
}
});
}
}
}])
This availability-additional-info directive uses an HTML template and AngularJS directives ($http) in the same way as if we had full control of the Summon 2.0 front-end. It contacts a JSON-P[18] service we provide and inserts the resources property of the returned JSON object into the scope so that the corresponding display can be rendered[19]. This directive is added to the availability directive’s template using the template cache technique described earlier:
var availability = "/assets/availability.html";
var v = templateCache.get(availability);
v = v.replace(/(<\/div>)\n$/, "$1");
templateCache.put(availability, v);
Since this directive will be used inside the availability directive, it must be adapted in two ways: the document whose ISBN should be used must be extracted from the avDoc property of the surrounding scope. In addition, we wish to display this message only if the type of the resource is fulltext. Since the type property is computed inside the postLink function of the surrounding availability directive, we perform this action inside a $watch callback once type becomes available.
Risks
By now the curious reader may be wondering: What could possibly go wrong with writing code that directly interfaces with vendor code as we have presented? A moderate number of things, it turns out.
First, hosting an external script requires that the server hosting the script is at least as available as the Summon service. Since its JavaScript is executed synchronously (and must be for our techniques to work!), an unavailable server will result in lengthy delays since the client will time out before executing the remaining JavaScript in the Summon page.
Second, any syntax error in the script, or any runtime error thrown in a config or run block that was added to a module[20], will prevent the initialization of the module, causing the entire UI to fail and the user to see a white page. As a precaution, we recommend wrapping such critical blocks in try/catch clauses to prevent errors from propagating. To avoid syntax errors, we are using a technique where experimental versions of our scripts are seen only by debugging users, which we identify using a cookie whose value determines the version of the script served (via an Apache mod_rewrite[21] directive). A special value empty instructs Apache to serve an empty script, turning off all modifications.
Third, we have encountered rare, but extremely difficult to debug problems in two instances. When we initially deployed Summon 2.0, librarians noticed that the legacy, GET-based Summon 1.0 search boxes had ceased to work. Summon 2.0 implements compatibility with these search forms by examining the URL in its window.location variable and executing a search if necessary. Instead of using the recommended $location[22] service, Summon’s implementors directly accessed window.location. In doing so, they introduced a subtle dependency on when the $location service was first instantiated[23]. When we injected $location into an entirely unrelated run block, we subsequently caused the page not to execute the search. The second instance concerned when a Summon directive’s template uses both the reload: true option (which says that this directive’s template should replace the element to which it is applied) and if it contains an ng-if directive that evaluates to true (see Issue #8748) [24]. In this case, stacked directives are not executed, causing those techniques that rely upon redefinition of directives not to work.
Summary
We have presented four techniques we used to extend an existing AngularJS application (Summon 2.0) that was not originally designed for such extensions. Based on limited reverse engineering of the application’s structure, in particular its use of template-expanding directives, we were able to devise a number of ways in which the behavior of this application can be changed and improved in a seamless manner.
Like all code that interacts with web pages whose implementation is controlled by another party, our code is subject to potential failure if their implementation changes. However, any such failure is likely to be local, affecting only features that depend on a particular template or service. Because our techniques rely only on AngularJS features whose behavior is documented, they are likely to work in future versions of AngularJS. Our “hacks” are fully integrated into AngularJS’s processing, specifically its dirty-checking process that provides the plumbing that keeps model state and the rendered view in sync. As a result, flickering effects are minimized and there is no potential for timing dependencies or race conditions.
Related Work
The idea to mash enhancing content or customizations into vendor-provided interfaces dates back several years (Schmidt, 2013). For instance, many libraries use tools from LibraryThing to enrich bibliographic records displayed in their OPAC with information that ranges from tables of contents to suggestions of reading based on the item the user is currently viewing (LibraryThing). Syndetics, a company later acquired by ProQuest, formed a business around including book covers and other information, now offered as Proquest’s Syndetics Solutions Enrichment Elements (Proquest). Librarians have also used this technique: for instance, Oldham’s work demonstrates how to add user interface improvements to the University of Guelph’s instance of Primo, a discovery product that competes with Summon (Oldham, 2014). Klein’s article “Hacking Summon” explains how Oregon State University was able to quickly roll “hacks” to improve the Summon 1.0 user experience (Klein, 2010). Reidsma developed open source code that allows customers to gather click information from the Summon 1.0 interface (Reidsma, 2012a-b). All of these examples mentioned were implemented using traditional techniques, such as DOM manipulation.
Electronic resource librarians benefit from the ability to modify vendor interfaces not only because it allows them to cosmetically improve their user’s experience, but also to improve collections management tasks and statistics. For instance, Reidsma’s code was used by Pattern at the University of Huddersfield to collect and analyze usage patterns and statistics from Summon users (Pattern, 2012).
The ability to manipulate a vendor user interface also facilitates the roll-out of entirely new services. For instance, prior to our work, Jing embedded links in Summon 1.0 to a licensing database that she created (Jing, 2014). This feature allowed users to find detailed license information about the resource being linked to.
Lastly, librarians actively study the features provided by modern discovery systems. As an example, Fyn et al. studied students’ acceptance of and use of the Database Recommender feature in Summon (Fyn, 2013), which promotes a database from a predefined list at the top of the display of search results.
These examples show that there is a great need for, and tremendous potential benefit from, being able to improve vendor user interfaces to collect data and statistics, implement new services, and facilitate user studies that contribute to a better understanding and improvement of the services librarians provide to their community.
Acknowledgements
We are indebted to the Summon user community for ideas and discussion regarding the hacks we presented. We would also like to thank Sara Amato for her feedback and help in shepherding the paper, and Jason Thomale for his excellent editing.
Notes
[1] Officially, Google refers to AngularJS as a MVW (“Model-View-Whatever”) framework to sidestep the largely philosophical discussion of whether it is closer to a traditional MVC (“Model-View-Controller”), or a MVVM (“Model-View-ViewModel”) or MVP (“Model-View-Presenter”) approach.
[2] https://docs.angularjs.org/api
[3] https://docs.angularjs.org/guide/directive
[4] https://docs.angularjs.org/api/ng/directive
[5] http://en.wikipedia.org/wiki/Dependency_injection
[6] By convention, the camelCased name doiLink in the definition corresponds to the hyphenated directive doi-link when invoked.
[7] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Values,_variables,_and_literals#String_literals
[8] https://github.com/pc035860/angular-highlightjs
[9] http://libx.lib.vt.edu/services/summonvis/summon2.0/listtemplates.html
[10] https://docs.angularjs.org/api/ng/service/$compile
[11] http://api.summon.serialssolutions.com/
[12] http://en.wikipedia.org/wiki/Prototype-based_programming
[13] https://github.com/angular/angular.js/issues/1306
[14] http://ocoins.info/
[15] https://docs.angularjs.org/api/ng/service/$templateCache
[16] AngularJS provides multiple methods of achieving the same goal, which can be confusing. They are discussed here (https://docs.angularjs.org/guide/di). Our example uses the “Inline Array Annotation” method.
[17] http://diveintohtml5.info/storage.html
[18] http://en.wikipedia.org/wiki/JSONP
[19] We would have liked to use AngularJS’s $resource service, but it is not included in Summon 2.0.
[20] https://docs.angularjs.org/guide/module
[21] http://httpd.apache.org/docs/2.2/rewrite/intro.html#rewritecond
[22] https://docs.angularjs.org/guide/$location
[23] https://docs.angularjs.org/guide/services
[24] https://github.com/angular/angular.js/issues/8748
References
Fyn AF, Vera Lux and Robert JS. 2013. Reflections on teaching and tweaking a discovery layer. Reference Services Review 41(1):113-124.
Hevery M. 2009. Building Web Apps with Angular. OOPSLA. Orlando, FL: Association for Computing Machinery. http://www.oopsla.org/oopsla2009/program/demonstrations/254-building-web-apps-with-angular-2-of-2
Hevery M, Abrons A. 2009. Declarative web-applications without server: demonstration of how a fully functional web-application can be built in an hour with only HTML, CSS & Javascript Library. Proceedings of the 24th ACM SIGPLAN conference companion on Object oriented programming systems languages and applications. Orlando, Florida, USA: ACM.
Jing J. 2014. Adding copyright/license information to different library systems. ALA. Las Vegas, NV. [cited 2014 September 09]. Available from: http://www.slideshare.net/happyrainb/ala2014
Klein MB. 2010. Hacking Summon. The Code4Lib Journal 11. [cited 2014 September 09]. Available from: http://journal.code4lib.org/articles/3655
LibraryThing. LibraryThing for Libraries [Internet]. [cited 2014 September 29]. Available from: https://www.librarything.com/forlibraries
Oldham R. 2014. Hacking Your Discovery Layer. Computers in Libraries. Washington, DC. [cited 2014 September 09]. Available from: http://www.infotoday.com/cil2014/session.asp?ID=A105
Pattern D. 2012. Relevancy Rules. Self-Plagiarism is Style. [cited 2014 September 09]. Available from: http://www.daveyp.com/2012/05/06/relevancy-rules/
Proquest. Syndetics Solutions, Enrichment Elements [Internet]. [cited 2014 September 29]. Available from: http://proquest.syndetics.com/Marketing/Detail/EnrichmentElement
Reidsma M. 2012a. Guerrilla Analytics. Matthew Reidsma. [cited 2014 September 09]. Available from: http://matthew.reidsrow.com/articles/24
Reidsma M. 2012b. Summon-Stats. [cited 2014 September 09]. Available from: https://github.com/mreidsma/Summon-Stats
Schmidt K, Elguindi AC. 2013. Discovery systems, layers and tools, and the role of the electronic resources librarian. Electronic Resource Management: Practical Perspectives in a New Technical Services Model. Chandos Publishing. p. 109-139.
About the Authors
Godmar Back is Associate Professor of Computer Science at Virginia Tech, where he has been doing research and teaching in Computer Science since 2004. Dr. Back obtained his PhD from the University of Utah and worked as a post-doctoral scholar at Stanford University. His research interests are diverse, including operating systems, virtualization, web technology, scientific computing, programming languages, and library information systems.
He is an active collaborator with librarians in the area of advancing library technology to ensure that modern technology can find its way into the library sphere. Since 2007, he has been involved in the LibX project, providing technical supervision and input. Recently, he has been leading the LibFX project (libfx.lib.vt.edu) which creates online visualizations of real-time library usage.
Annette Bailey is currently the Assistant Director for Electronic Resources and Emerging Technology Services for the Jean Russell Quible Department of Collections and Technical Services at Virginia Tech. Bailey serves on the Program Planning Committee for the ER&L Conference. She co-developed the open source LibX plug-in, for which she received the 2007 LITA Brett Butler Entrepreneurship Award. She won a National Leadership Grant in 2006 for LibX and in 2008 for LibX 2.0. Her role in Collections Technical Services is to ensure best practices are implemented as workflows and data change for electronic resources.
Subscribe to comments: For this article | For all articles
Leave a Reply
Name (required)
Mail (will not be published) (required)
Website
Δ
ISSN 1940-5758
Current Issue
Issue 60, 2025-04-14
Previous Issues
Issue 59, 2024-10-07
Issue 58, 2023-12-04
Issue 57, 2023-08-29
Issue 56, 2023-04-21
Older Issues
For Authors
Call for Submissions
Article Guidelines
Log in
This work is licensed under a Creative Commons Attribution 3.0 United States License.