SharePoint 2013 - Need to Split Names from a Multi-Select People Picker - javascript

I'm working in SharePoint 2013, and I have created a custom display template for a Content Search Web Part. Three of my fields use multi-select people pickers, and all three are returning the names in one string as shown below:
Brown, JohnSmith, MikeJones, Mary
I want to return the names in the format shown below but I just can't seem to get it to work:
Brown, John; Smith, Mike; Jones, Mary
I've tried the advice from these blog articles:
https://social.msdn.microsoft.com/Forums/en-US/ea0fe2fe-0757-4c1c-b3cc-2dd99b38bfa1/sharepoint-2013-custom-display-template-people-picker-field-separate-multiple-names-in-display?forum=sharepointdevelopment
https://sharedpointtips.blogspot.com/2015/01/sharepoint-2013-display-template.html
http://www.dotnetmafia.com/blogs/dotnettipoftheday/archive/2014/02/26/useful-javascript-for-working-with-sharepoint-display-templates-spc3000-spc14.aspx
I've tried all the suggestions included in the first article - https://social.msdn.microsoft.com/Forums/en-US/ea0fe2fe-0757-4c1c-b3cc-2dd99b38bfa1/sharepoint-2013-custom-display-template-people-picker-field-separate-multiple-names-in-display?forum=sharepointdevelopment
In the Header:
'Response Preparer'{Response Preparer}:'ResponsePreparerOWSUSER'
In the body:
<script>
$includeLanguageScript(this.url, "~sitecollection/_catalogs/masterpage/Display Templates/Language Files/{Locale}/CustomStrings.js");
$includeScript(this.url, "~sitecollection/_catalogs/masterpage/Display Templates/Search/jquery-1.11.3.min.js");
$includeScript(this.url, "~sitecollection/_catalogs/masterpage/Display Templates/Search/splitNames.js");
RegisterSod('jquery-1.11.3.min.js', Srch.U.replaceUrlTokens("~sitecollection/_catalogs/masterpage/Display Templates/Search/jquery-1.11.3.min.js"));
RegisterSod('splitNames.js', Srch.U.replaceUrlTokens("~sitecollection/_catalogs/masterpage/Display Templates/Search/splitNames.js"));
//Register Dependencies
RegisterSodDep('splitNames.js', 'jquery-1.11.3.min.js');
AddPostRenderCallback(ctx, function () {
EnsureScriptFunc("splitNames.js", 'splitNames', function() {
var regulatorypartner = $getItemValue(ctx, "Regulatory Partner");
var splitregpartner = "";
splitregpartner = $splitNames(regulatorypartner);
});
});
</script>
In the JavaScript section I have tried this:
var regulatorypartner = ctx.RegulatoryPartnerOWSUSER;
var splitregpartner = splitNames(regulatorypartner);
This is my display code:
<td rowspan="2" colspan="4" style="text-align:center; border:0.5px solid #F88007;"> _#= splitregpartner =#_ </td>
The display should look like this:
Brown, John; Smith, Mike; Jones, Mary
Here is the output of regulatrypartner:
Brown, JohnSmith, MikeJones, Mary
Here is the splitNames code (file is included in the RegisterSod statement):
var newStr="";
for(var i=0;i<str.length;i++){
var char=str.charAt(i);
if(char==char.toUpperCase()){
newStr+=" "+char ;
}else{
newStr+=char;
}
}
return newStr;
}

Keep in your mind that it won't work for a person who has more then 2 capital letters in his name, there is no way to write something that works for all cases and converts to the format you are looking for unless you add an example for multiple words and unique names.
to_ReadableFormat("Brown, JohnSmith, MikeJones, Mary");
function to_ReadableFormat(regulatorypartner){
var counter = 0;
var fullString = "";
regulatorypartner.match(/[A-Z]/g).map(function (cap) { // loop through all the capitals
let regIndex = regulatorypartner.indexOf(cap);
if (counter != 0 && counter % 2 == 0) {
fullString += regulatorypartner.slice(0, regIndex) + ";";
regulatorypartner = regulatorypartner.slice(regIndex, regulatorypartner.length);
}
counter++;
});
fullString += regulatorypartner; // concat the remaining
return fullString;
}

Related

Get second, third and so on values

I have this problem here
The problem has been solved, but my question is how can I get the second value from that, or the third one. The sheet will have many tables and at some point I will need a total for each table. Also, is there any solution to automatically find the the array number which contain date row for each table (instead defining this manually). Hope my explanation make sense.
Thank you!
Kind regards,
L.E. Test file
If I understood your question correctly, instead of breaking the loop when a match to "Total" is found do whatever is needed to be done within the loop like so...
var today = toDateFormat(new Date());
var todaysColumn =
values[5].map(toDateFormat).map(Number).indexOf(+today);
var emailDate = Utilities.formatDate(new Date(today),"GMT+1",
"dd/MM/yyyy");
for (var i=0; i<values.length; i++){
if (values[i][0]=='Total'){
nr = i;
Logger.log(nr);
var output = values[nr][todaysColumn];
// Do something with the output here I"m assuming you email it
}
}
The loop will keep going and find every "Total" and do the same thing. This answer assumes that the "Totals" are in the same column. You can get fancier with this if you only want certain tables to send and not others, but this should get you started.
I didn't quite understand the second part of your question...
"Also, is there any solution to automatically find the the array
number which contain date row for each table (instead defining this
manually). Hope my explanation make sense."
I'm guessing you want all the rows that contain "Total" in the specific column. You could instantiate a variable as an empty array like so, var totals = [];. Then instead of sending the email or whatever in the first loop you would push the row values to the array like so, totals.push(nr+1) . //adding 1 gives you the actual row number (rows count from 1 but arrays count from 0). You could then simply loop through the totals array and do whatever you wanted to do. Alternatively you could create an array of all the values instead of row numbers like totals.push(values[nr][todaysColumn]) and loop through that array. Lots of ways to solve this problem!
Ok based on our conversation below I've edited the "test" sheet and updated the code. Below are my edits
All edits have been made in your test sheet and verified working in Logger. Let me know if you have any questions.
Spreadsheet:
Added "Validation" Tab
Edited "Table" tab so the row with "Email Address" in Column A lines up with the desired lookup values (dates or categories)...this was only for the first two tables as all the others already had this criteria.
Code:
Create table/category selector...
In the editor go to File >> New >> HTMLfile
Name the file "inputHTML"
Copy and paste the following code into that file
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form class="notice_form" autocomplete="off" onsubmit="formSubmit(this)" target="hidden_iframe">
<select id="tables" onchange="hideunhideCatagory(this.value)" required></select>
<p></p>
<select id="categories" style="display:none"></select>
<hr/>
<button class="submit" type="submit">Get Total</button>
</form>
<script>
window.addEventListener('load', function() {
console.log('Page is loaded');
});
</script>
<script
src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript">
// The code in this function runs when the page is loaded.
$(function() {
var tableRunner = google.script.run.withSuccessHandler(buildTableList);
var catagoryRunner = google.script.run.withSuccessHandler(buildCatagoryList);
tableRunner.getTables();
catagoryRunner.getCategories();
});
function buildTableList(tables) {
var list = $('#tables');
list.empty();
list.append('<option></option>');
for (var i = 0; i < tables.length; i++) {
if(tables[i]==''){break;}
list.append('<option>' + tables[i] + '</option>');
}
}
function buildCatagoryList(categories) {
var list = $('#categories');
list.empty();
list.append('<option></option>');
for (var i = 0; i < categories.length; i++) {
if(categories[i]==''){break;}
list.append('<option>' + categories[i] + '</option>');
}
}
function hideunhideCatagory(tableValue){
var catElem = document.getElementById("categories");
if(tableValue == "Total Calls By Date" || tableValue == "Total Appointments by Date"){
catElem.style.display = "none"
document.required = false;
}else{
catElem.style.display = "block"
document.required = true;
}
}
function formSubmit(argTheFormElement) {
var table = $("select[id=tables]").val(),
catagory = $("select[id=categories]").val();
console.log(table)
google.script.run
.withSuccessHandler(google.script.host.close)
.getTotal(table,catagory);
}
</script>
</body>
<div id="hiframe" style="display:block; visibility:hidden; float:right">
<iframe name="hidden_iframe" height="0px" width="0px" ></iframe>
</div>
</html>
Edits to Code.gs file
Replace code in Code.gs with this...
//This is a simple trigger that creates the menu item in your sheet
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Run Scripts Manually')
.addItem('Get Total','fncOpenMyDialog')
.addToUi();
}
//This function launches the dialog and is launched by the menu item
function fncOpenMyDialog() {
//Open a dialog
var htmlDlg = HtmlService.createHtmlOutputFromFile('inputHTML')
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setWidth(200)
.setHeight(150);
SpreadsheetApp.getUi()
.showModalDialog(htmlDlg, 'Select table to get total for');
};
//main function called by clicking "Get Total" on the dialogue...variables are passed to this function from the formSubmit in the inputHTML javascript
function getTotal(table,catagory) {
function toDateFormat(date) {
try {return date.setHours(0,0,0,0);}
catch(e) {return;}
}
//get all values
var values = SpreadsheetApp
.openById("10pB0jDPG8HYolECQ3eg1lrOFjXQ6JRFwQ-llvdE2yuM")
.getSheetByName("Tables")
.getDataRange()
.getValues();
//declare/instantiate your variables
var tableHeaderRow, totalRow, tableFound = false;
//begin loop through column A in Tables Sheet
for (var i = 0; i<values.length; i++){
//test to see if values have already been found if so break the loop
if(tableFound == true){break;}
//check to see if value matches selected table
if (values[i][0]==table){
//start another loop immediately after the match row
for(var x=i+1; x<values.length; x++){
if(values[x][0] == "Email Address"){ //This header needs to consistantly denote the row that contains the headers
tableHeaderRow = x;
tableFound = true;
}else if(values[x][0] == "Total"){
totalRow = x;
break;
}
}
}
}
Logger.log("Header Row = "+tableHeaderRow)
Logger.log("Total Row = "+ totalRow)
var today = toDateFormat(new Date())
var columnToTotal;
if(catagory==''){
columnToTotal = values[tableHeaderRow].map(toDateFormat).map(Number).indexOf(+today);
}else{
columnToTotal = values[tableHeaderRow].indexOf(catagory);
}
var output = values[totalRow][columnToTotal];
Logger.log(output);
var emailDate = Utilities.formatDate(new Date(today),"GMT+1", "dd/MM/yyyy");
//here is where you would put your code to do something with the output
}
/** The functions below are used by the form to populate the selects **/
function getTables(){
var cFile = SpreadsheetApp.getActive();
var cSheet = cFile.getSheetByName('Validation');
var cSheetHeader = cSheet.getRange(1,1,cSheet.getLastRow(),cSheet.getLastColumn()).getValues().shift();
var tabelCol = (cSheetHeader.indexOf("Tables")+1);
var tables = cSheet.getRange(2,tabelCol,cSheet.getLastRow(),1).getValues();
return tables.filter(function (elem){
return elem != "";
});
}
function getCatagories(){
var cFile = SpreadsheetApp.getActive();
var cSheet = cFile.getSheetByName('Validation');
var cSheetHeader = cSheet.getRange(1,1,cSheet.getLastRow(),cSheet.getLastColumn()).getValues().shift();
var catagoriesCol = (cSheetHeader.indexOf("Catagory")+1);
var catagories = cSheet.getRange(2,catagoriesCol,cSheet.getLastRow(),1).getValues();
return catagories.filter(function (elem){
return elem != "";
});
}

Finding the missing sequence number in a file

Hi I have to find a missing number in an xml file. but I feel difficulty to find. Pls suggest some ideas.
Example
A file contains an <a> tag which include id i.e page-1,2... I need to find the missing numbers using jquery.
a.xml
<p>have a great <a id="page-1"/>day. How are you.</p>
<p><a id="page-2"/>Have a nice day.</p>
<p>How <a id="page-5"/>are you</p>
<p>Life is so exciting<a id="page-6"/></p>
My code
<script>
$(document).ready(function() {
$("#find").click(function(){
Fname = $("#myFile").val();
lpage = $("#lpage").val();
$.get(Fname, function(data){
var lines = data.split("\n");
if (lines.match(id="page-)) { //how to use regular exoreessi0n
alert("hi");
}
});
});
});
</script>
I'll take some assumptions regarding your input. Please add validations as necessary:
var lines = ['<p>have a great <a id="page-1"/>day. How are you.</p>',
'<p><a id="page-2"/>Have a nice day.</p>',
'<p>How <a id="page-5"/>are you</p>',
'<p>Life is so exciting<a id="page-6"/></p>'];
var sequences = [];
lines.forEach(function(line) {
// Not efficient but simple
// Let jQuery parse this string to object, so we won't need regexp
var obj = $(line);
// Assuming there's always A and ID attribute
var id = obj.find("a").attr("id").split("-");
// Assuming sequence is always last
sequences.push(parseInt(id[id.length - 1]));
});
sequences.sort();
// Again, inefficient, but will do the job
var last = sequences[sequences.length - 1];
for (var i = last; i >= 0; i--) {
if (sequences.indexOf(i) < 0) {
console.log(i + " is missing");
}
}

Function to remove <span></span> from string in an json object array in JavaScript

I know there are many similar questions posted, and have tried a couple solutions, but would really appreciate some guidance with my specific issue.
I would like to remove the following HTML markup from my string for each item in my array:
<SPAN CLASS="KEYWORDSEARCHTERM"> </SPAN>
I have an array of json objects (printArray) with a printArray.header that might contain the HTML markup.
The header text is not always the same.
Below are 2 examples of what the printArray.header might look like:
<SPAN CLASS="KEYWORDSEARCHTERM">MOST EMPOWERED</SPAN> COMPANIES 2016
RECORD WINE PRICES AT <SPAN CLASS="KEYWORDSEARCHTERM">NEDBANK</SPAN> AUCTION
I would like the strip the HTML markup, leaving me with the following results:
MOST EMPOWERED COMPANIES 2016
RECORD WINE PRICES AT NEDBANK AUCTION
Here is my function:
var newHeaderString;
var printArrayWithExtract;
var summaryText;
this.setPrintItems = function(printArray) {
angular.forEach(printArray, function(printItem){
if (printItem.ArticleText === null) {
summaryText = '';
}
else {
summaryText = '... ' + printItem.ArticleText.substring(50, 210) + '...';
}
// Code to replace the HTML markup in printItem.header
// and return newHeaderString
printArrayWithExtract.push(
{
ArticleText: printItem.ArticleText,
Summary: summaryText,
Circulation: printItem.Circulation,
Headline: newHeaderString,
}
);
});
return printArrayWithExtract;
};
Try this function. It will remove all markup tags...
function strip(html)
{
var tmp = document.createElement("DIV");
tmp.innerHTML = html;
return tmp.textContent || tmp.innerText || "";
}
Call this function sending the html as a string. For example,
var str = '<SPAN CLASS="KEYWORDSEARCHTERM">MOST EMPOWERED</SPAN> COMPANIES 2016';
var expectedText = strip(str);
Here you find your expected text.
It can be done using regular expressions, see below:
var s1 = '<SPAN CLASS="KEYWORDSEARCHTERM">MOST EMPOWERED</SPAN> COMPANIES 2016';
var s2 = 'RECORD WINE PRICES AT <SPAN CLASS="KEYWORDSEARCHTERM">NEDBANK</SPAN> AUCTION';
function removeSpanInText(s) {
return s.replace(/<\/?SPAN[^>]*>/gi, "");
}
$("#x1").text(removeSpanInText(s1));
$("#x2").text(removeSpanInText(s2));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
1 ->
<span id="x1"></span>
<br/>2 ->
<span id="x2"></span>
For more info, see e.g. Javascript Regex Replace HTML Tags.
And jQuery is not needed, just used here to show the output.
I used this little replace function:
if (printItem.Headline === null) {
headlineText = '';
}
else {
var str = printItem.Headline;
var rem1 = str.replace('<SPAN CLASS="KEYWORDSEARCHTERM">', '');
var rem2 = rem1.replace('</SPAN>', '');
var newHeaderString = rem2;
}

Using Javascript replace with getElementsByClassName not working

I posted a question a few days ago which worked great and I thank those who helped but for reasons beyond my control I have to classes instead of id's as per my original post.
Basically what I am trying to do is remove the word "Other" from a string (The content is added dynamically through a form).
Here is the code I am trying to use:
var str = document.getElementsByClassName('gv-field-4-custom').innerHTML;
var text = str.replace("Other", " ");
document.getElementsByClassName('gv-field-4-custom').innerHTML = text;
.gv-field-4-custom {
color: #ff0000;
}
<table>
<tr>
<td class="gv-field-4-custom">Complex interventions, Evidence Synthesis (randomised trials), Studies within a Trial (SWAT), Trial Conduct, Trial Design, Other Core Outcome Sets (COS)</td>
</tr>
</table>
Any advise as to what I am doing wrong?
Your problem here is, that getElementsByClassName returns a set of elements, which in this particular case just contains a single element. If you just have a single element with this className, or just want to change one single element, you can go like this:
var element = document.getElementsByClassName('gv-field-4-custom')[0];
var str = element.innerHTML;
var text = str.replace("Other", " ");
element.innerHTML = text;
.gv-field-4-custom {
color: #ff0000;
}
<table>
<tr>
<td class="gv-field-4-custom">Complex interventions, Evidence Synthesis (randomised trials), Studies within a Trial (SWAT), Trial Conduct, Trial Design, Other Core Outcome Sets (COS)</td>
</tr>
</table>
If you have more elements that need a treatment, go like this:
var elements = document.getElementsByClassName('gv-field-4-custom');
for (var i = 0; i < elements.length; i++) {
var str = elements[i].innerHTML;
var text = str.replace("Other", " ");
elements[i].innerHTML = text;
}
.gv-field-4-custom {
color: #ff0000;
}
<table>
<tr>
<td class="gv-field-4-custom">Complex interventions, Evidence Synthesis (randomised trials), Studies within a Trial (SWAT), Trial Conduct, Trial Design, Other Core Outcome Sets (COS)</td>
</tr>
</table>
document.getElementsByClassName('gv-field-4-custom')
will returns an array.You cannot directly get the innerHtml.
use document.getElementsByClassName('gv-field-4-custom')[0].innerHtml to get the value.Use the below code
var str = document.getElementsByClassName('gv-field-4-custom')[0].innerHTML;
var text = str.replace("Other", " ");
Note the s in getElementsByClassName. It means you need to loop over these.
You can use either the code
var className= document.getElementsByClassName("gv-field-4-custom");
for(i=0;i<className.length;i++)
{
className[i].innerHTML = "text";
}
like #saina suggested, or use document.getElementsByClassName('gv-field-4-custom')[0] like #Imran suggested.
var str = document.getElementsByClassName('gv-field-4-custom')[0];
var oldText = str.innerHTML
var text = oldText.replace("Other", " ");
str.innerHTML = text;
try this:
document.getElementsByClassName('gv-field-4-custom')[0]
instead of
document.getElementsByClassName('gv-field-4-custom')

jQuery: modify html tables by changing number of columns

What's the easiest way to modify the html tables on the page with jQuery/javascript so that:
it contains the same data but has only two rows.
This is what is needed:
Table 1
City State Population Mayor Time zone
New York New York 8,405,837 Bill de Blasio UTC-5
Chicago Illinois 2,695,598 Rahm Emanuel UTC-6
Houston Texas 2,195,914 Annise Parker UTC-6
Table 2:
City New York
State New York
Population 8,405,837
Mayor Bill de Blasio
Time zone UTC-5
City Chicago
State Illinois
Population 2,695,598
Mayor Rahm Emanuel
Time zone UTC-6
City Houston
State Texas
Population 2,195,914
Mayor Annise Parker
Time zone UTC-6
This is what I have as for now and will continue working on it. It transposes the table: http://jsfiddle.net/0cm611xv/
$(".other").click(function(){
$("table").each(function() {
var $this = $(this);
var newrows = [];
$this.find("tr").each(function(){
var i = 0;
$(this).find("td").each(function(){
i++;
if(newrows[i] === undefined) { newrows[i] = $("<tr></tr>"); }
newrows[i].append($(this));
});
});
$this.find("tr").remove();
$.each(newrows, function(){
$this.append(this);
});
});
return false;
});
However, I need to modify the table in another manner - as described above and:
The table should switch to the previous state if the link clicked again.
All id, class names and attributes should be preserved and follow the value. As result, nothing is changed for the table if clicked on the link twice.
The number of columns and rows in the tables could be any. M x N table should be converted to 2 x (M*(N-1)) table upon clicking the link and 2 x (M*(N-1)) should be converted back to M x N by clicking the link again.
It should be done for each table on the page upon clicking the link.
I can ignore asking the SO and try to do it on my own but I believe it will take a lot of time to make it work and one person won't be able to find all bugs.
However, I believe this is an interesting task and this practical task could be useful for anyone else.
Had a go at this, and got a working example. In my example it changes the <table> to a <dl> as this is more semantically correct for the new layout.
jQuery
flag=0;
oldState = '';
$(".other").click(function(){
myDls = '';
if (flag == 0) {
// Clone the old table
oldState = $('#MyTable').clone(true);
// Change Table to dl,dt,dd
$('#MyTable tr').each(function(index){
// Itterate through the <td>s
$('td',this).each(function(index){
// Get the <th> for the current <td> column and change to <dt>
$(this).parent().parent().find('tr:first-child th:eq('+index+')').each(function(){
var replacementTagd = 'dt';
var outer = this.outerHTML;
var regex = new RegExp('<' + this.tagName, 'i');
newTagd = outer.replace(regex, '<' + replacementTagd);
regex = new RegExp('</' + this.tagName, 'i');
newTagd = newTagd.replace(regex, '</' + replacementTagd);
});
// Change <td> to <dd>
var replacementTag = 'dd';
var outer = this.outerHTML;
var regex = new RegExp('<' + this.tagName, 'i');
var newTag = outer.replace(regex, '<' + replacementTag);
regex = new RegExp('</' + this.tagName, 'i');
newTag = newTag.replace(regex, '</' + replacementTag);
// Append to variable
myDls += newTagd+newTag;
});
})
$('#MyTable').replaceWith('<dl id="MyDl">'+myDls+'</dl>');
flag=1;
}
else {
$('#MyDl').replaceWith(oldState);
flag=0;
}
});
Check out the jsfiddle - http://jsfiddle.net/L8z9bsv0/
Alex, thank you for your solution.
This is my solution (still in the middle, works for values and doesn't go back to the previous state yet):
$(".other").click(function(){
$("table").each(function() {
var $this = $(this);
var newrows = [];
var firstRow = $this.first("tr");
var rowsNum = firstRow.find("th").length;
var colNum = $this.find("tr").length;
//populate the first column
var j;
for (j=0; j< (colNum-1)*rowsNum; j++){
newrows[j] = $("<tr></tr>");
//newrows[j].append("<td>"+firstRow.find("th").eq(j%rowsNum).text()+"</td>");
newrows[j].append(firstRow.find("th").eq(j%rowsNum)[0].outerHTML);
}
var i = 0;
$this.find("tr:not(:first)").each(function(){
$(this).find("td").each(function(){
//newrows[i].append("<td>"+$(this).text()+"</td>");
newrows[i].append($(this)[0].outerHTML);
i++;
});
});
$this.find("tr").remove();
$.each(newrows, function(){
$this.append(this);
});
});
return false;
});

Categories

Resources