我在自定義指令中遇到了隔離範圍的問題。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' });
}]);
從detailspage我將回到通過使用NG-點擊資源簡介。在被稱爲我使用的函數中:
$location.path("/");
如果這件事情按鈕在另一個指令。
的人選擇器,指令的parentcontroller看起來是這樣的:
angular.module('presenceSummary', [])
.controller('presenceSummary', function ($scope, $location, hrDbService, hrUserService, hrUiControlService) {
...
});
我想你需要向我們展示更多的指令,即控制器和鏈接功能(如果有的話)。 – 2014-09-30 15:24:53
用更多代碼更新帖子 – 2014-09-30 15:34:38
請添加您的路由配置和控制器,即父範圍。 – 2014-09-30 15:46:28