Я, как и многие, давно использую библиотеку SPServices для решения многих задач.
У этой библиотеки есть функционал по автокомплиту:
Но есть у этого механизма несколько недоработок:
Просто замените код из библиотеки SPServices кодом выше.
Правда теперь и прикреплять автокомплит надо несколько иначе:
Так же был изменен цвет, под 2013 и ширину, что бы вровень было. В 2013 padding появился.
Теперь нам необходимо добавить код, который покажет popup:
Дальше добавим функцию добавление элемента списка и колбэки, которые отработают при удачном\неудачном завершении процесса создания элемента:
Теперь добавим функции, которые закрепим за кнопкой Добавить и Отмена.
При добавлении будет создавать элемент и закрытие формы, в случае нажатия по кнопке Отмена - только закрытие формы. Важно отметить, что в этих функциях мы сообщаем и результат для колбэка закрытия формы. Именно в колбэке логика по которой мы показываем уведомление.
Пример работы:
У этой библиотеки есть функционал по автокомплиту:
Но есть у этого механизма несколько недоработок:
- нет задержки перед показом вариантов
- ничего не отображается, если нет вариантов
- нельзя предлагать варианты действий, если ничего не найдено
Т.е. необходимо поменять поведение, что бы варианты появлялись с задержкой в секунду, если ничего не нашли, то показываем как на картинке:
Тут же даем возможность добавить элемент:
Извещаем о добавлении:
Вот код уже поправленной функции $.fn.SPServices.SPAutocomplete:
$.fn.SPServices.SPAutocomplete = function(options) { var opt = $.extend({}, { webURL: "", // [Optional] The name of the Web (site) which contains the sourceList sourceList: "", // The name of the list which contains the values sourceColumn: "", // The static name of the column which contains the values columnName: "", // The display name of the column in the form CAMLQuery: "", // [Optional] For power users, this CAML fragment will be Anded with the default query on the relatedList CAMLQueryOptions: "", // [Optional] For power users, allows specifying the CAMLQueryOptions for the GetListItems call CAMLRowLimit: 0, // [Optional] Override the default view rowlimit and get all appropriate rows filterType: "BeginsWith", // Type of filtering: [BeginsWith, Contains] numChars: 0, // Wait until this number of characters has been typed before attempting any actions ignoreCase: false, // If set to true, the function ignores case, if false it looks for an exact match highlightClass: "", // If a class is supplied, highlight the matched characters in the values by applying that class to a wrapping span uniqueVals: false, // If set to true, the function only adds unique values to the list (no duplicates) maxHeight: 99999, // Sets the maximum number of values to display before scrolling occurs slideDownSpeed: "fast", // Speed at which the div should slide down when values match (milliseconds or ["fast" | "slow"]) processingIndicator: "_layouts/images/REFRESH.GIF", // If present, show this while processing htmlifnothingfound: "Ничего не найдено!", debug: false // If true, show error messages;if false, run silent }, options); var matchNum; // Find the input control for the column and save some of its attributes var columnObj = $("input[Title='" + opt.columnName + "']"); columnObj.css("position", ""); var columnObjColor = columnObj.css("color"); var columnObjWidth = columnObj.css("width"); // myAdd Добавляем переменную columnObjPadding var columnObjPadding = columnObj.css("padding"); if (columnObj.html() === null && opt.debug) { errBox("SPServices.SPAutocomplete", "columnName: " + opt.columnName, "Column is not an input control or is not found on page"); return; } // Remove the which isn't needed and messes up the formatting columnObj.closest("span").find("br").remove(); columnObj.wrap(" "); // Create a div to contain the matching values and add it to the DOM var containerId = genContainerId("SPAutocomplete", opt.columnName); // myAdd изменен цвет на #2A8DD4 как в 2013 по умолчанию columnObj.after("
"); // Set the width to match the width of the input control $("#" + containerId).css("width", columnObjWidth); // Handle keypresses $(columnObj).keyup(function() { // Get the column's value var columnValue = $(this).val(); // Hide the container while we're working on it $("#" + containerId).hide(); // Have enough characters been typed yet? if (columnValue.length < opt.numChars) { return false; } // Show the the processingIndicator as a background image in the input element columnObj.css({ "background-image": "url(" + opt.processingIndicator + ")", "background-position": "right", "background-repeat": "no-repeat" }); // Array to hold the matched values var matchArray = []; // Build the appropriate CAMLQuery var camlQuery = ""; // Call GetListItems to find all of the potential values $().SPServices({ operation: "GetListItems", async: false, webURL: opt.WebURL, listName: opt.sourceList, CAMLQuery: camlQuery, CAMLQueryOptions: opt.CAMLQueryOptions, CAMLViewFields: " "; if (opt.CAMLQuery.length > 0) { camlQuery += " "; } camlQuery += "<" + opt.filterType + "> "; } camlQuery += "" + columnValue + " </" + opt.filterType + ">"; if (opt.CAMLQuery.length > 0) { camlQuery += opt.CAMLQuery + "", CAMLRowLimit: opt.CAMLRowLimit, completefunc: function(xData) { // Handle upper/lower case if ignoreCase = true var testValue = opt.ignoreCase ? columnValue.toUpperCase() : columnValue; // See which values match and add the ones that do to matchArray $(xData.responseXML).SPFilterNode("z:row").each(function() { var thisValue = $(this).attr("ows_" + opt.sourceColumn); var thisValueTest = opt.ignoreCase ? $(this).attr("ows_" + opt.sourceColumn).toUpperCase() : $(this).attr("ows_" + opt.sourceColumn); // Make sure we have a match... if (opt.filterType === "Contains") { var firstMatch = thisValueTest.indexOf(testValue); if ((firstMatch >= 0) && // ...and that the match is not already in the array if we want uniqueness (!opt.uniqueVals || ($.inArray(thisValue, matchArray) === -1))) { matchArray.push($(this).attr("ows_" + opt.sourceColumn)); } } else { // Handles normal case, which is BeginsWith and and other unknown values if (testValue === thisValueTest.substr(0, testValue.length) && // ...and that the match is not already in the array if we want uniqueness (!opt.uniqueVals || ($.inArray(thisValue, matchArray) === -1))) { matchArray.push($(this).attr("ows_" + opt.sourceColumn)); } } }); } }); // Build out the set of list elements to contain the available values var out = ""; // !myAdd if(matchArray.length==0){ matchArray.push(opt.htmlifnothingfound); } for (i = 0; i < matchArray.length; i++) { // If a highlightClass has been supplied, wrap a span around each match if (opt.highlightClass.length > 0) { // Set up Regex based on whether we want to ignore case var thisRegex = new RegExp(columnValue, opt.ignoreCase ? "gi" : "g"); // Look for all occurrences var matches = matchArray[i].match(thisRegex); var startLoc = 0; // Loop for each occurrence, wrapping each in a span with the highlightClass CSS class for (matchNum = 0; matchNum < matches.length; matchNum++) { var thisPos = matchArray[i].indexOf(matches[matchNum], startLoc); var endPos = thisPos + matches[matchNum].length; var thisSpan = "" + matches[matchNum] + ""; matchArray[i] = matchArray[i].substr(0, thisPos) + thisSpan + matchArray[i].substr(endPos); startLoc = thisPos + thisSpan.length; } } // Add the value to the markup for the container out += "
" + matchArray[i] + " "; } // Add all the list elements to the containerId container $("#" + containerId).html(out); // Set up hehavior for the available values in the list element // !myAdd if(matchArray[0] != opt.htmlifnothingfound) if(matchArray[0] != opt.htmlifnothingfound){ $("#" + containerId + " li").click(function() { $("#" + containerId).fadeOut(opt.slideUpSpeed); columnObj.val($(this).text()); }).mouseover(function() { var mouseoverCss = { "cursor": "hand", "color": "#ffffff", "background": "#3399ff" }; $(this).css(mouseoverCss); }).mouseout(function() { var mouseoutCss = { "cursor": "inherit", "color": columnObjColor, "background": "transparent" }; $(this).css(mouseoutCss); });} // If we've got some values to show, then show 'em! if (matchArray.length > 0) { // !myAdd delay(1000) $("#" + containerId).slideDown(opt.slideDownSpeed).delay(2000); } // Remove the processing indicator columnObj.css("background-image", ""); }); };
Просто замените код из библиотеки SPServices кодом выше.
Правда теперь и прикреплять автокомплит надо несколько иначе:
function AddAutoCompleteContractor() { console.log("Начало выполнения функции 'AddAutoCompleteContractor()"); //Добавляем autocomplete для поля "Наименование контрагента" $().SPServices.SPAutocomplete({ sourceList: "Contractors", sourceColumn: "Title", columnName: "Наименование контрагента", ignoreCase: true, filterType: "Contains", numChars: 3, slideDownSpeed: 400, htmlifnothingfound: "Ничего не найдено! <a href='#' onClick='ShowPopupContractor()'>Добавить?</a>", debug: true }); }Добавили опцию "htmlifnothingfound" - в ней указывайте html, который будет отображаться, если ничего не найдено.
Так же был изменен цвет, под 2013 и ширину, что бы вровень было. В 2013 padding появился.
Теперь нам необходимо добавить код, который покажет popup:
function ShowPopupContractor() { console.log("Начало выполнения функции 'ShowPopupContractor()"); $("#Anchor").append("Добавьте контрагента: "); $('#popupDivContractor').show(); SP.UI.ModalDialog.showModalDialog({ html: document.getElementById('popupDivContractor'), title: "Введите комментарий", allowMaximize: false, showClose: false, autoSize: true, dialogReturnValueCallback: onPopUpCloseCallBackContractor }); }
Дальше добавим функцию добавление элемента списка и колбэки, которые отработают при удачном\неудачном завершении процесса создания элемента:
function createListItemContractor() { console.log("Начало выполнения функции 'createListItemContractor()"); var clientContext = new SP.ClientContext(currentWebUrl); var oList = clientContext.get_web().get_lists().getByTitle('Contractors'); var itemCreateInfo = new SP.ListItemCreationInformation(); this.oListItem = oList.addItem(itemCreateInfo); oListItem.set_item('Title', $("#ContractorInput").val()); oListItem.update(); clientContext.load(oListItem); clientContext.executeQueryAsync( Function.createDelegate(this, this.onQuerySucceededСreateListItemContractor), Function.createDelegate(this, this.onQueryFailedСreateListItemContractor) ); } function onQuerySucceededСreateListItemContractor() { console.log("Начало выполнения функции 'onQuerySucceededСreateListItemContractor()"); console.log('Элемент создан: ' + oListItem.get_id()); } function onQueryFailedСreateListItemContractor(sender, args) { console.log("Начало выполнения функции 'onQueryFailedСreateListItemContractor()"); console.log('Ошибка при создании элемента. ' + args.get_message() + '\n' + args.get_stackTrace()); }
Теперь добавим функции, которые закрепим за кнопкой Добавить и Отмена.
При добавлении будет создавать элемент и закрытие формы, в случае нажатия по кнопке Отмена - только закрытие формы. Важно отметить, что в этих функциях мы сообщаем и результат для колбэка закрытия формы. Именно в колбэке логика по которой мы показываем уведомление.
function onPopUpCloseCallBackContractor(result, returnValue) { console.log("Начало выполнения функции 'onPopUpCloseCallBackContractor()"); $("nobr:contains('Наименование контрагента')").closest('tr').find("input").val(""); $("nobr:contains('Наименование контрагента')").closest('tr').find("input").keyup() if (result == SP.UI.DialogResult.OK) { SP.UI.Status.removeAllStatus(true); var sId = SP.UI.Status.addStatus("Контрагент добавлен!"); SP.UI.Status.setStatusPriColor(sId, 'green'); } else if (result == SP.UI.DialogResult.cancel) { SP.UI.Status.removeAllStatus(true); var sId = SP.UI.Status.addStatus("Вы не стали добавлять контрагента"); SP.UI.Status.setStatusPriColor(sId, 'yellow'); } } function closePopupOkContractor() { console.log("Начало выполнения функции 'closePopupOkContractor()"); createListItemContractor(); SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.OK, null); } function closePopupCancelContractor() { console.log("Начало выполнения функции 'closePopupCancelContractor()"); SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.cancel, null); }
Пример работы:
Александр, добрый день!
ОтветитьУдалитьОчень круто, спасибо!
а не мог бы ты выложить изменнный SPservices и скрипты формы в отдельных файликах, а то что то не получается прикрутить.
Здравствуйте! Что именно не выходит?
ОтветитьУдалитьЭто решение, используя SPServices autocomplete я сейчас не рекомендую использовать. Я решил использовать jQuery autocomplete, из-за его большей функциональности.