在ngroute之后,指令无法正确加载

时间:2014-09-30 14:36:21

标签: javascript angularjs angularjs-directive angularjs-scope ngroute

我的自定义指令中有一个隔离范围的问题。

我已经构建了一个自定义指令。当我没有使用父范围在指令中设置scope-attribute时,它工作。

它做了什么?它呈现了本机JavaScript控件。每次加载站点时,控件都被初始化,控件的数据被插入到父作用域中。

为什么我需要一个孤立的范围?因为我想将指令两次放在页面上。对于我希望放入不同变量的数据。

有什么问题?每次加载页面都可以正常工作。然后我使用ng-route切换到另一个站点。在那里我使用$ Location.Path重置到第一页的路由。我的控件初始化但似乎它没有呈现它的内容。例如,没有keydown工作。

这里有一些代码: 指令:

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

指令:

.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);
        }

这个peoplepicker使用一个控件,它可以处理4个html元素。遗嘱必须初始化。

对于完整代码,我将发布控件(删除了一些行,因为长度限制)。

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's 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' });
}]);

在详细信息页面中,我将使用ng-click返回摘要页面。在我称之为的地方使用:

$location.path("/");

如果这很重要,按钮是另一个指令。

people-picker-directive的parentcontroller看起来像这样:

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

        ...
    });

1 个答案:

答案 0 :(得分:1)

我找到了答案。该指令在dom准备好之前呈现。我的控件不可用。

我设置了超时。这篇文章给了我这个提示: http://blog.brunoscopelliti.com/run-a-directive-after-the-dom-has-finished-rendering

感谢您的帮助!