0

I am working on a SharePoint 2013 App which is an AngularJS SPA (so I don't think SharePoint is an issue).

In the Default.aspx page, I am referencing all pertinent scripts:

    <!-- Add your JavaScript to the following file -->
    <script type="text/javascript" src="../Scripts/jquery-1.9.1.min.js"></script>
    <script type="text/javascript" src="../Scripts/angular.js"></script>
    <script type="text/javascript" src="../Scripts/angular-route.js"></script>
    <script type="text/javascript" src="../Scripts/bootstrap.min.js"></script>
    <script type="text/javascript" src="../Scripts/ui-bootstrap-tpls-0.10.0.min.js"></script>
    <script type="text/javascript" src="../Scripts/moment.min.js"></script>

    <!-- ANGULARJS APPLICATION FILES -->
    <script type="text/javascript" src="../App/App.js"></script>
    <script type="text/javascript" src="../App/Controllers/main.js"></script>
    <script type="text/javascript" src="../App/Services/SharePointJSOMService.js"></script>

And here is my template:

<div data-ng-app="appITI">
    <div data-ng-controller="MainController">
        <div id="header" class="clr-darkblue">
        <a href="#">
            <img src="../Images/head_logo.gif">
        </a>
        <span class="sp_controls" data-ng-cloak="">
            Welcome {{currentUser.Title}}
            &nbsp;&nbsp;|&nbsp;&nbsp;
            <a id="btnPreferences" data-ng-click="prefs = true">My Settings</a>
            &nbsp;&nbsp;|&nbsp;&nbsp;
            Role: {{currentUser.Role}}
            &nbsp;&nbsp;|&nbsp;&nbsp;
            <a href="#">Logout</a>
        </span>
        </div> <!-- /#header -->
    </div> <!-- /mainController -->
</div> <!-- /ANGULAR APP -->

As you can see I am using ng-cloak but I have also tried ng-bind.

here is App.js

var appITI = angular.module('appITI', ['ui.bootstrap']);

var hostweburl;
var appweburl;
var currentUser;

$(document).ready(function () {
    SP.SOD.executeOrDelayUntilScriptLoaded(runMyCode, "SP.js");
    function runMyCode(){} // end runMyCode fn
}); // end Document.Ready

and the controller:

(function(){
    var MainController = function($scope, SharePointJSOMService){
        SP.SOD.executeOrDelayUntilScriptLoaded(runMyCode, "SP.js");
        function runMyCode(){

        //get currentUser
        $.when(SharePointJSOMService.getCurrentUser())
        .done(function(jsonObject){
            currentUser = jsonObject.d;
            $scope.currentUser = currentUser;
            $scope.currentUser.Role = "RSC";
            console.dir($scope);
        }).fail(function(err){ console.info(JSON.stringify(err)); });

        } // end runMyCode fn
    }; // end MainController

    MainController.$inject = ['$scope', 'SharePointJSOMService'];

    angular.module('appITI').controller('MainController', MainController);
})();

Lastly, here is the service:

appITI.service('SharePointJSOMService', function($q, $http){
    this.getCurrentUser = function(){
        var deferred = $.Deferred();

        JSRequest.EnsureSetup();
        hostweburl = decodeURIComponent(JSRequest.QueryString["SPHostUrl"]);
        appweburl = decodeURIComponent(JSRequest.QueryString["SPAppWebUrl"]);

        var userid = _spPageContextInfo.userId;
        var restQueryUrl = appweburl + "/_api/web/getuserbyid(" + userid + ")";

        var executor = new SP.RequestExecutor(appweburl);
        executor.executeAsync({
            url: restQueryUrl,
            method: "GET",
            headers: { "Accept": "application/json; odata=verbose" },
            success: function(data, textStatus, xhr){
                deferred.resolve(JSON.parse(data.body));
            },
            error: function(xhr, textStatus, errorThrown){
                deferred.reject(JSON.stringify(xhr));
            }
        });
        return deferred;
    }; // /getCurrentUser fn
});

According to everything I have read and studied, this should work. In the console.dir, everything is shown for currentUser:

{
       [functions]: ,
       $$asyncQueue: [ ],
       $$childHead: null,
       $$childTail: null,
       $$destroyed: false,
       $$isolateBindings: { },
       $$listenerCount: { },
       $$listeners: { },
       $$nextSibling: null,
       $$phase: null,
       $$postDigestQueue: [ ],
       $$prevSibling: null,
       $$watchers: [ ],
       $id: "003",
       $parent: { },
       $root: { },
       currentUser: {
          [functions]: ,
          __metadata: { },
          Email: "[email protected]",
          Groups: { },
          Id: 9,
          IsHiddenInUI: false,
          IsSiteAdmin: false,
          LoginName: "i:0#.f|membership|[email protected]",
          PrincipalType: 1,
          Role: "RSC",
          Title: "Name, My (My Title)",
          UserId: { }
       },
       this: { }
    }
2
  • You should not mix $.when() with Angular.js. Angular is designed to remove the need for jQuery asynchronicity. Commented May 5, 2014 at 16:38
  • I am following the coding of a Senior Product Marketing Manager at Microsoft and it's the best I know at this point. I hope to learn Angular and SharePoint better very soon. Commented May 5, 2014 at 18:12

1 Answer 1

1

When you are using $.when jQuery's promise implementation you will need to notify angular that something in the $scope needs updated.

At the end of this logic, call $scope.$apply():

$.when(SharePointJSOMService.getCurrentUser())
    .done(function(jsonObject){
        currentUser = jsonObject.d;
        $scope.currentUser = currentUser;
        $scope.currentUser.Role = "RSC";
        console.dir($scope);
        $scope.$apply(); // <-- tell angular to update the scope and refresh the UI
    }).fail(function(err){ console.info(JSON.stringify(err)); });

Note: this is only needed when you are referencing something outside of angular-land

Sign up to request clarification or add additional context in comments.

5 Comments

Agreed, that is the ideal solution, but there are times where existing logic and code must be re-used, and this solves the issue the OP is attempting to resolve.
Yes, I was too hasty in my assessment. Angular can be easily incorporated into existing legacy code that is using other frameworks. My comment was meant to say, if you are creating an Angular project from scratch, 99.9% of the time there is no reason to need jQuery (Angular includes its own version of jqlite). New Angular developers need to think in a declarative manner to really "get" Angular.
added $scope.apply() exactly where you suggested and got "JavaScript runtime error: Object doesn't support property or method 'apply'. NEVER MIND -- I was still in debugger. I quit that and F5 and it works perfectly. Thanks!!!
the method name is $apply not apply
It should be added that as long as you mix jQuery and Angular in this way, you will constantly need $scope.$apply() and various other hacks. Avoid it!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.