Currently, I am utilizing Primo, an AngularJS app developed by Ex Libris. This application functions as a library catalog, enabling users to explore both physical and digital collections within the library. Despite not having direct access to the original AngularJS codebase, I do possess the capability to define and append AngularJS modules as needed.
My immediate task seems straightforward at first glance: establish a link within Primo that directs users to a third-party app, inclusive of a query string encompassing the specific item ID which the patron is viewing, for example,
https://library.example.edu/ill/primo.php?docID=cdi_proquest_ebookcentral_EBC7007769
.
By using the Primo control panel, I was able to successfully insert the link with options to set the URL, link text, and other parameters. The screenshot below illustrates this section of the control panel:
The URL Template field permits the input of the desired link URL and offers placeholders to incorporate data related to the item. For instance, {rft.atitle}
would be substituted with the article title. Regrettably, it lacks a method to insert the docID directly. Although I attempted including an AngularJS token like {{pnx.control.recordid[0]}}
, presumably to fetch the required data, the UI rejected this input as an invalid parameter. Consequently, I specified my URL as
https://example.com/incoming.php?docID=replaceMe
. My intention was to craft JavaScript logic to extract the docID from the dynamic URL and update the link prior to user interaction.
However, upon implementation, Primo generated the link as an AngularJS component, generating the following code snippet when rendered on an actual page:
<md-list-item ng-repeat="service in $ctrl.filteredServices() track by $index" role="listitem">
<button type="button" ng-transclude="" (click)="$ctrl.onClick(service)" aria-label="Interlibrary Loan, opens in a new window">
<span ng-if="service['service-type'] === 'OvL'">
<a
ng-href="https://library.example.edu/ill/primo.php?docID=replaceMe"
ng-click="$event.preventDefault()"
translate="Interlibrary Loan"
href="https://library.example.edu/ill/primo.php?docID=replaceMe"
>Interlibrary Loan</a>
</span>
</button>
</md-list-item>
To enhance clarity, extraneous container DIVs and styling information have been excluded. Moreover, the indentation has been refined for readability.
Evidently, the link incorporates both an ng-href
attribute and an href
attribute storing the initial URL inputted. Despite attempting to dynamically update these attributes via Javascript manipulation, the modifications failed to persist when clicking the link, subsequently redirecting users to the unaltered URL. Supposedly, AngularJS retains the original URL within its internal data structure during processing, thereby circumventing any alterations made to the corresponding tag attributes.
Notably, a redundant <button>
encompassing the link was introduced, effectively replicating the functionality of the link itself. While this design choice appears aimed at expanding the clickable area, managing the URL updates across both elements complicates the debugging process.
In essence, my goal centers around substituting the placeholder "replaceMe" with the actual docID and updating the associated URL accordingly. Although a pragmatic solution could involve manipulating the DOM to replicate and replace the entire HTML structure produced by AngularJS, such brute force tactics contradict my preference of collaborating harmoniously with AngularJS rather than working against its innate functionalities.
This predicament raises two pivotal inquiries:
- How can I pinpoint where AngularJS stores the URL? Identifying the exact location of this data remains elusive.
- Once located, is there an AngularJS-specific approach to modifying it? Adhering to AngularJS conventions is imperative to avoid unforeseen conflicts.
After exhaustively scouring through search results predominantly yielding AngularJS coding resources instead of practical insights on real-time data updates, my continuous efforts over the past three days have yet to yield substantial progress. Your guidance or assistance would be immensely valued and appreciated.
UPDATE, six days later:
Progress is being made, albeit at a gradual pace.
An initial hurdle encountered involved the discovery that debug info had been disabled by the original developers at Ex Libris:
$compileProvider.debugInfoEnabled(false)
Further exploration led me to stumble upon a Firefox extension titled AngularScope, promising the ability to inspect scopes linked to arbitrary DOM elements. Upon installation, the extension alerted me regarding the disabled debug info, prompting me to re-enable it via the console with:
angular.reloadWithDebugInfo()
Discovering that the scope for my current link contains an object referred to as service
housing a property named
link-to-service</code shed light on where the URL data was stored. Subsequently, I captured a reference to the target link under investigation denoted as <code>myLink
and formulated the following script:
angular.element(myLink).scope().$apply(function () {
angular.element(myLink).scope().service["link-to-service"] = newURL;
});
Remarkably, the execution yielded successful outcomes! Updating the URL content, users are now directed to the correct destination by clicking either the link or accompanying button.
However, a crucial caveat emerged - this method exclusively operates when AngularJS's debug info feature is enabled. By default, this option remains inactive, causing the AngularJS scopes to remain detached from the DOM, rendering angular.element(myLink).scope()
inaccessible and ineffectual.
An attempt to restore access to the scopes by executing the following script methodology provided limited success:
var scope;
angular.element(document.body).injector().invoke(function ($rootScope) {
scope = $rootScope;
console.log(scope);
});
Unfortunately, encountering a similar setback where
angular.element(document.body).injector()
returned as undefined suggests potential revisions to AngularJS framework may have transpired since the referenced answer back in 2015.
A strategic maneuver entailing the establishment of a novel AngularJS module integrated with its .run()
function to interact with the DOM post-AngularJS bootstrap phase but premised before template compilation had little to no impact, likely due to delayed loading subsequent to page initialization by the time my module integration took effect.
Contemplation ensued surrounding leveraging event handling mechanisms like DOMContentLoaded
to preemptively modify URLs ahead of AngularJS script injection. Realization dawned upon realizing the counterproductive nature of such attempts given my scripts were appended by AngularJS itself; essentially translating to missed opportunities for timely intervention towards URL updates.
Hence, the focal issue stands resolute: How does one obtain access to an AngularJS component's scope sans debug info?
If empowered with scope accessibility, the URL update procedure becomes trivial. Alas, despite laboring intensively over the course of nine days, achieving this objective persists as an ongoing challenge. A growing temptation lingers urging one towards devising a potential workaround involving radical JavaScript interventions aimed at reconstructing the AngularJS-generated HTML structure entirely in favor of facilitating URL adjustments. While undoubtedly cumbersome and grossly inefficient, the reassurance of attaining successful outcomes merits contemplation amid looming hurdles stalling further progress.