Using Javascript to update a repeating section


Userlevel 4
Badge +7

Following on from this question Need to Copy a repeating section from a List-item to a repeating section to a different List-item?‌ raised by Pam Lewis‌ i thought i would blog my solution in case there were others with the same requirement.

 

Requirement:

 

ListA - Title column and repeating section.

ListB - Title column, lookup column and repeating section.

 

Create an item in ListA, update a repeating section with info as required. Save.

Create an item in ListB, from a lookup control, select the relevant item from ListA and the repeating section on ListB will be populated from the repeating section data from ListA.

 

Form from ListA:

The repeating section control is connected to a plain text multiline of text column.

The first text control in the repeating section has a name of dwgDimension.

The second text control in the repeating section has a name of ddOperation.

 

Form from ListB

The repeating section control is connected to a plain text multiline of text column with a name of rsdata and css class of rsdata.

The first text control in the repeating section has a name of dwgDimension.

The second text control int the repeating section has a name of ddOperation.

Under the Advanced section of the list lookup control set the Store Client ID in JavaScript variable to yes and add a variable name of varDropDown

Go to form settings and under Custom JavaScript add the following code:

 

NWF.FormFiller.Events.RegisterAfterReady(function () {
NWF$(document).ready(function () {
NWF$("#" + varDropdown).change(function () {
//clear repeating section
ClearRSData();
//get repeating section data
GetRSDataFromLookup();
});
});
});

function ClearRSData() {
//get the repeating section
var rsdata = NWF$('.rsdata');
//count number of fields to give number of rows
var labels = NWF$(rsdata).find('.dwgDimension');
//iterate through rows
NWF$.each(labels, function (index) {
//delete the last row
NWF$('.rsdata .nf-repeater-row:last').find('.nf-repeater-deleterow-image').click();
});
//for last row as index 0 row cannot be deleted
NWF$('.rsdata .nf-repeater-row:last').each(function () {
//get the row
var $row = NWF$(this);
//clear the field value
$row.find('.dwgDimension input').val('');
//clear the field value
$row.find('.ddOperation input').val('');
});
}

function GetRSDataFromLookup() {
//get the lookup value
var lookupId = NWF.RuntimeFunctions.parseLookup(NWF$('#' + varDropdown).val(), true);
//if lookup value is not null
if (lookupId != '') {
//clear jQuery error messages
NWF$('#errorMsg').empty();
//set the lookup list url to get repeating section xml data
var requestUri = _spPageContextInfo.webAbsoluteUrl + '/_api/Web/Lists/getByTitle('ListA')/items?$filter=Title eq '' + lookupId + ''';
try {
NWF$.ajax({
url: requestUri,
type: 'GET',
headers: { 'ACCEPT': 'application/json;odata=verbose' },
success: GetRSDataFromLookupSuccess,
error: GetRSDataFromLookupError
});
}
catch (err) {
//set error message
NWF$('#errorMsg').html('getListData Error: ' + err);
}
}

}

function GetRSDataFromLookupSuccess(data) {
//check the result set is not empty
if (data.d.results.length > 0) {
//get the xml data from the result
var rsdata = data.d.results[0].rsdata;
//intiate xml parser
parser = new DOMParser();
// populate the parser with the xml data
xmlDoc = parser.parseFromString(rsdata, 'text/xml');
//get the item tag from the xml
var items = xmlDoc.getElementsByTagName('Item');
//foreach item in the xml
for (var i = 0; i < items.length; i++) {
//get the repeating section last row
NWF$('.rsdata .nf-repeater-row:last').each(function () {
var $row = NWF$(this);
//set the field value
$row.find('.dwgDimension input').val(xmlDoc.getElementsByTagName('dwgDimension')[i].childNodes[0].nodeValue);
//set the field value
$row.find('.ddOperation input').val(xmlDoc.getElementsByTagName('ddOperation')[i].childNodes[0].nodeValue);
});
//add new row
NWF$('.rsdata').find('a').click();
}
//delete extra unnecessary row
NWF$('.rsdata .nf-repeater-row:last').find('.nf-repeater-deleterow-image').click();
}
} function GetRSDataFromLookupError() {
alert('Failed to load Lookup Items');
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

 

Fistly we register the function to the change event of the lookup field.

Then we clear any data from the repeating section (allows for changes in the lookup value)

Then we populate from the repeating section of the first List

 

Save and publish both forms.

 

Item 1 from ListA

 

Item 2 From ListA

 

New item from ListB

Change lookup value

 

Now you have a dynamically updating repeating section depending on the item selected in the lookup

 

Any questions, let me know.

 

Paul

 

nintex forms ;‌ repeating sections‌ javascript‌ custom javascript‌


25 replies

Badge +2

Paul,

Thank you for your post!  I have a similar scenario that I'm hoping you could shed some light on.  List B associates more than one (multi-value) lookup item from List A.  On the List B form, when a list item is added to the selected Contacts (in my example) I'd like the repeating section to perform the lookup either on List A or the associated lookup column in List B.  

List A (Contacts) includes text columns with contact details

List B includes a multi-value lookup on Contacts, so one record in List B is associated with multiple contacts. 

 

Given your Javascript above, this scenario seems similar.  How to you parse the mutli-values that are moved to the box on the right?

Thanks in advance!

Katie

Badge +4

thank you Paul... works like a charm!! fantastically awesome...

Pam,

I was unsuccessful at getting the example to work. Would you be willing to share the files?

Badge +4

Hi.. Paul --  how could I use this process - dynamic repeating section - in multiple repeating sections on a ListB/Item form? I have a form with 2 repeating sections (right now max = 8 sections); using a drop down lookup selection from the ListA/Item, choosing a different item for each repeating section.  Can this be done within the JS ? 

Badge +4

Hi Fred,  following Paul's steps works, just be sure to change the file/link values in his code to yours and the column names need to match your names. 

Userlevel 4
Badge +7

Hi Pam Lewis

If I'm not wrong it is very similar to your first requirement?

If so then you would replicate the script to have 2 complete versions of it within the same form. You would just need to make sure that the controls and panels etc were named differently and the functions were named differently

eg:

NWF.FormFiller.Events.RegisterAfterReady(function () {
NWF$(document).ready(function () {
NWF$("#" + varDropdown1stLookup).change(function () {
//clear repeating section1
ClearRSData1stRepeatingSection();
//get repeating section data
GetRSDataFromLookup1stRepeatingSection();
 });

NWF$("#" + varDropdown2ndLookup).change(function () {//clear repeating section2
ClearRSData2ndRepeatingSection();
//get repeating section data
GetRSDataFromLookup2ndRepeatingSection();

 });
});

function ClearRSData1stRepeatingSection() {
//get the repeating section
var rsdata1 = NWF$('.rsdata1stRepeatingSection');
//count number of fields to give number of rows
var labels = NWF$(rsdata1).find('.dwgDimension1stRepeatingSection');

...................

function ClearRSData2ndRepeatingSection() {
//get the repeating section
var rsdata2 = NWF$('.rsdata2ndRepeatingSection');
//count number of fields to give number of rows
var labels = NWF$(rsdata2).find('.dwgDimension2ndRepeatingSection');

...................

etc etc etc.

Hope this helps

Let me know if you have any problems

Badge +4

thankyou... I thought it had to be something like that.. I'm going attempt to put 'if-elseif'.. around them based on column values not equal to blanks..  around them... I'm at 'intro' level to JS!  

Userlevel 4
Badge +7

Hahaha, we all started at the beginning!!!!

Badge +4

Hi Paul,

ok.. I tried the code addition above (outcome -> no good or nothing) and decided since the 2nd repeating section will read/pull from the same List as the 1st repeating section, there is a possible naming problem.  Maybe due to the column names need to be the same on both lists for the repeating section to populate.  Is there a way to connect List A (lookup/reading from) to the 2nd or 3rd, etc. repeating sections on List B (copied to) same field/column names? 

Badge +3

Hi Paul, 

thanks for that post - great work!

Only thing is not working for me is to delete the values of the last row. 

NWF$('.XMLSpecifications .nf-repeater-row:last').each(function () {
//get the row
var $row = NWF$(this);
//clear the field value
$row.find('.classMaterial').val('');
$row.find('.classUnit').val('');
$row.find('.classQuantity').val('');
});

Should that also work on lookup fields? 

BR, Rubi

Badge +1

Hi!

Do you mean that you have an empty section at the end?

Best,

Florian

Userlevel 2
Badge +11

This indeed happens to me if there is more than 1 row; for 1 row it works properly. Even worse, not only are all rows gone, the controls below the repeating section get messed up as well.

I've put an alert in the $NWF$.each of the ClearRSData() and for an empty rs it gives 2 alerts (index=0 and index=1); there's a hidden row that seems to be included and I'm wondering if the code in this post takes this into account?

NB: I'm using this functionality to copy metadata from another item (query in js using various filters) after selecting it and pressing a Copy Metadata button.

Badge +1

Hi,

NWF$('.repStores .nf-repeater-row:last').find('.nf-repeater-deleterow-image').click();

 

I think thisone would help you to delete the last empty row.

let me know if this helps you.

Regards

Userlevel 2
Badge +11

Thank you Florian,

My scenario would be a bit like this:

  1. user creates a new item
  2. user fills 3 rows with data in the repeating section
  3. then the user has a change of heart and on the Copy Metadata panel set several filters, selects one exiting item from the filtered dropdown list and presses the Copy Metadata  It is here that I need to clear 2 repeating sections and (not yet implemented) populate them again with existing data from the selected item.

The current reset of the repeating section, using the click() event, deletes all rows.....

It feels to me as if the repeating section in Nintex 2013 Forms v2.11.2.2 works slightly different.........

EDIT: the last row does not need to be deleted, only the values emptied as intended in the code in this post.

EDIT 2: reason why the code is misbehaving in my case is because the panel containing the repeating section is hidden..... So I'll have to temp show it, update it and hide it again.

EDIT 3: temporarily showing the panels did indeed resolve my issue.

Badge

Hi,

I have similar requirement but I just want one field from repeating sectionA(Form a) to be update in repeating sectionB(form b), and this 2nd repeating section has some other fields which need not be update, those will be entered by user.

Can somebody will give some insight how should i update this?

BR/Sonam 

Badge +2

Hi Paul,

I tried your script and i am unable to run it. When i execute the code, it goes directly into error header. Can you help me out.

Userlevel 2
Badge +11

Did anyone figure out how to set the value of a list lookup field in a repeating section? I'm getting as far as setting it based on the item's ID, but on saving the form the validation rules still reports that these lookups are missing a value. The JS snippet I'm currently using is:

$currRow.find("." + currFieldLabel + " select.nf-client-control").val(currFieldValue);

Considering the fact that outside a repeating section one also has to set the Selected attribute, I would guess this is also required within the repeating section. Whatever I try, it does not seem I've found the proper command setup.

NB: I'm copying from another item using a (JS) query which only returns a list lookup ID value (and thus not also the display value). Using the following snippet did not work for me to set the selected value of my list lookup in the repeating section:

var tmpDispVal = NWF.RuntimeFunctions.SPLookup("Currencies","ID",currFieldValue,"Currency").done(function(data) {

    $currRow.find("." + currFieldLabel + " option:contains(" + data +")").attr("selected", true);

});

Also, SPLookup seems to be async..... So any info on a sync version of calling the inline function lookup() from JavaScript would also be welcome.

Badge +5

Hi Paul Crawford, thanks for this wonderful solution. I really like the clean code.

Not sure if you're still monitoring this but I have one question.

In my solution I'm using a list lookup control in the repeating section. This is setup on both lists so that they marry up. They work perfectly in populating the repeating section, however when I save the item the values aren't committed to the multi-line text field XML. All other values are visible in the XML except for the lookup values.

I need a way to commit the value to the lookup field after the jQuery has populated it. I've tried applying ProcessOnChange after setting the lookup field but this doesn't have any effect:

NWF.FormFiller.Functions.ProcessOnChange(NWF$(.ItemType));

Any advice would be appreciated.

Badge +5

I found the solution here: https://community.nintex.com/thread/12582#comment-46255 

I just needed to add a change event after updating the lookup field:

for (var i = 0; i < items.length; i++) {
//get the repeating section last row
NWF$('.ItemsClass .nf-repeater-row:last').each(function() {
var $row = NWF$(this);
//set the field values
$row.find('.ItemType select').val(xmlDoc.getElementsByTagName('.ItemType')[i].childNodes[0].nodeValue);
$row.find('.ItemType select').change();
});
//add new row
NWF$('.Items').find('a').click();
}‍‍‍‍‍‍‍‍‍‍‍
Userlevel 4
Badge +7

Send me your form and I can have a look

Paul

Get Outlook for iOS<https://aka.ms/o0ukef>

Badge +5

Thanks Paul, i found the solution shortly after asking the question  

I needed to add a change event after updating the lookup field. I posted the code in the response above.

Appreciate you coming back to me  

Hi Paul

When i tried to use the ClearData() function it removes all the row in repeating section.

Hi Paul

 

Thank you very much for your instructions. I was able to successfully adapt them to my Nintex Forms form for an external list on SharePoint Server 2016.

Unfortunately, I was not yet able to fulfill all the needs with your instructions. Do I get it correctly that on your print screens below their title "Item 1 from ListA" and "Item 2 from ListA" are from the form in display mode? If so, how did you get this working? I mean, in display mode there is obviously no button that the JavaScript code can click to add a new repeating section row. However, I would like to fill the repeating section in display mode also with the results of a REST API request.

 

I thank you or someone else's help in advance.

 

Best regards

Paul

Badge +1

Hi @paul_crawford,


 


What if I have 1 single line of text field and 2 date and time fields? Will this work with the date fields? I know I will have to include the 3rd control in the code above, but I am not sure how the date fields affect the solution. 


 


Thanks,

Badge +4

@paul_crawford The commenting in this code, not to mention it's functionality, make this a great example of using jQuery with Nintex. Thanks!


 


Since the Nintex forum has reformatted the code to be almost unrecognisable I will repost here (unedited) in the hopes that it may be readable (all credit to @paul_crawford)


 


NWF.FormFiller.Events.RegisterAfterReady(function () {
NWF$(document).ready(function () {
NWF$("#" + varDropdown).change(function () {
//clear repeating section
ClearRSData();
//get repeating section data
GetRSDataFromLookup();
});
});
});

function ClearRSData() {
//get the repeating section
var rsdata = NWF$('.rsdata');
//count number of fields to give number of rows
var labels = NWF$(rsdata).find('.dwgDimension');
//iterate through rows
NWF$.each(labels, function (index) {
//delete the last row
NWF$('.rsdata .nf-repeater-row:last').find('.nf-repeater-deleterow-image').click();
});

//for last row as index 0 row cannot be deleted
NWF$('.rsdata .nf-repeater-row:last').each(function () {
//get the row
var $row = NWF$(this);
//clear the field value
$row.find('.dwgDimension input').val('');
//clear the field value
$row.find('.ddOperation input').val('');
});
}

function GetRSDataFromLookup() {
//get the lookup value
var lookupId = NWF.RuntimeFunctions.parseLookup(NWF$('#' + varDropdown).val(), true);
//if lookup value is not null
if (lookupId != '') {
//clear jQuery error messages
NWF$('#errorMsg').empty();
//set the lookup list url to get repeating section xml data
var requestUri = _spPageContextInfo.webAbsoluteUrl + '/_api/Web/Lists/getByTitle('ListA')/items?$filter=Title eq '' + lookupId + ''';
try {
NWF$.ajax({
url: requestUri,
type: 'GET',
headers: {
'ACCEPT': 'application/json;odata=verbose'
},
success: GetRSDataFromLookupSuccess,
error: GetRSDataFromLookupError
});
}
catch (err) {
//set error message
NWF$('#errorMsg').html('getListData Error: ' + err);
}
}
}

function GetRSDataFromLookupSuccess(data) {
//check the result set is not empty
if (data.d.results.length > 0) {
//get the xml data from the result
var rsdata = data.d.results[0].rsdata;
//intiate xml parser
parser = new DOMParser();
// populate the parser with the xml data
xmlDoc = parser.parseFromString(rsdata, 'text/xml');
//get the item tag from the xml
var items = xmlDoc.getElementsByTagName('Item');
//foreach item in the xml
for (var i = 0; i < items.length; i++) {
//get the repeating section last row
NWF$('.rsdata .nf-repeater-row:last').each(function () {
var $row = NWF$(this);
//set the field value
$row.find('.dwgDimension input').val(xmlDoc.getElementsByTagName('dwgDimension')[i].childNodes[0].nodeValue);
//set the field value
$row.find('.ddOperation input').val(xmlDoc.getElementsByTagName('ddOperation')[i].childNodes[0].nodeValue);
});
//add new row
NWF$('.rsdata').find('a').click();
}
//delete extra unnecessary row
NWF$('.rsdata .nf-repeater-row:last').find('.nf-repeater-deleterow-image').click();
}
}

function GetRSDataFromLookupError() {
alert('Failed to load Lookup Items');
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

 


 


 

Reply