I put the code that talks to SharePoint in a separate class, "SPDataServices". It uses CSOM to talk to SharePoint, I am exploring changing to REST, it requires less code. See Angular and Angular User Information List for a discussion of the scripts that use this class.

​SPDataServices
​
(function () {
"use strict";
  var app = angular.module("modSPDataServices", []); 
//
// DatePicker Directive
//

app.directive("datepicker", function () {
return {
restrict: "A",
require: "ngModel",
link: function (scope, elem, attr, ngModelCtrl) {
var updateModel = function (dateText) {
scope.$apply(function () {
ngModelCtrl.$setViewValue(dateText);
});
};
var options = {
dateFormat: "mm/dd/yy",
onSelect: function (dateText) {
updateModel(dateText);
}
};
elem.datepicker(options);
}
}
});

//
// SPDataServices Factory
//

app.factory("SPDataServices", function($window, $q, $log) {
var SPDataServices = {};

//
// SharePoint List methods
//

SPDataServices.addListItem = function (listName, fields, values) {
// Get Context.
var contextLoaded = $q.defer();
var clientCtx;
var web;
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', function () {
clientCtx = SP.ClientContext.get_current();
  web = clientCtx.get_web();
  contextLoaded.resolve(web);
});
  // Add List Item.
var deferred = $q.defer();
contextLoaded.promise
.then(function () {

    var list = web.get_lists().getByTitle(listName);
        var itemCreateInfo = new SP.ListItemCreationInformation();
        var listItem = list.addItem(itemCreateInfo);
  for (var i = 0; i < fields.length; i++) {
  if (values[i] == null) {
  console.log("Field " + fields[i] + " was null.");
  }
  else {
listItem.set_item(fields[i], values[i].toString());
  }
  };
    listItem.update();
    clientCtx.load(listItem);
    clientCtx.executeQueryAsync(function () {
        deferred.resolve(listItem.get_fieldValues());
    }, function (sender, args) {
        var messageFormat="Adding new item to list {" + listName + "} failed with error " + args.get_message();
        //var message = messageFormat.format(listName, args.get_message(), args.get_stackTrace());
        $log.error(messageFormat);
    })
});
return deferred.promise;
}; // end SPDataServices.addListItem

SPDataServices.getListItem = function(listName, listItemID, fields) {
var listItem;
// Get Context.
var contextLoaded = $q.defer();
var clientCtx;
var web;
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', function () {
clientCtx = SP.ClientContext.get_current();
  web = clientCtx.get_web();
  contextLoaded.resolve(web);
});
// Get List Item.
var deferred = $q.defer();
contextLoaded.promise
.then(function () {
var list = web.get_lists().getByTitle(listName);
var listItem = list.getItemById(listItemID);
  clientCtx.load(list);
  clientCtx.load(listItem, fields);
  clientCtx.executeQueryAsync(function () {
deferred.resolve(listItem);
}, function (sender, args) {
  var messageFormat="Loading of list item {" + listItemID + "} from {" + listName + "} failed with error " + args.get_message();
//var message=messageFormat.format(listName,args.get_message() ,args.get_stackTrace());
$log.error(messageFormat);
})
});
return deferred.promise;
}; // end SPDataServices.getListItem

SPDataServices.saveListItem = function (listName, listItemID, fields, values) {

// Get Context.
var contextLoaded = $q.defer();
var clientCtx;
var web;
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', function () {
clientCtx = SP.ClientContext.get_current();
  web = clientCtx.get_web();
  contextLoaded.resolve(web);
});
  // Save List Item.
var deferred = $q.defer();
contextLoaded.promise
.then(function () {

    var list = web.get_lists().getByTitle(listName);
    var listItem = list.getItemById(listItemID);
  for (var i = 0; i < fields.length; i++) {
  if (values[i] == null) {
  console.log("Field " + fields[i] + " was null.");
  }
  else {
listItem.set_item(fields[i], values[i].toString());
  }
  };
    listItem.update();
    clientCtx.load(listItem);
    clientCtx.executeQueryAsync(function () {
        deferred.resolve(listItem.get_fieldValues());
    }, function (sender, args) {
        var messageFormat="Updating of item {" + listItemID + "} of list {" + listName + "} failed with error " + args.get_message();
        //var message = messageFormat.format(listName, args.get_message(), args.get_stackTrace());
        $log.error(messageFormat);
    })
});
return deferred.promise;
}; // end SPDataServices.saveListItem
SPDataServices.getFields = function(listName) {
var list;
  var fields = [];

// Get Context.
var contextLoaded = $q.defer();
var clientCtx;
var web;
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', function () {
clientCtx = SP.ClientContext.get_current();
  web = clientCtx.get_web();
  contextLoaded.resolve(web);
});
// Get Fields.
var deferred = $q.defer();
contextLoaded.promise
.then(function () {
  list = web.get_lists().getByTitle(listName);
  var getListFields = list.get_fields();

// Load the List Fields.
  clientCtx.load(getListFields);
  clientCtx.executeQueryAsync(function () {
  var listFieldEnumerator = getListFields.getEnumerator();
  while (listFieldEnumerator.moveNext()) {
  var listField = listFieldEnumerator.get_current();
fields.push(listField);
}
deferred.resolve(fields);

}, function (sender, args) {
  var messageFormat="Loading of list {" + listName + "} failed with error " + args.get_message();
//var message=messageFormat.format(listName,args.get_message() ,args.get_stackTrace());
$log.error(messageFormat);
})
});
return deferred.promise;
}; // end SPDataServices.getFields
SPDataServices.getListItemsByView = function(listName, view) {
var list;
var viewQuery;
var viewFields = [];
var listView;

// Get Context.
var contextLoaded = $q.defer();
var clientCtx;
var web;
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', function () {
clientCtx = SP.ClientContext.get_current();
  web = clientCtx.get_web();
  contextLoaded.resolve(web);
});
// Get View.
var viewLoaded = $q.defer();
contextLoaded.promise
.then(function () {
  list = web.get_lists().getByTitle(listName);
  var getViews = list.get_views();

  clientCtx.load(getViews);
  clientCtx.executeQueryAsync(function () {
  var viewEnumerator = getViews.getEnumerator();
  while (viewEnumerator.moveNext()) {
  listView = viewEnumerator.get_current();
if(listView.get_title() == view) {
viewLoaded.resolve(listView);
return;
}
}
$log.error("View {" + view + "} of list {" + listName + "} does not exist");
}, function (sender, args) {
  var messageFormat="Loading of list {" + listName + "} failed with error " + args.get_message();
//var message=messageFormat.format(listName,args.get_message() ,args.get_stackTrace());
$log.error(messageFormat);
})
});
// Get View Fields.
var viewFieldsLoaded = $q.defer();
viewLoaded.promise
.then(function () {
//console.log(listView.get_viewQuery());
viewQuery = listView.get_viewQuery();
var getViewFields = listView.get_viewFields();
  clientCtx.load(getViewFields);
  clientCtx.executeQueryAsync(function () {
  var viewFieldEnumerator = getViewFields.getEnumerator();
  while (viewFieldEnumerator.moveNext()) {
  var viewField = viewFieldEnumerator.get_current();
  //console.log(viewField);
  viewFields.push(viewField);   
}   
viewFieldsLoaded.resolve(getViewFields);
}, function (sender, args) {
  var messageFormat="Loading of list {" + listName + "} failed with error " + args.get_message();
//var message=messageFormat.format(listName,args.get_message() ,args.get_stackTrace());
$log.error(messageFormat);
})
});

return SPDataServices.getListItems(listName, viewQuery, viewFields);
//return viewFieldsLoaded.promise;
} // end SPDataServices.getListItemsByView
SPDataServices.getListItems = function(listName, viewQuery, fields) {

var list;
  var allListFields = [];

// Get Context.
var contextLoaded = $q.defer();
var clientCtx;
var web;
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', function () {
clientCtx = SP.ClientContext.get_current();
  web = clientCtx.get_web();
  contextLoaded.resolve(web);
});
// Get Fields.
var fieldsLoaded = $q.defer();
contextLoaded.promise
.then(function () {
  list = web.get_lists().getByTitle(listName);
  var getListFields = list.get_fields();

// Load the List Fields.
  clientCtx.load(getListFields);
  clientCtx.executeQueryAsync(function () {
  var listFieldEnumerator = getListFields.getEnumerator();
  while (listFieldEnumerator.moveNext()) {
  var listField = listFieldEnumerator.get_current();
allListFields.push(listField);
}
fieldsLoaded.resolve(allListFields);

}, function (sender, args) {
  var messageFormat="Loading of list {" + listName + "} failed with error " + args.get_message();
//var message=messageFormat.format(listName,args.get_message() ,args.get_stackTrace());
$log.error(messageFormat);
})
});

// Get List Items.
var deferred = $q.defer();
fieldsLoaded.promise
.then(function () {
  var query = new SP.CamlQuery();
  query.set_viewXml(viewQuery);
  var listItems = list.getItems(query);
  var listFields = [];
  var listFieldsInternal = [];
  angular.forEach(fields, function(field) {
for (var i = 0; i < allListFields.length; i++) {
if (allListFields[i].get_title() == field || allListFields[i].get_internalName() == field) {
listFields.push(allListFields[i].get_title());
listFieldsInternal.push(allListFields[i].get_internalName());
break;
}
}
});

  var fieldList = listFieldsInternal.join(",");
  clientCtx.load(listItems,"Include("+fieldList+")" );
  clientCtx.executeQueryAsync(function () {
  var resultItems = [];
  var listItemEnumerator = listItems.getEnumerator();
  while (listItemEnumerator.moveNext()) {
  var listItem = listItemEnumerator.get_current();
  var resultItem = {};
  for (var i = 0; i < listFieldsInternal.length; i++) {
  resultItem[listFieldsInternal[i]] = listItem.get_item(listFieldsInternal[i]);
}
  resultItems.push(resultItem);
}
  deferred.resolve(resultItems);
}, function (sender, args) {
  var messageFormat="Loading of list items from {" + listName + "} failed with error " + args.get_message();
//var message=messageFormat.format(listName,args.get_message() ,args.get_stackTrace());
$log.error(messageFormat);
})
});
return deferred.promise;
}; // end SPDataServices.getListItems
return SPDataServices;
}); // end app.factory("SPDataServices", function($window)
}()); // end function




Angular

Angular User Information List