Directive doesn't load correctly after ngroute

I have an isolated scope issue in my custom directive.

I created a custom directive. It worked when I didn't set the scope attribute on the directive using the parent scope.

What is it? This created its own JavaScript control. Each time the site was loaded, the control was initialized and the data for the control was inserted into the parent area.

Why do I need an isolated area? Because I wanted to put the directive on the page twice. And for data that I would like to put in different variables.

What's the problem? Every time I load the page everything works fine. Then go to another site using ng-route. There I use $ Location.Path to reset the route to the first page. My control is initializing, but it doesn't seem to display it. For example, crash doesn't work.

Here is the code: directive:

 <people-picker instancename="peoplePicker" labeltext="Mitarbeiter" singleusermode="true" useonlyallowedusers="true"
                                                   allowedusers="AllowedUsers" selectedusers="selectedUsers" instance="instance"
                                                   callbackwhenuserchanged="dataChanged(currentSelectedUsers)">
                                    </people-picker>

      

directive:

.directive('peoplePicker', function () {
    return {
        restrict: 'E',
        templateUrl: '../DirectiveTemplates/PeoplePicker.html',
        scope: {
            instancename: '@',
            labeltext: '@',
            singleusermode: '@',
            selectedusers: '=',
            useonlyallowedusers: '@',
            allowedusers: '=',
            callbackwhenuserchanged: '&',
            instance: '='
        },
        controller: function ($scope, utilities, spContextProvider) {
            $scope.singleusermode = $scope.singleusermode !== undefined && $scope.singleusermode.toUpperCase() === 'TRUE';
            $scope.useonlyallowedusers = $scope.useonlyallowedusers !== undefined && $scope.useonlyallowedusers.toUpperCase() === 'TRUE';

            $scope.peoplePicker = {};
            $scope.idSpanAdministrators = 'spanAdministrators' + $scope.instancename;
            $scope.idInputAdministrators = 'inputAdministrators' + $scope.instancename;
            $scope.idDivAdministratorsSearch = 'divAdministratorsSearch' + $scope.instancename;
            $scope.idHdnAdministrators = 'hdnAdministrators' + $scope.instancename;

           ...

            $scope.initializePeoplePicker = function () {
                var context = spContextProvider.GetSharePointContext();

                $scope.peoplePicker = new CAMControl.PeoplePicker(
                $scope.instancename,
                context,
                $('#' + $scope.idSpanAdministrators),
                $('#' + $scope.idInputAdministrators),
                $('#' + $scope.idDivAdministratorsSearch),
                $('#' + $scope.idHdnAdministrators));

                ...

                $scope.peoplePicker.Initialize();
                $scope.addSelectedUsers($scope.selectedusers);
            }

            $scope.addSelectedUsers = function (selectedUsers) {
                if (selectedUsers !== null) {
                    angular.forEach(selectedUsers, function (item) {
                        $scope.peoplePicker.RecipientSelected(item.Login, item.Name, item.Email);
                    });
                }
            }

            $scope.$watchCollection($scope.selectedusers, function () {
                $scope.addSelectedUsers($scope.selectedusers);
            }, true);

            spContextProvider.CallSharePointWithFunction($scope.initializePeoplePicker);
        }

      

This peoplepicker uses a control that works with 4 html elements. The will must be initialized.

For complete code, I'll post the control (removed some lines due to length limitation).

var CAMControl;
(function (CAMControl) {
    var PeoplePicker = (function () {

        // Constructor
        function PeoplePicker(InstanceName, SharePointContext, PeoplePickerControl, PeoplePickerEdit, PeoplePickerDisplay, PeoplePickerData) {
            //public properties
            this.SharePointContext = SharePointContext;
            this.PeoplePickerControl = PeoplePickerControl;
            this.PeoplePickerEdit = PeoplePickerEdit;
            this.PeoplePickerDisplay = PeoplePickerDisplay;
            this.PeoplePickerData = PeoplePickerData;
            this.InstanceName = InstanceName;
            // optionally show more/less entries in the people picker dropdown, 5 is the default
          ...

            window.document[this.InstanceName] = this;
        }

        // Property wrapped in function to allow access from event handler
        PeoplePicker.prototype.GetPrincipalType = function () {
            return this.PrincipalType;
        }

        ...

        // HTML encoder
        PeoplePicker.prototype.HtmlEncode = function (html) {
            return document.createElement('a').appendChild(document.createTextNode(html)).parentNode.innerHTML;
        }

        // HTML decoder
        PeoplePicker.prototype.HtmlDecode = function (html) {
            var a = document.createElement('a');
            a.innerHTML = html;
            return a.textContent;
        }

      ...

        PeoplePicker.prototype.LoadScript = function (url, callback) {
            var head = document.getElementsByTagName("head")[0];
            var script = document.createElement("script");
            script.src = url;

            // Attach handlers for all browsers
            var done = false;
            script.onload = script.onreadystatechange = function () {
                if (!done && (!this.readyState
                            || this.readyState == "loaded"
                            || this.readyState == "complete")) {
                    done = true;

                    // Continue your code
                    callback();

                    // Handle memory leak in IE
                    script.onload = script.onreadystatechange = null;
                    head.removeChild(script);
                }
            };

            head.appendChild(script);
        }

       ...

        // Generates the html for a resolved user
        PeoplePicker.prototype.ConstructResolvedUserSpan = function (login, name) {
            var login = login.replace(/\\/g, '\\\\');

            resultDisplay = 'Remove person or group {0}';
            if (typeof deleteUser != 'undefined') {
                resultDisplay = deleteUser;
            }
            resultDisplay = this.Format(resultDisplay, name);

            var userDisplaySpanTemplate = '<span class="peoplepicker-userSpan"><span class="entity-resolved">{0}</span><a title="{3}" class="peoplepicker-delImage" onclick="{1}.DeleteProcessedUser({2}); return false;" href="#">x</a></span>';
            return this.Format(userDisplaySpanTemplate, name, this.InstanceName, "'" + login + "'", resultDisplay);
        }

        // Create a html representation of the resolved user array
        PeoplePicker.prototype.ResolvedUsersToHtml = function () {
            var userHtml = '';
            for (var i = 0; i < this._ResolvedUsers.length; i++) {
                userHtml += this.ConstructResolvedUserSpan(this._ResolvedUsers[i].Login, this._ResolvedUsers[i].Name);
            }
            return userHtml;
        }

        // Returns a resolved user object
        PeoplePicker.prototype.ResolvedUser = function (login, name, email) {
            var user = new Object();
            user.Login = login;
            user.Name = name;
            user.Email = email;
            return user;
        }

        // Add resolved user to array and updates the hidden field control with a JSON string
        PeoplePicker.prototype.PushResolvedUser = function (resolvedUser) {
            if (this.AllowDuplicates) {
                this._ResolvedUsers.push(resolvedUser);
            } else {
                var duplicate = false;
                for (var i = 0; i < this._ResolvedUsers.length; i++) {
                    if (this._ResolvedUsers[i].Login == resolvedUser.Login) {
                        duplicate = true;
                    }
                }

                if (!duplicate) {
                    this._ResolvedUsers.push(resolvedUser);
                }
            }

            this.PeoplePickerData.val(JSON.stringify(this._ResolvedUsers));
        }


        // Function called then the clientPeoplePickerSearchUser succeeded
        PeoplePicker.prototype.QuerySuccess = function (queryNumber, searchResult) {
            var results = this.SharePointContext.parseObjectFromJsonString(searchResult.get_value());
            var txtResults = '';

            var baseDisplayTemplate = '<div class=\'ms-bgHoverable\' style=\'width: 400px; padding: 4px;\' onclick=\'javascript:{0}.RecipientSelected(\"{1}\", \"{2}\", \"{3}\")\'>{4}';
            var displayTemplate = '';
            if (this.ShowLoginName && this.ShowTitle) {
                displayTemplate = baseDisplayTemplate + ' ({5})<br/>{6}</div>';
            } else if (this.ShowLoginName) {
                displayTemplate = baseDisplayTemplate + ' ({5})</div>';
            } else if (this.ShowTitle) {
                displayTemplate = baseDisplayTemplate + ' ({6})</div>';
            } else {
                displayTemplate = baseDisplayTemplate + '</div>';
            }

            if (results) {
                ...

                if (results.length > 0) {
                    // if this function is not the callback from the last issued query then just ignore it. This is needed to ensure a matching between
                    // what the user entered and what is shown in the query feedback window
                    if (queryNumber < this._lastQueryID) {
                        return;
                    }

                    displayCount = results.length;
                    if (displayCount > this.MaxEntriesShown) {
                        displayCount = this.MaxEntriesShown;
                    }

                    for (var i = 0; i < displayCount; i++) {
                        var item = results[i];
                        var oldLoginName = item['Key'];
                        var loginName = oldLoginName.replace(/\\/g, '\\\\');
                        var displayLoginName = oldLoginName.split('|')[1].replace(/\\/g, '\\');
                        var displayName = item['DisplayText'];
                        var title = item['EntityData']['Title'];
                        var email = item['EntityData']['Email'];
                        txtResults += this.Format(displayTemplate, this.InstanceName, loginName, this.HtmlEncode(displayName), email, displayName, displayLoginName, title);
                    }
                    var resultDisplay = '';
                    txtResults += '<div class=\'ms-emphasisBorder\' style=\'width: 400px; padding: 4px; border-left: none; border-bottom: none; border-right: none; cursor: default;\'>';
                    if (results.length == 1) {
                        resultDisplay = 'Showing {0} result';
                        if (typeof resultsSingle != 'undefined') {
                            resultDisplay = resultsSingle;
                        }
                        txtResults += this.Format(resultDisplay, results.length) + '</div>';
                    } else if (displayCount != results.length) {
                        resultDisplay = "Showing {0} of {1} results. <B>Please refine further<B/>";
                        if (typeof resultsTooMany != 'undefined') {
                            resultDisplay = resultsTooMany;
                        }
                        txtResults += this.Format(resultDisplay, displayCount, results.length) + '</div>';
                    } else {
                        resultDisplay = "Showing {0} results";
                        if (typeof resultsMany != 'undefined') {
                            resultDisplay = resultsMany;
                        }
                        txtResults += this.Format(resultDisplay, results.length) + '</div>';
                    }

                    this.PeoplePickerDisplay.html(txtResults);
                    //display the suggestion box
                    this.ShowSelectionBox();
                }
                else {
                    var searchbusy = '<div class=\'ms-emphasisBorder\' style=\'width: 400px; padding: 4px; border-left: none; border-bottom: none; border-right: none; cursor: default;\'>No results found</div>';
                    this.PeoplePickerDisplay.html(searchbusy);
                    //display the suggestion box
                    this.ShowSelectionBox();
                }
            }
            else {
                //hide the suggestion box since results are null
                this.HideSelectionBox();
            }
        }

        // Initialize
        PeoplePicker.prototype.Initialize = function () {
            var scriptUrl = "";
            var scriptRevision = "";
            $('script').each(function (i, el) {
                if (el.src.toLowerCase().indexOf('peoplepickercontrol.js') > -1) {
                    scriptUrl = el.src;
                    scriptRevision = scriptUrl.substring(scriptUrl.indexOf('.js') + 3);
                    scriptUrl = scriptUrl.substring(0, scriptUrl.indexOf('.js'));
                }
            })

            // Load translation files
            var resourcesFile = scriptUrl + "_resources." + this.Language.substring(0, 2).toLowerCase() + ".js";
            if (scriptRevision.length > 0) {
                resourcesFile += scriptRevision;
            }

            this.LoadScript(resourcesFile, function () {
            });


            // is there data in the hidden control...if so show it
            if (this.PeoplePickerData.val() !== undefined && this.PeoplePickerData.val().length > 0) {
                // Deserialize JSON string into list of resolved users
                this._ResolvedUsers = JSON.parse(this.PeoplePickerData.val());
                // update the display of resolved users
                this.PeoplePickerControl.html(this.ResolvedUsersToHtml());
            }

            var parent = this;
            this.PeoplePickerEdit.keydown(function (event) {
                var keynum = event.which;
                //backspace
                if (keynum == 8) {
                    //hide the suggestion box when backspace has been pressed
                    parent.HideSelectionBox();
                    // do we have text entered
                    var unvalidatedText = parent.PeoplePickerEdit.val();
                    if (unvalidatedText.length > 0) {
                        // delete the last entered character...meaning do nothing as this delete will happen as part of the keypress
                    }
                    else {
                        // are there resolved users, if not there nothing to delete
                        if (parent._ResolvedUsers.length > 0) {
                            // remove the last added user
                            parent.PopResolvedUser();
                            // update the display
                            parent.PeoplePickerControl.html(parent.ResolvedUsersToHtml());
                            // focus back to input control
                            parent.PeoplePickerEdit.focus();
                            // Eat the backspace key
                            return false;
                        }
                    }
                }
                    // An ascii character or a space has been pressed
                else if (keynum >= 48 && keynum <= 90 || keynum == 32) {
                    // get the text entered before the keypress processing (so the last entered key is missing here)    
                    var txt = parent.PeoplePickerEdit.val();

                    // keynum is not taking in account shift key and always results inthe uppercase value
                    if (event.shiftKey == false && keynum >= 65 && keynum <= 90) {
                        keynum += 32;
                    }

                    // Append the last entered character: since we're handling a keydown event this character has not yet been added hence the returned value misses the last character
                    txt += String.fromCharCode(keynum);

                    // we should have at least 1 character
                    if (txt.length > 0) {
                        var searchText = txt;

                        //ensure that MinimalCharactersBeforeSearching >= 1
                        if (parent.GetMinimalCharactersBeforeSearching() < 1) {
                            parent.SetMinimalCharactersBeforeSearching(1);
                        }

                        // only perform a query when we at least have two chars and we do not have a query running already
                        if (searchText.length >= parent.GetMinimalCharactersBeforeSearching()) {
                            resultDisplay = 'Searching...';
                            if (typeof resultsSearching != 'undefined') {
                                resultDisplay = resultsSearching;
                            }
                            var searchbusy = parent.Format('<div class=\'ms-emphasisBorder\' style=\'width: 400px; padding: 4px; border-left: none; border-bottom: none; border-right: none; cursor: default;\'>{0}</div>', resultDisplay);
                            parent.PeoplePickerDisplay.html(searchbusy);
                            //display the suggestion box
                            parent.ShowSelectionBox();

                            var query = new SP.UI.ApplicationPages.ClientPeoplePickerQueryParameters();
                            query.set_allowMultipleEntities(false);
                            query.set_maximumEntitySuggestions(2000);
                            query.set_principalType(parent.GetPrincipalType());
                            query.set_principalSource(15);
                            query.set_queryString(searchText);
                            var searchResult = SP.UI.ApplicationPages.ClientPeoplePickerWebServiceInterface.clientPeoplePickerSearchUser(parent.SharePointContext, query);

                            // update the global queryID variable so that we can correlate incoming delegate calls later on
                            parent._queryID = parent._queryID + 1;
                            var queryIDToPass = parent._queryID;
                            parent._lastQueryID = queryIDToPass;

                            // make the SharePoint request
                            parent.SharePointContext.executeQueryAsync(Function.createDelegate(this, function () { parent.QuerySuccess(queryIDToPass, searchResult); }),
                                                                       Function.createDelegate(this, function (a, arguments) { parent.QueryFailure(queryIDToPass, arguments); }));
                        }
                    }
                }
                    //tab or escape
                else if (keynum == 9 || keynum == 27) {
                    //hide the suggestion box
                    parent.HideSelectionBox();
                }
            });

        }

        return PeoplePicker;
    })();
    CAMControl.PeoplePicker = PeoplePicker;
})(CAMControl || (CAMControl = {}));

      

Routeprovider:

.config(['$routeProvider', function ($routeProvider) {
    $routeProvider.when('/summary', {
        templateUrl: 'PresenceSummary.html'
    })
        .when('/details/:workingDay', {
            templateUrl: 'PresenceDetails.html'
        })
        .otherwise({ redirectTo: '/summary' });
}]);

      

On the details page, I'll go back to the pivot page with ng-click. In the gateway called, I use:

$location.path("/");

      

If it matters, the button is in a different directive.

The parentcontroller element of the people-picker directive looks like this:

angular.module('presenceSummary', [])
    .controller('presenceSummary', function ($scope, $location, hrDbService, hrUserService, hrUiControlService) {

        ...
    });

      

+3


source to share


1 answer


I found the answer. The directive is displayed before the dom is ready. My controls are not available.

I have set a timeout. This article gave me this hint: http://blog.brunoscopelliti.com/run-a-directive-after-the-dom-has-finished-rendering



Thank you for your help!

+1


source







All Articles