I have a list with a LOOKUP column to another list. The lookup column is called "Employee" and I want to GET the values from the "Employment Type" field. However I keep on getting a request error. What is wrong with my statement below. Before, I was only looking for choice and $ columns.Everything worked fine until I inserted the Employee/Employment_Type&$expand=Employee part
xhr.open('GET', _spPageContextInfo.webAbsoluteUrl + '/_api/web/lists/GetByTitle(\'' + listName +
'\')/items? $Funding$Funding_Type$Vacant&Direct&Employee/Employment_Type$select=ID,Employee/Employment_Type&$expand=Employee&$top=1000');
also, is my Employment_Type = results[i].Employee/Employment_Type syntax correct below?
Note: I am only including a small part of the overall script
for (var i = 0; i < results.length; i++){
if (results[i].Direct == "DCSP" & results[i].Funding == "A-Base") {
dcsp_abaseSal += results[i].SalEnv3
Employment_Type = results[i].Employee/Employment_Type
TypeSal = results[i].SalEnv3
dcsp_vacant_days += results[i].Vacant_Days
dcsp_variance = dcsp_abase_cap - dcsp_abaseSal
}
}
rest api get look up column:
/_api/web/lists/getByTitle('test3')/items(1)?$select=Title,columnTitle/Title&$expand=columnTitle
You could add columns which you want to get after $select like columnTitle/sourceColumnTitle
Related
When I attempt to get attributes from an element using the getAttributes() method from the Google Apps Script DocumentApp library for a Google Doc, not all attributes show up; specifically the GLYPH_TYPE attribute for a listItem element.
Due to the lack of functionality within Google Docs for checklists, I'm writing a code script to automatically calculate the percent completion of a list based on the symbol present of each list item belonging to a list. In order to do this, I am retrieving all listItems relevant to a listID, and then attempting to check their GLYPH_TYPE attribute in order to differentiate which items have been completed (which the user indicates by clicking the symbol left of the list item and changing it to a checkmark). It is the latter that I am having issues with; when I call getAttributes() for either the Paragraph or the listItem object for the list item, GLYPH_TYPE isn't present at all.
Here's a method where I am simply trying to extract the GLYPH_TYPE attribute for a listItem;
function getGlyphTypeFromListItem(documentId){
var doc =
DocumentApp.openById("1mzVQUccSH_suf8KoTkbVN4XjIOcfbYDuie3GV_M1Fg8");
var body = doc.getBody();
Logger.log(body.getParagraphs()[0].getAttributes());
Logger.log(body.getParagraphs()
[0].findElement(DocumentApp.ElementType.LIST_ITEM).getElement()
.getAttributes());
}
When I run this method I get the responses:
[19-01-20 18:22:02:242 MST] {FONT_SIZE=11, ITALIC=true, HORIZONTAL_ALIGNMENT=null, INDENT_END=null, INDENT_START=144.0,LINE_SPACING=null, LINK_URL=null, UNDERLINE=true,
BACKGROUND_COLOR=null, INDENT_FIRST_LINE=126.0, LEFT_TO_RIGHT=true,
SPACING_BEFORE=null, HEADING=Normal, SPACING_AFTER=null,
STRIKETHROUGH=null, FOREGROUND_COLOR=null, BOLD=true,
FONT_FAMILY=Roboto Condensed}
[19-01-20 18:30:21:253 MST] {FONT_SIZE=11, ITALIC=true,
HORIZONTAL_ALIGNMENT=null, INDENT_END=null, INDENT_START=144.0,
LINE_SPACING=null, LINK_URL=null, UNDERLINE=true, BACKGROUND_COLOR=null,
INDENT_FIRST_LINE=126.0, LEFT_TO_RIGHT=true, SPACING_BEFORE=null,
HEADING=Normal, SPACING_AFTER=null, STRIKETHROUGH=null, FOREGROUND_COLOR=null,
BOLD=true, FONT_FAMILY=Roboto Condensed}
As you can see, GLYPH_TYPE is completely absent from both of the logs; is there something I'm missing? Also, have any of you found a more intuitive way to track the completion of "checklists" within Google Docs?
Thank you in advance!
Google documentation says that the "Paragraph" getAtributes method (doc) "retrieves the element's attributes. The result is an object containing a property for each valid element attribute where each property name corresponds to an item in the DocumentApp.Attribute enumeration." GLYPH_TYPE is recorded as one of the properties of "Enum Attribute".
I agree with the OP that the GLYPH TYPE is not reported when a paragraph is analysed.
However if the Paragraph Type = DocumentApp.ElementType.LIST_ITEM, then getAttributes does report the GLYPH_TYPE, as well as some additional data (Refer image below). It is difficult to say whether there is a bug in the Google code, or (perhaps) an error in the documentation.
So far as the OP code is concerned, I got the same results.
But it's interesting to note a ListItem is returned by getParagraphs but a ListItem is NOT a 'paragraph'. ("A Paragraph may contain Equation, Footnote, HorizontalRule, InlineDrawing, InlineImage, PageBreak, and Text elements." (docs)). The getParagraphs method "retrieves all the Paragraphs contained in the section (including ListItems)" (docs). It's an odd, almost contradictory result, but I think this may be a reason why the OP's code was unsuccessful.
This was my code (adapted from the OP).
function so54282539() {
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
// variable to count the list#
var listcounter = 0;
// get the Paragraphs
var paras = doc.getParagraphs();
//Logger.log("DEBUG: paras = "+paras);//DEBUG
Logger.log("DEBUG:Number of paragraphs: " + paras.length); //DEBUG
// get the List Items
var lists = doc.getListItems();
//Logger.log("DEBUG: Lists: "+lists);//DEBUG
Logger.log("DEBUG: Number of lists: " + lists.length); //DEBUG
Logger.log(" "); //DEBUG
//Loop through the Paragraphs (i)
for (var i = 0; i < paras.length; i++) {
var mytypeof = paras[i].getType();
Logger.log("DEBUG: Paragraph#i=" + (i + 1) + ", Type: " + mytypeof); //DEBUG
// if thgis parapgraph is a list item, then get more information
if (mytypeof === DocumentApp.ElementType.LIST_ITEM) {
var paraattributes = paras[i].getAttributes();
// list the paragraph attributes
for (var key in paraattributes) {
if (paraattributes.hasOwnProperty(key)) {
Logger.log("Paragraph Attribute: " + key + " -> " + paraattributes[key]);
}
}
// List the GLPH TYPE
Logger.log("Glyph: " + lists[listcounter].getGlyphType());
var otherattributes = lists[listcounter].getAttributes();
// List the List_Item Attributes
for (var listkey in otherattributes) {
if (otherattributes.hasOwnProperty(listkey)) {
Logger.log("List_Item Attribute: " + listkey + " -> " + otherattributes[listkey]);
}
}
listcounter = listcounter + 1;
}
}
}
Typical Attribute comparison - Paragraph vs List_Item
List_Item Attributes
Document layout
I tried this:
function getGlyphType(){
var doc=DocumentApp.getActiveDocument();
var body=doc.getBody();
var children=body.getNumChildren();
var gA=[];
for(var i=0;i<children;i++){
var child=body.getChild(i);
if(child.getType()==DocumentApp.ElementType.LIST_ITEM){
gA.push(child.asListItem().getAttributes()['GLYPH_TYPE']);
}
var ui=HtmlService.createHtmlOutput(gA.join(', '));
DocumentApp.getUi().showModelessDialog(ui, 'Info')
}
}
I could get whether its a number or a bullet but I couldn't determine what type of bullet it was.
I created the following js function
function csvDecode(csvRecordsList)
{
var cel;
var chk;
var chkACB;
var chkAF;
var chkAMR;
var chkAN;
var csvField;
var csvFieldLen;
var csvFieldsList;
var csvRow;
var csvRowLen = csvRecordsList.length;
var frag = document.createDocumentFragment();
var injectFragInTbody = function () {tblbody.replaceChild(frag, tblbody.firstElementChild);};
var isFirstRec;
var len;
var newEmbtyRow;
var objCells;
var parReEx = new RegExp(myCsvParag, 'ig');
var tblbody;
var tblCount = 0;
var tgtTblBodyID;
for (csvRow = 0; csvRow < csvRowLen; csvRow++)
{
if (csvRecordsList[csvRow].startsWith(myTBodySep))
{
if (frag.childElementCount > 0)
{
injectFragInTbody();
}
tgtTblBodyID = csvRecordsList[csvRow].split(myTBodySep)[1];
newEmbtyRow = getNewEmptyRow(tgtTblBodyID);
objCells = newEmbtyRow.cells;
len = newEmbtyRow.querySelectorAll('input')[0].parentNode.cellIndex; // Finds the cell index where is placed the first input (Check-box or button)
tblbody = getElById(tgtTblBodyID);
chkAF = toBool(tblbody.dataset.acceptfiles);
chkACB = toBool(tblbody.dataset.acceptcheckboxes) ;
chkAN = toBool(tblbody.dataset.acceptmultiplerows) ;
tblCount++;
continue;
}
csvRecordsList[csvRow] = csvRecordsList[csvRow].replace(parReEx, myInnerHTMLParag); // Replaces all the paragraph symbols ¶ used into the db.csv file with the tag <br> needed into the HTML content of table cells, this way will be possible to use line breaks into table cells
csvFieldsList = csvRecordsList[csvRow].split(myEndOfFld);
csvFieldLen = csvFieldsList.length;
for (csvField = 0; csvField < csvFieldLen; csvField++)
{
cel = chkAN ? csvField + 1 : csvField;
if (chkAF && cel === 1) {objCells[cel].innerHTML = makeFileLink(csvFieldsList[csvField]);}
else if (chkACB && cel === len) {objCells[cel].firstChild.checked = toBool(csvFieldsList[csvField]);}
else {objCells[cel].innerHTML = csvFieldsList[csvField];}
}
frag.appendChild(newEmbtyRow.cloneNode(true));
}
injectFragInTbody();
var recNum = getElById(tgtTblBodyID).childElementCount;
customizeHtmlTitle();
return csvRow - tblCount + ' (di cui '+ recNum + ' record di documenti)';
}
More than 90% of records could contain file names that have to be processed by the following makeFileLink function:
function makeFileLink(fname)
{
return ['<a href="', dirDocSan, fname, '" target="', previewWinName, '" title="Apri il file allegato: ', fname, '" >', fname, '</a>'].join('');
}
It aims to decode a record list from a special type of *.db.csv file (= a comma-separated values where commas are replaced by another symbol I hard-coded into the var myEndOfFld). (This special type of *.db.csv is created by another function I wrote and it is just a "text" file).
The record list to decode and append to HTML tables is passed to the function with its lone parameter: (csvRecordsList).
Into the csv file is hosted data coming from more HTML tables.
Tables are different for number of rows and columns and for some other contained data type (which could be filenames, numbers, string, dates, checkbox values).
Some tables could be just 1 row, others accept more rows.
A row of data has the following basic structure:
data field content 1|data field content 2|data field content 3|etc...
Once decoded by my algorithm it will be rendered correctly into the HTML td element even if into a field there are more paragraphs. In fact the tag will be added where is needed by the code:
csvRecordsList[csvRow].replace(par, myInnerHTMLParag)
that replaces all the char I choose to represent the paragraph symbol I have hard-coded into the variable myCsvParag.
Isn't possible to know at programming time the number of records to load in each table nor the number of records loaded from the CSV file, nor the number of fields of each record or what table field is going to contain data or will be empty: in the same record some fields could contain data others could be empty. Everything has to be discovered at runtime.
Into the special csv file each table is separated from the next by a row witch contains just a string with the following pattern: myTBodySep = tablebodyid where myTBodySep = "targettbodydatatable" that is just a hard coded string of my choice.
tablebodyid is just a placeholder that contains a string representing the id of the target table tbody element to insert new record in, for example: tBodyDataCars, tBodyDataAnimals... etc.
So when the first for loop finds into the csvRecordsList a string staring with the string into the variable myTBodySep it gets the tablebodyid from the same row: this will be the new tbodyid that has to be targeted for injecting next records in it
Each table is archived into the CSV file
The first for loop scan the csv record list from the file and the second for loop prepare what is needed to compile the targeted table with data.
The above code works well but it is a little bit slow: in fact to load into the HTML tables about 300 records from the CSV file it takes a bit more of 2.5 seconds on a computer with 2 GB ram and Pentium core 2 4300 dual-core at 1800 MHz but if I comment the row that update the DOM the function needs less than 0.1 sec. So IMHO the bottle neck is the fragment and DOM manipulating part of the code.
My aim and hope is to optimize the speed of the above code without losing functionalities.
Notice that I'm targeting just modern browsers and I don't care about others and non standards-compliant browsers... I feel sorry for them...
Any suggestions?
Thanks in advance.
Edit 16-02.2018
I don't know if it is useful but lastly I've noticed that if data is loaded from browser sessionstorage the load and rendering time is more or less halved. But strangely it is the exact same function that loads data from both file and sessionstorage.
I don't understand why of this different behavior considering that the data is exactly the same and in both cases is passed to a variable handled by the function itself before starting checking performance timing.
Edit 18.02.2018
Number of rows is variable depending on the target table: from 1 to 1000 (could be even more in particular cases)
Number of columns depending on the target table: from 10 to 18-20
In fact, building the table using DOM manipulations are way slower than simple innerHTML update of the table element.
And if you tried to rewrite your code to prepare a html string and put it into the table's innerHTML you would see a significant performance boost.
Browsers are optimized to parse the text/html which they receive from the server as it's their main purpose. DOM manipulations via JS are secondary, so they are not so optimized.
I've made a simple benchmark for you.
Lets make a table 300x300 and fill 90000 cells with 'A'.
There are two functions.
The first one is a simplified variant of your code which uses DOM methods:
var table = document.querySelector('table tbody');
var cells_in_row = 300, rows_total = 300;
var start = performance.now();
fill_table_1();
console.log('using DOM methods: ' + (performance.now() - start).toFixed(2) + 'ms');
table.innerHTML = '<tbody></tbody>';
function fill_table_1() {
var frag = document.createDocumentFragment();
var injectFragInTbody = function() {
table.replaceChild(frag, table.firstElementChild)
}
var getNewEmptyRow = function() {
var row = table.firstElementChild;
if (!row) {
row = table.insertRow(0);
for (var c = 0; c < cells_in_row; c++) row.insertCell(c);
}
return row.cloneNode(true);
}
for (var r = 0; r < rows_total; r++) {
var new_row = getNewEmptyRow();
var cells = new_row.cells;
for (var c = 0; c < cells_in_row; c++) cells[c].innerHTML = 'A';
frag.appendChild(new_row.cloneNode(true));
}
injectFragInTbody();
return false;
}
<table><tbody></tbody></table>
The second one prepares html string and put it into the table's innerHTML:
var table = document.querySelector('table tbody');
var cells_in_row = 300, rows_total = 300;
var start = performance.now();
fill_table_2();
console.log('setting innerHTML: ' + (performance.now() - start).toFixed(2) + 'ms');
table.innerHTML = '<tbody></tbody>';
function fill_table_2() {// setting innerHTML
var html = '';
for (var r = 0; r < rows_total; r++) {
html += '<tr>';
for (var c = 0; c < cells_in_row; c++) html += '<td>A</td>';
html += '</tr>';
}
table.innerHTML = html;
return false;
}
<table><tbody></tbody></table>
I believe you'll come to some conclusions.
I've got two thoughts for you.
1: If you want to know which parts of your code are (relatively) slow you can do very simple performance testing using the technique described here. I didn't read all of the code sample you gave but you can add those performance tests yourself and check out which operations take more time.
2: What I know of JavaScript and the browser is that changing the DOM is an expensive operation, you don't want to change the DOM too many times. What you can do instead is build up a set of changes and then apply all those changes with one DOM change. This may make your code less nice, but that's often the tradeoff you have when you want to have high performance.
Let me know how this works out for you.
You should start by refactoring your code in multiples functions to make it a bit more readable. Make sure that you are separating DOM manipulation functions from data processing functions. Ideally, create a class and get those variables out of your function, this way you can access them with this.
Then, you should execute each function processing data in a web worker, so you're sure that your UI won't get blocked by the process. You won't be able to access this in a web worker so you will have to limit it to pure "input/output" operations.
You can also use promises instead of homemade callbacks. It makes the code a bit more readable, and honestly easier to debug. You can do some cool stuff like :
this.processThis('hello').then((resultThis) => {
this.processThat(resultThis).then((resultThat) => {
this.displayUI(resultThat);
}, (error) => {
this.errorController.show(error); //processThat error
});
}, (error) => {
this.errorController.show(error); //processThis error
});
Good luck!
I have not been able to find a working example or a good explanation of how I can achieve the following: (I would appreciate if anyone can point me in the right direction.
I have a query string: **"/api/bla?sources=[1,2]&plans=[1,2]&codes=[1,2,3]"**
I will be updating the query string via either javascript or jquery when certain events occur on my page, doesnt matter which.
For example, there is a multi select dropdown on the page which houses [sources] and [plans] and [codes]... These dropdowns have IDs which i am to update my request url with upons selecting items in teh dropdowns.
When a source with ID "3" is selected from the dropdown (or checkbox, doesnt matter what page controls are being used) the query string parameter sources[1,2] will need a "3" appended. Likewise then if the item with an ID of "2" is unselected, it will likewise be removed from the query string leaving the new string as sources[1,3]
I am somewhat new to javascript/jquery and especially more advanced string manipulation. I have been attempting to recreate something to demonstrate this and have gotten to the following which is not fully working.
Basically my initial if statement works as intended, but the moment the else is hit (when another ID needs to be added to an existing model in the query string - like a second ID for [sources] or [codes]) it returns wonky output - seeng as I couldnt get the right formula to update everything correctly.
//TIMEMTABLE QUERY
function updateCalendar(filter_id, filter_element) {
//Run through the filter checks before making final call to query and update timetable?
//GET THE MODEL/OBJECT NAME
var queryName = filter_element.attr('data-owner');
//GET THE IDs //this is either an array of all selected IDs or a single id which is used in the else statement
var queryId = filter_element.attr('value');
var queryIds = $('#'+filter_id).val();
var modelCheckIndex = requestString.toLowerCase().indexOf(queryName.toLowerCase());
//build a request string
if (modelCheckIndex < 0) {
console.info('ADD MODEL TO QUERY STRING');
requestString = requestString + "&" + (queryName.toLowerCase() + "[" + queryIds + "]");
console.log(requestString);
}
else{
console.info('UPDATE MODEL ON QUERY STRING');
var position = requestString.toLowerCase().indexOf(queryName.toLowerCase());
//requestString = requestString.substr(modelCheckIndex -1, requestString.length -1) + "," + queryId + "]";
requestString = requestString.slice(modelCheckIndex.indexOf("]"), modelCheckIndex) + "," + queryId;
console.log(requestString);
}
//MAKE THE API CALL USING CREATED QUERY STRING
}
If anyone has any examples or fiddles lying around I would also appreciate it.
Fiddle I am trying to get to work
It looks like you are just having trouble parsing and updating a query string. In which case, I have a function I've been using for that (thank you Google)
function getUriParams(string) {
var params = {},
queryString = string.slice(string.lastIndexOf('?')).substring(1),
regex = /([^&=]+)=([^&]*)/g,
m;
while (m = regex.exec(queryString)) {
params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
}
return params;
}
The input is your requestString and the output is an object of key value pairs of the query string.
To make the object a string, jQuery makes it easy with $.param().
//get key value pairs
var obj = getUriParams(requestString);
//make query string
var str = $.param(obj);
I suggest to change the logic a bit. I would use some data storage for the wanted parameter and rebuild the request string every time when it's necessary, like the below example.
It is much more better, than rebuild the string each time when some value has changed.
var data = {
sources: [1, 2],
plans: [],
codes: [1, 3, 4]
};
function buildStr() {
function get(key) { return key + '=' + JSON.stringify(data[key]); }
return '/api/bla?' + ['sources', 'plans', 'codes'].map(get).join('&');
}
document.write('<pre>' + buildStr() + '</pre>');
I am working with the google sites list item.
The classes are Here and Here
I have been able to iterate through the columns and put all of the column headers in to one array with the following code.
//Global
var page = getPageByUrl(enter URL here)
var name = page.getName();
function getInfo() {
var columns = page.getColumns();
//Get Column Names
for (var j in columns) {
var cName =columns[j].getName();
columnList.push(cName);
}
}
Now I want to be able to get each row of the listitem and put it in its own array.
I can add the variable
function getInfo() {
var columns = page.getColumns();
var listItems = page.getListItems();//new variable
//Get Column Names
for (var j in columns) {
var cName =columns[j].getName();
columnList.push(cName);
}
}
Now that I have the variable the output is [ListItem, ListItem, ListItem, ListItem]
So I can use a .length and get a return of 4.
So now I know I have 4 rows of data so based on my wants I need 4 arrays.
Small interjection here, Not a coder by trade but code as a precursor to wants becoming needs.
A buddy of mine who is a JS coder by trade showed me this code which does work. With the logger added by me.
for (var i in listItems) {
if (listItems.hasOwnProperty(i)) {
item = listItems[i];
for (var x = 0; x < columnList.length; x++) {
attrib = item.getValueByName(columnList[x]);
Logger.log("Logging value of get list page get value by name = " + columnList[x] + " " + attrib);
}
}
}
Which brings the total code to
var name = page.getName();
var listItems = page.getListItems();
var listCount = listItems.length
var listList = [];
var columns = page.getColumns();
var name = columns[0].getName();
var item, attrib = 0;
var columnList = [];
Logger.log(listItems);
Logger.log(name + " was last updated " + page.getLastUpdated());
Logger.log(name + " was last edited " + page.getLastEdited());
var listCount = 0;
//Get Column Names
for (var j in columns) {
var cName =columns[j].getName();
columnList.push(cName);
}
Logger.log(columnList);
// Get index of Due Date
var dueDateValue = columnList.indexOf("Due Date");
Logger.log("The index of due date is " + dueDateValue);
for (var i in listItems) {
if (listItems.hasOwnProperty(i)) {
item = listItems[i];
for (var x = 0; x < columnList.length; x++) {
attrib = item.getValueByName(columnList[x]);
Logger.log("Logging value of get list page get value by name = " + columnList[x] + " " + attrib);
}
}
}
}`
Forgive the above code as it has been a bit of a sketch pad trying to work this out.
I am a bit behind on understanding what is happening here
for (var i in items) { // This is for each item in the items array
if (items.hasOwnProperty(i)) {
if items is an array, how can we use has own property? Doesn't that belong to an object? Does an array become an object?
My questions are two category fold.
Category # 1
What is happening with the hasOwnProperty?
-Does the array become an object and thus can be passed to .hasOwnProperty value
Category # 2
Is this the only way to take the values from the listitem and populate an array
- If it is, is there some way to delimit so I can pass each row into it's own array
- If it isn't , why does it work with the hasOwnProperty and why doesn't it work without it in the example below
for (var i in listItems) {
for (var y = 0; y < columnList.length; y++) {
item = listItems[i];
listList = item.getValueByName(columnList[x]);
Logger.log("Logging my version of list naming " + listList);
}
In which I get a "Invalid argument: name (line 41" response. Highlighting the
listList = item.getValueByName(columnList[x]);
Not looking for a handout but I am looking to understand the hasOwnPropertyValue further.
My current understanding is that hasOwnValue has to do with prototyping ( vague understanding ) which doesn't seem to be the case in this instance
and it has to depend on a object which I described by confusion earlier.
To clarify my want:
I would like to have each row of listitems in its own array so I can compare an index value and sort by date as my current column headers are
["Project", "Start Date" , "End Date"]
Any and all help is much appreciated for this JS beginner of 2 weeks.
An array can be inside of an object as the value of a member:
{"myFirstArray":"[one,two,blue]"}
The above object has one member, a name/value pair, where the value of the member is an array.
Here is a link to a website that explains JSON.
Link To JSON.org
JSON explained by Mozilla
There are websites that will test the validity of an object:
Link to JSONLint.com
An array has elements, and elements in an array can be other arrays. So, there can be arrays inside of arrays.
.hasOwnProperty returns either true or false.
Documentation hasOwnProperty
Interestingly, I can use the hasOwnProperty method in Apps Script on an array, without an error being produced:
function testHasProp() {
var anArrayTest = [];
anArrayTest = ['one', 'two', 'blue'];
Logger.log(anArrayTest);
var whatIsTheResult = anArrayTest.hasOwnProperty('one');
Logger.log(whatIsTheResult);
Logger.log(anArrayTest);
}
The result will always be false. Using the hasOwnProperty method on an array doesn't change the array to an object, and it's an incorrect way of using Javascript which is returning false.
You could put your list values an object instead of an array. An advantage to an object is being able to reference a value by it's property name regardless of where the property is indexed. With an array, you need to know what the index number is to retrieve a specific element.
Here is a post that deals with adding properties to an object in JavaScript:
StackOverflow Link
You can either use dot notation:
objName.newProperty = 'newvalue';
or brackets
objName["newProperty"] = 'newvalue';
To add a new name/value pair (property) to an object.
I have an XML response from server (SOAP) and I'm getting multiple values in it. XPath extracts all the values and stores them internally like Match_1, Match_2, Match_3, etc.
But I can't access them neither via BSF Post Processor nor via JavaScript code pasted in XML. It just refuses to return values then I address to them like this: ${Match_1}.
Example:
Response returns multiple contentGroupID values.
Debug Sampler reveals them:
contentGroupID=67
contentGroupID_1=67
contentGroupID_2=50
contentGroupID_3=38
contentGroupID_4=54
contentGroupID_5=46
We need to use each of these values in the next single request, so we add a code inside XML in place where we need those values to sit:
${__javaScript
(myOutput =''; var names = {};
for (var i = 1; i <= ${contentGroupID_matchNr}; i++)
{names[i] = "${contentGroupID_" + i + "}";}
for (var j = 1; j <= ${contentGroupID_matchNr}; j++)
{myOutput =
myOutput + '<ns8:forContentGroupId><ns2:id>' + names[j] + '</ns2:id></ns8:forContentGroupId>';},
myOutput)
}
Here we place the part of XML with values <ns8:forContentGroupId><ns2:id>' + ids + '</ns2:id></ns8:forContentGroupId> as many times as matches were found by XPath.
But the magic does not happen. The request is sent as follows:
<ns8:forContentGroupId><ns2:id>${contentGroupID_1}</ns2:id></ns8:forContentGroupId>
<ns8:forContentGroupId><ns2:id>${contentGroupID_2}</ns2:id></ns8:forContentGroupId>
<ns8:forContentGroupId><ns2:id>${contentGroupID_3}</ns2:id></ns8:forContentGroupId>
<ns8:forContentGroupId><ns2:id>${contentGroupID_4}</ns2:id></ns8:forContentGroupId>
<ns8:forContentGroupId><ns2:id>${contentGroupID_5}</ns2:id></ns8:forContentGroupId>
The same happens in case I set BSF Post Processor with JavaScript code and add a variable in XML.
The question is: how the hell can one access those magical values?
P.S. Everything works great then I use ForEach Controller. But the trick is I need to make single request with all the values, not multiple requests one after another.
Found the solution here:
BSF Post Processor witch JavaScript code:
var myOutput = '';
var names = {};
var str;
var value = 0;
var match = vars.get("contentGroupID_matchNr");
for (var i = 1; i <= match; i++)
{
var n = i.toString();
str = 'contentGroupID_' + n;
value = vars.get(str);
names[i] = value;
}
for (var j = 1; j <= match; j++) {
myOutput = myOutput + '<ns8:forContentGroupId><ns2:id>' + names[j] + '</ns2:id></ns8:forContentGroupId>';
}
vars.put("array", myOutput);
Plus ${array} variable inside XML.
End of story! =)