SharePoint list item popovers on hover with AngularJS

Here’s how you can create Bootstrap style popovers of SharePoint list items using AngularJS.

<!DOCTYPE html>
<link rel=”stylesheet” href=”bootstrap.css” />
<link rel=”stylesheet” href=”font-awesome.css” />

<script type=”text/javascript” src=”modernizr.custom.js”></script>
<script type=”text/javascript” src=”jquery.js”></script>
<script type=”text/javascript” src=”angular.min.js”></script>
<script type=”text/javascript” src=”bootstrap.js”></script>
<script type=”text/javascript” src=”ui-bootstrap-tpls.min.js”></script>

<body ng-app=”toolTips”>

<div ng-controller=”mainController”>
<tr ng-repeat=”faq in faqs” bs-popover>
<a href=”#” data-popover=”true” rel=”popover” data-content=”{{faq.Body}}” data-original-title=”{{faq.Title}}”>

<script type=”text/javascript”>
var app = angular.module(‘toolTips’, [‘ui.bootstrap’]);
app.controller(‘mainController’, function($scope, $http, $sce) {

method: ‘GET’,
url: “/_api/web/lists/getByTitle(‘someList)/items?$orderby=Title asc”,
cache: true,
headers: { “Accept”: “application/json;odata=verbose” }
}).success(function (data, status, headers, config) {
$scope.faqs = data.d.results;
//$scope.trustAsHtml = $sce.trustAsHtml;

}).error(function (data, status, headers, config) {



app.directive(‘bsPopover’, function() {
return function(scope, element, attrs) {
element.find(“a[rel=popover]”).popover({ placement: ‘bottom’, html: ‘true’});

$(‘body’).popover({ selector: ‘[data-popover]’, trigger: ‘click hover’, placement: ‘auto’, delay: {show: 50, hide: 2000}});



Testing AngularJS on SharePoint: 1 Installing Protractor on Windows


1: Install Protractor and Webdriver-Manager

Open a Node command prompt

Two tools will be installed when you run “npm install -g protractor“.

Test your install by running “protractor –version”

2: Update Webdriver-Manager

Next, download some needed binaries with “webdriver-manager update

3: Start the server

Start the server with “webdriver-manager start“.

What you should have now is a running instance of Selenium. Protractor tests send their requests to this server which controls the local browser. Status information should be visible here: http://localhost:4444/wd/hub

4: Create a simple test

This will require two files. One with some basic configuration information “conf.js” and another with a simple test “todo-spec.js”. Put the following in each respective file.


        exports.config = {
            seleniumAddress: ‘http://localhost:4444/wd/hub’,
            specs: [‘todo-spec.js’]


describe(‘angularjs homepage todo list’, function() {
    it(‘should add a todo’, function() {

        element(by.model(‘todoList.todoText’)).sendKeys(‘write first protractor test’);

        var todoList = element.all(by.repeater(‘todo in todoList.todos’));
        expect(todoList.get(2).getText()).toEqual(‘write first protractor test’);

        // You wrote your first test, cross it off the list
        var completedAmount = element.all(by.css(‘.done-true’));

To run the test, from the Node command prompt, cd into the folder where you have saved the two files and execute the following “protractor conf.js“.


Using stacktrace.js to log AngularJS errors to a SharePoint list

stacktrace.js: is a Framework-agnostic, micro-library for getting stack traces in all web browsers allowing you to debug your JavaScript by giving you a nicely detailed stack trace of function calls leading to an error (or any condition you specify).

1: Create a new list, in this example we will call it “apperrors” and it will be at the root. Create the following columns:

  • errorMessage as multiple lines without formatting.
  • stackTrace as multiple lines without formatting.

2: First include stacktrace.js after your AngularJS script.

<script type=”text/javascript” src=”angular-1.3.15/angular.min.js”></script>
<script type=”text/javascript” src=”stacktrace.min.js”></script>

3: By default AngularJS catches errors and log them verbosely to the console. This is highly desirable so we will keep that behavior and just add an interception in so that we can use stacktrace.js to centrally log any errors.

app.provider(“$exceptionHandler”, {
    $get: function( errorLogService ) {
        return( errorLogService );

4: Even though since step 1 stacktrace.js is now in the global scope it is not ‘correct’ to reference a global object inside an AngularJS component. Therefore the stacktrace feature needs to be wrapped in an AngularJS service that will expose the print method.

app.factory(“stacktraceService”, function() {
        print: printStackTrace


5: The error logging service is a wrapper around the core error handling of AngularJS.

app.factory(“errorLogService”, function( $log, $window, stacktraceService ) {
    function log( exception, cause ) {
        $log.error.apply( $log, arguments );
        try {
            var URL = window.location.href;
            var errorMessage = JSON.stringify(exception.toString());
            var stackTrace = JSON.stringify(stacktraceService.print({ e: exception }));
            var item = {
                “__metadata”: { “type”: “SP.Data.apperrorsListItem”},
                “Title”: URL,
                “errorMessage”: errorMessage,
                “stackTrace”: stackTrace
                url: _spPageContextInfo.webAbsoluteUrl + “/_api/web/lists/getbytitle(‘apperrors’)/items”,
                type: “POST”,
                contentType: “application/json;odata=verbose”,
                data: JSON.stringify(item),
                headers: {
                        “Accept”: “application/json;odata=verbose”,
                       “X-RequestDigest”: $(“#__REQUESTDIGEST”).val()
                success: function (data) {
                    console.log(JSON.stringify(data, null, 4));
                error: function (data) {
                    console.log(JSON.stringify(data, null, 4));
            } catch ( loggingError ) {
                $log.warn( “Error logging failed” );
                $log.log( loggingError );
    // Return the logging function.
    return( log );

5: That’s it. In theory if all has gone correctly any AngularJS errors will now get written to the SharePoint list.