65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 AngularJS/jQuery 为 SharePoint 2013 开发自定义日期选择器、人员选择器和选择(菜单选择)

starIconstarIconstarIconstarIconstarIcon

5.00/5 (7投票s)

2015 年 7 月 13 日

CPOL

5分钟阅读

viewsIcon

52506

downloadIcon

894

使用 AngularJs/jQuery 为 SharePoint 2013 应用或内容编辑器 Web 部件创建自定义日期选择器、人员选择器和选择。

引言

当我们需要创建一个自定义表单来添加新项或编辑列表中的项时,我们可能会在一些字段上遇到困难,例如 日期人员以及选择。其原因在于:用户很可能希望为这些类型的字段使用日期选择器、人员选择器和下拉列表、单选按钮或复选框。我们不能强制用户在文本输入框中输入这些字段的精确值,然后保存。如果我们这样做,那将非常糟糕,我猜想。因此,本文的目的是:如何创建这些控件以改善我们用户的用户体验。

初始设置

在我们深入本文之前,需要具备以下知识。

  1. AngularJs
  2. jQuery
  3. SharePoint 2013 REST API to List (SharePoint 2013 REST API 与列表)
  4. SharePoint 2013 和 AngularJs

出于演示目的,我假设我们有一个名为 Task 的列表,其中包含以下字段

标题 单行文本
DueDate (到期日期) 日期和时间
AssignedTo (指派给) People or Group (人员或组)
状态 选择

为了测试,请在 Status (状态) 字段中输入一些值,例如 Running (运行中)、Closed (已关闭) 等。现在,我们需要下载一些库,例如

  1. jQuery(从官方网站或 nuget 下载)
  2. AngularJs(从官方网站或 nuget 下载)
  3. jQuey UI(从官方网站或 nuget 下载)
  4. ui-date 指令(如果您想使用 AngularJs 开发日期选择器,它将很有帮助)
  5. ngTagsInput(如果您想使用 AngularJs 开发人员选择器,它将很有帮助)
  6. bootstrap-tagsinput(如果您想使用 jQuery 开发日期选择器,它将很有帮助)

为了对所有内容进行样式设置,bootstrap 是一个不错的选择。我在这里不展示创建应用或内容编辑器 Web 部件的步骤,但在附件中您会找到一个使用 AngularJs 的 SharePoint 托管应用。在本文中,我将只讨论方法。因此,在创建这些控件之前,请将上述库添加到您的项目中。

选择

要创建选择输入字段,首先,我们必须获取选择字段的值。

var choiceFieldEndPoint = "/_api/web/lists/GetByTitle('List Name')/
fields?$filter=EntityPropertyName eq 'Name of the Choice field'"

如果您向上述 URL 发送一个 get 请求,它将返回 Choice 字段的所有值。在 AngularJs 中,您可以这样编写 HTML

<select class="form-control" 
        data-ng-model="vm.newTask.status"
        data-ng-options="status as status for status in vm.newTask.taskStatusOptions">
</select>

现在,在控制器中,从您的服务中获取 Choice 字段的值,并将其绑定到 vm.newTask.taskStatusOptions

demoAppSvc.getTaskStatusOptions()
        .then(function (response) {
            vm.newTask.taskStatusOptions = response.d.results[0].Choices.results;
        });

如果您的 Choice 字段允许多选,则创建复选框组,如下所示

<label ng-repeat="status in vm.newTask.taskStatusOptions">
    <input type="checkbox"
           value="{{status}}"
           ng-checked="vm.selectedOptions.indexOf(status) > -1"
           ng-click="vm.toggleSelection(status)"> {{status}}
</label>

在控制器中,添加以下代码使其正常工作

vm.selectedOptions = [];
vm.toggleSelection = function toggleSelection(status) {
                var index = vm.selectedOptions.indexOf(status);
                if (index > -1) {
                    vm.selectedOptions.splice(index, 1);
                } else {
                    vm.selectedOptions.push(status);
                }
            };

当您将值保存到 Choice 字段时,如果您的 Choice 字段不允许多选,请编写以下代码。

function saveTask(task) {
    var data = {
        __metadata: {
            'type': 'SP.Data.TaskListItem'
        },
        Status: task.status //It's a string
    };
    var url = "/_api/web/lists/GetByTitle('Task')/Items";
    return baseSvc.postRequest(data, url);
}

如果 Choice 字段允许多选,那么您必须传递一个 string 数组。

function saveTask(task) {
    var data = {
        __metadata: {
            'type': 'SP.Data.TaskListItem'
        },
        Status: {
            results: task.selectedOptions //It's an array
        }
    };
    var url = "/_api/web/lists/GetByTitle('Task')/Items";
    return baseSvc.postRequest(data, url);
}

我在这里不展示 baseSvc.postRequest 的创建方法。我之前写过另外两篇文章,分别使用 jQueryAngularJs 进行了介绍。

我们如何使用 jQuery 来实现这一点,让我们在实践中看看。

<select id="task-status"></select>

现在,通过 Ajax 请求获取 Choice 值,并像下面这样填充下拉列表

function createStatusOptions() {
    $.ajax({
        url: _spPageContextInfo.siteAbsoluteUrl + choiceFieldEndPoint,
        type: "GET",
        headers: {
            "accept": "application/json;odata=verbose",
        },
        success: function(response) {
            var statusOptions = response.d.results[0].Choices.results
            var status = $('#task-status');
            $.each(statusOptions, function(index, value) {
                status.append($("<option>").attr('value', index).text(value));
            });
        },
        error: function(error) {
            alert(JSON.stringify(error));
        }
    });
}

如果您的 choice 字段允许多选,那么使用 jQuery 创建一个 checkbox 组而不是 select,这正是我在上面使用 AngularJs 所做的。

日期和时间选择器

在 SharePoint 中,我们可以使用 jQuery UI 日期选择器。它在 AngularJs 中也有相同的版本。让我们从 AngularJs 开始。基本上,我推荐 这个。在使用之前,请阅读文档。

 <input class="form-control" data-ui-date="vm.dateOptions" data-ng-model="vm.newTask.dueDate" />

这里使用了 ui-date 指令。您必须像下面这样向它传递日期选项

 vm.dateOptions = {
     changeYear: true,
     changeMonth: true,
     yearRange: '1900:-0'
 };

为了将此值保存到 DateTime 字段,您必须将其转换为 ISOString

function saveTask(task) {
    var data = {
        __metadata: {
            'type': 'SP.Data.TaskListItem'
        },
        Status: task.status,
        DueDate: new Date(task.dueDate).toISOString()
    };
    var url = "/_api/web/lists/GetByTitle('Task')/Items";
    return baseSvc.postRequest(data, url);
}

对于 jQuery,以下代码演示了 HTML 和 jQuery 代码

<input type="text" id="due-date">
 $(function() {
     $("#datepicker").datepicker({
         changeYear: true,
         changeMonth: true,
         yearRange: '1900:-0'
     });
 });

您可以添加更多此处 可用 的选项。

人员或组选择器

对于这个控件,我搜索了很多,因为我们知道它是一个非常复杂的控件。我们需要在输入字段中键入时显示建议,然后从输入字段中删除用户等等。最后,我设法找到了 这个这个。基本上,这个指令允许我们在输入字段中添加标签,它在键入时还会显示建议。我试图将其制作成一个人员或组选择器。让我们一步一步地从 AngularJs 开始。第一步应该是输入时获得建议。我们可以从以下三个端点获取建议。

var userSearchSuggestionEndpoint = "/_api/web/siteusers?$select=Id,
					Title&$filter=substringof('some character', Title)";

您可以通过上述 URL 获取搜索建议,这非常好。但是有一个问题:搜索是区分大小写的。我的意思是,如果您搜索“Mo”,它将返回 Title 中包含“Mo”的结果,而不会返回那些包含“mo”的结果。

var userSearchSuggestionEndpoint = 
"/_api/SP.UI.ApplicationPages.ClientPeoplePickerWebServiceInterface.clientPeoplePickerSearchUser";

上述端点非常强大。它可以搜索所有目录中的用户。我们可以通过 POST 请求向其发送建议。

var data = {
    queryParams: {
        __metadata: {
            type: 'SP.UI.ApplicationPages.ClientPeoplePickerQueryParameters'
        },
        AllowEmailAddresses: true, 
        AllowMultipleEntities: false, 
        AllUrlZones: false, 
        MaximumEntitySuggestions: 50, 
        PrincipalSource: 15, 
        PrincipalType: 15,
        QueryString: "Your search string"
        Required: false, 
        SharePointGroupID: null, 
        UrlZone: null,
        UrlZoneSpecified: false, 
        Web: null,
        WebApplicationID: null
    }
}

MSDN 中了解更多关于 SP.UI.ApplicationPages.ClientPeoplePickerQueryParameters 的信息。

它还有一个问题,那就是它不会在响应中返回 People or Group Id (人员或组 ID)。保存值到 People or Group 字段时需要 Id。但它在响应中返回 LoginName 作为键,我们可以从 LoginName 中获取 Id。请参见 此处

现在我找到的最后一个端点似乎很有帮助。它没有区分大小写或 LoginName 的问题。它为我们提供了创建人员或组选择器所需的一切。

function getPeoplePickerSuggestion(searchKey) {
    var userSearchSuggestionEndpoint = "/_vti_bin/ListData.svc/UserInformationList?
		$select=Id,Name&$filter=substringof('" + searchKey + "',Name)";
    return baseSvc.getRequest(userSearchSuggestionEndpoint);
}

现在看看我从 这里 使用的指令。请阅读文档以获得更多自定义选项。

<tags-input ng-model="vm.newTask.assignedUsers"
                    display-property="Name"
                    placeholder="Pick User"
                    add-from-autocomplete-only="true"
                    replace-spaces-with-dashes="false">
            <auto-complete source="vm.getPeoplePickerSuggestion($query)"></auto-complete>
</tags-input>

基本上,您必须将一个数组作为 ng-model 传递,该数组将负责所有选中的用户,还有一个函数返回延迟的建议结果。请参阅我的控制器代码。

vm.newTask = {
    assignedUsers: []
};
vm.getPeoplePickerSuggestion = function(searchString) {
    return demoAppSvc.getPeoplePickerSuggestion(searchString)
        .then(function(response) {
            var results = response.d.results;
            return results.filter(function(user) {
                return user.Name.toLowerCase().indexOf(searchString.toLowerCase()) != -1;
            });
        });
};

如果您的 People or Group 字段不允许多选,那么您的代码应该如下所示

function saveTask(task) {
    var data = {
        __metadata: {
            'type': 'SP.Data.TaskListItem'
        },
        Title: task.title,
        DueDate: new Date(task.dueDate).toISOString(),
        Status: task.status,
        AssignedToId: 'Id of the selected user'
    };
    var url = "/_api/web/lists/GetByTitle('Task')/Items";
    return baseSvc.postRequest(data, url);
}

以下是多选的。您需要传递一个整数数组而不是单个整数。

function saveTask(task) {
    var data = {
        __metadata: {
            'type': 'SP.Data.TaskListItem'
        },
        Title: task.title,
        DueDate: new Date(task.dueDate).toISOString(),
        Status: task.status,
        AssignedToId: {
            results: [] // construct a array of user Id from selected users or groups
        }
    };
    var url = "/_api/web/lists/GetByTitle('Task')/Items";
    return baseSvc.postRequest(data, url);
}

对于 jQuery 版本,首先请查看 文档,并以您自己的方式实现。

<input type="text" id="people-picker" />
$('#people-picker').tagsinput({
    itemValue: 'Id',
    itemText: 'Name',
    typeaheadjs: {
        name: 'users',
        displayKey: 'Name',
        source: getPeoplePickerSuggestion() // this function returns user or group suggestions
    }
});

结论

在整篇文章中,我给了您高层次的想法。因此,也请下载我的源代码并开始深入研究。别忘了将库引用添加到您的项目中。否则,它将无法工作。

© . All rights reserved.