Solved

Set Repeating Section Value with JS

  • 20 August 2021
  • 9 replies
  • 580 views

Badge +8

hello there,


I have a tricky question and I have made an example nintex-form (classic) so I can show you my problem.


For my example I have following controls:


1. Number (it is a specific number which is unique)


2. Every number is assigned to a group of animals


3. and every animal has specific values (name, born on, colour) and there can be more than one of its kind (therefore a repeating section)... it is just an example and I couldnt think of something better


important: the data of the repeating section is saved to a multiple lines field (I already connected them).

 

19339i384C0EA447394FC0.png

 

 

At first I create an item:

 

19340i8C22A4DFC47F9B90.png

 

and in the list it looks like this:

 

19341iF55285304584ECC5.png

 

So what do I want?


I have a wiki page and on that page I have a webpart where users can fill out a NEW form (they cant see the list, they can just fill out the form).

If a user enters a number (in my example 1)... then via some formulars the values from the list should be autofilled with javascript so that the user can see the animals an then in the repeating section all of the other values.... and there is the problem.


I know how to do that with normal textboxes:

 

create a formular field and create a lookup with an JS function:

"setAnimals(Nachschlagen("Repeating Section", "Number", Number, "Animals"))"


..assign that textbox a JS Var (varAnimals)

 

and put the function into the settings -- custom JS

 

function setAnimals(Animals) {NWF$('#' + varAnimals).val(Animals).trigger('blur');}   


And that works fine.


...but I dont know how to do that with the repeating section...I got the informations in the list so i could look them up... but... how?


another important note is that the user can change the numbers... so the values should change appropriately.. if he enters a "2" then other values should show up (that already works with textboxes, date, dropdowns etc...hopefully it is possible with repeating sections aswell)


and ofcourse thats just an example .. my orginal form is way to big and confusing so i tried to reduce it to the essentials


regards,

Alex


and because I dont know how to tag a person I am going to try this: @MegaJerk

icon

Best answer by Aleximo 31 August 2021, 14:07

View original

9 replies

Badge +8

update:


 


I found this post:


 


https://community.nintex.com/t5/Community-blogs/Using-Javascript-to-update-a-repeating-section/ba-p/82584


 


but he uses a lookup on another list and not a textbox on the same list as I do... i tried to change the code but my code does nothing EXECPT adding one empty row to the repeating section???


 


here are the variables I use:


 


rsdate = MULTIKostenstellen


 


varDropDown = varFOMAID


 


dwgDimensio = KostenstellenNr


 


ddOperation = KostenstellenWissenschaftler


 


and I added a few more fields


 


because I have a textfield and not a lookup I changed the code to this:


 


var lookupId = NWF$('#' + varFOMAID).val();


 


instead of:


 


var lookupId = NWF.RuntimeFunctions.parseLookup(NWF$('#' + varDropdown).val(), true);


 


 


here is the modified code:


 


 


 


NWF.FormFiller.Events.RegisterAfterReady(function () {
NWF$(document).ready(function () {
NWF$("#" + varFOMAID).change(function () {
ClearRSData();
GetRSDataFromLookup();
});
});
});

function ClearRSData() {
var MULTIKostenstellen = NWF$('.MULTIKostenstellen');
var labels = NWF$(MULTIKostenstellen).find('.KostenstellenNr');
NWF$.each(labels, function (index) {
NWF$('.MULTIKostenstellen .nf-repeater-row:last').find('.nf-repeater-deleterow-image').click();
});

NWF$('.MULTIKostenstellen .nf-repeater-row:last').each(function () {
var $row = NWF$(this);
$row.find('.KostenstellenNr input').val('');
$row.find('.KostenstellenWissenschaftler input').val('');
$row.find('.KostenstellenZusatz input').val('');
$row.find('.KostenstellenDatum input').val('');
$row.find('.KostenstellenStandderKS input').val('');
$row.find('.KostenstelleBemerkung input').val('');
});
}

function GetRSDataFromLookup() {
var lookupId = NWF$('#' + varFOMAID).val();
if (lookupId != '') {
NWF$('#errorMsg').empty();
var requestUri = _spPageContextInfo.webAbsoluteUrl + '/_api/Web/Lists/getByTitle('AG3 Programm')/items?$filter=Title eq '' + lookupId + ''';
try {
NWF$.ajax({
url: requestUri,
type: 'GET',
headers: {
'ACCEPT': 'application/json;odata=verbose'
},
success: GetRSDataFromLookupSuccess,
error: GetRSDataFromLookupError
});
}
catch (err) {
NWF$('#errorMsg').html('getListData Error: ' + err);
}
}
}

function GetRSDataFromLookupSuccess(data) {
if (data.d.results.length > 0) {
var MULTIKostenstellen = data.d.results[0].MULTIKostenstellen;
parser = new DOMParser();
xmlDoc = parser.parseFromString(MULTIKostenstellen, 'text/xml');
var items = xmlDoc.getElementsByTagName('Item');
for (var i = 0; i < items.length; i++) {
NWF$('.MULTIKostenstellen .nf-repeater-row:last').each(function () {
var $row = NWF$(this);
$row.find('.KostenstellenNr input').val(xmlDoc.getElementsByTagName('KostenstellenNr')[i].childNodes[0].nodeValue);
$row.find('.KostenstellenWissenschaftler input').val(xmlDoc.getElementsByTagName('KostenstellenWissenschaftler')[i].childNodes[0].nodeValue);
$row.find('.KostenstellenZusatz input').val(xmlDoc.getElementsByTagName('KostenstellenZusatz')[i].childNodes[0].nodeValue);
$row.find('.KostenstellenDatum input').val(xmlDoc.getElementsByTagName('KostenstellenDatum')[i].childNodes[0].nodeValue);
$row.find('.KostenstellenStandderKS input').val(xmlDoc.getElementsByTagName('KostenstellenStandderKS')[i].childNodes[0].nodeValue);
$row.find('.KostenstelleBemerkung input').val(xmlDoc.getElementsByTagName('KostenstelleBemerkung')[i].childNodes[0].nodeValue);
});
NWF$('.MULTIKostenstellen').find('a').click();
}
NWF$('.MULTIKostenstellen .nf-repeater-row:last').find('.nf-repeater-deleterow-image').click();
}
}

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

 


 


 


any ideas?


 

Userlevel 5
Badge +14

I've looked at this problem and it's pretty large. Frankly, it would take a lot of time to develop / test something like this, so instead of getting your hopes up, let me ask you another question: 

What is the purpose of solving this problem in this way?


 


I ask this because the way you'd like to do this is very difficult, and if there is something preventing you from accomplishing the same outcome, but in a different way, perhaps we can solve the problems surrounding that instead of trying to 'reinvent the wheel' so to speak.


 


To expand: 


 


What is the end goal of this method of data entry?


 


Is there a reason people couldn't just use the forms that exist elsewhere with the data already on them?


 


Could we just prevent them from changing *existing* data, instead of trying to move Repeating Rows around?


 


There are a few more Questions I have, but I think this is a good starting point as it will help to narrow stuff down. 

Badge +8

I have already a few formulars that work like that.. but all of them never had repeating sections... so thats why I am here 😃.


 


I want to have an overlay for the users, so they can just edit data .. start workflows...save it ... and continue... and that all from one formular on a wiki page. (imagine skipping through a list  via a formular just by entering a ID and everything autofills in the formular so u have it nice and neat)


 


the new formular I have created is for the group who works with finances and they have to use repeating section (to calculated multiple values or to add multiple new colleagues with different informations).


 


I know that this is kind of a specific topic but I have to find a solution for that.


 


And the post from paul_crawford is (exept for the lookup and 2 lists) exactly what I need.


 


I thought it would be doable with just a few changes to the code.

Userlevel 5
Badge +14

Well that sounds interesting. I can't speak for the rest of their code, but if you just wanna target a Lookup Control inside of a Repeating Section (or any control for that matter), then you'll just need to NOT use the built in variable ID reference because it doesn't work. Instead I suggest relying on the Control Name, as it's straight forward to use.


 


Here is an example form with a RS section and Lookup Control called "control_Fruit":



 


If I Preview the Form and then look at the HTML in the Dev Console, you'll see that the outermost container of the control has an attribute on it called "data-controlname" with a value that is equal to the Control Name we gave it: 



 


Using this, we can target the control using the following selector: 


NWF$("[data-controlname='control_Fruit']");

 


But wait a second! 


 


Doing this will return Two (or more!) Controls!



 


The reason for this is that when a Repeating Section is being generated, it first HIDES the original version with all of the controls / IDs, and then copies from that every time a new Row is needed. Even though there is only ONE visible Row on my form, there are TWO controls named "control_fruit" because one is hidden.


 


We can find only the "active" controls by changing our selector a bit to: 


NWF$(".nf-repeater-row:not" + "(.nf-repeater-row-hidden) [data-controlname='control_Fruit']")

(note: why did I concatenate two strings at the "not"? because Nintex Forms will automatically check any code (that's not referenced as a file) and *replace* certain keywords that are immediately followed by an open parenthesis "(" into its internal custom function call instead. Because "not(" is one of those words, if I don't do something to break that apart, then it gets turned into something else and breaks the jquery!)


 


Now that returns only the controls from the visible rows, which in this case is 1.


 


But what if you have more than one row? 



 


Well you can either directly target a specific row using the [index] or you can iterate through the RS Rows and do work to each control.


 


Let's say we wanna select only the Second Row's Fruit Lookup. We could do this:


NWF$(NWF$(".nf-repeater-row:not" + "(.nf-repeater-row-hidden) [data-controlname='control_Fruit']")[1])

 


Notice that to get the 2nd Row I'm using an Index of [1]. That's because the indexes start at 0, so row 1 is index[0]!


 


But if I wanted to do work to every Fruit control in every row, then we could just iterate through them like:


NWF$(".nf-repeater-row:not" + "(.nf-repeater-row-hidden)").each(function(index, row){
row = NWF$(row);
var fruitControl = row.find("[data-controlname='control_Fruit']");
console.log(fruitControl.find(".nf-associated-control").val());
});

 


let's say though that I want to actually change the value of the control. Well, targeting is much the same, except we'll be making sure to change the value of the internal <select> element instead of anything else. Because the visible client <select> element has the class of "nf-client-control", we can just target that. But <select> element values aren't set on that element as they are just really a "container" for <option> elements. The "selected" option will have a property named "selected" set to true if it is. So using that info, if we wanted to change the value of our Fruit Control in the second row, we could use the following formula:


NWF$(NWF$(".nf-repeater-row:not" + "(.nf-repeater-row-hidden) [data-controlname='control_Fruit']")[1]).find("select.nf-client-control option[value='1']").prop("selected", true).trigger('change');

 


 


If I wanted to iterate through all rows and change the Fruit Control's value to that of the Row Index + 1, then I could do just that using something like:


NWF$(".nf-repeater-row:not" + "(.nf-repeater-row-hidden)").each(function(index, row){
row = NWF$(row);
var fruitControl = row.find("[data-controlname='control_Fruit']");
var fruitSelect = fruitControl.find("select.nf-client-control");
fruitSelect.find("option[value='" + String(index+1) + "']").prop("selected", true).trigger("change");

console.log(fruitControl.find(".nf-associated-control").val());
});


 


So, as you can see, while it isn't as straight forward as changing the value of other controls, it's kinda similar enough that it shouldn't be too big of a challenge. Just remember that for Lookups, the value of the options are usually set to the ID of whatever it is the Lookup has been setup to point towards. You might have to press F12 and inspect the Control to get an idea of which values it's pulling, but the principle above apply regardless of their values (just make sure you're actually selecting real values!). 


 


You also may have noticed that I'm adding a ".trigger("change")" bit at the end of my value change, and that's to make sure the form knows to update any related Controls / Rules that are relying on data from the Lookup in question.

This should at least get you started on the way to doing what it is you'd like to do. 


 


Hope it helps. 


 


 


 

Badge +8

I will look into it tomorrow (it is quite late in germany).


 


I'll let u know if it did the trick. 🙂

Badge +8

@MegaJerk Okay. I think there is a missunderstanding in our communication.


 


Lets just ignore that paul JS code stuff and look at following example:


 


So we have no JS and start from the beginning.


 


I try to explain it as good as possible so you could create the example by urself and test it in detail.


 


I have a List named:


 


Animal


 


It contains the following fields:


 


Number = required Textfield coloum (which will contain an unique number)


 


Multilinetextfield = a multilinetextfield (plain text) where the repeating section data will be stored


 



 


 


now to the formular:


 


Firstly the repeating section is connected to the Multilinetextfield and gets the name control_Multilinetextfield 


 



 


THE REPEATING SECTION contains:


 


Name = name of the animal


 


Born on = data coloum to select a date (only date NO time)


 


Colour = dropdown coloum to select a colour (Red, Green, Blue)


 


and because you mentioned it in ur answer they all need a Control Name so they have:


 


Name = control_Name


 


Born on = control_Bornon


 


Colour = control_Colour


 


 


Thats it ... now we publish the formular and enter some entries and save them to the list:


 




 


Now the list looks like this:


 



 


 


Sooooo now it gets to the part where I have no clue (bcs the solution of paul doesnt work):


 


When I open a new formular again its empty (as it should be):


 



 


What I want is that when I enter the "1" into the "Number" field and focusout of it the repeating section should autofill itself with the values stored in the Multilinetextfield. (so we need a lookup formula on the field Multilinetextfield and get its value somehow ... I mentioned in my first post that I know how to do that with any other kind of field (date, text, dropdown, multiple choice) but NOT with repeating section :()


 



 


It looks a bit confusing but I tried to add a few colours so u know what belongs to which field.


 


Now if I would change the Numberfield to "2" (and focus out of it) it should clear the repeating section and autofills it with the values linked to the "2" in the list (the repeating section clears itself and then adds the 3 rows with Lion, Ape and Bird)


 


It got a bit confusing because I tried the JS from the post I mentioned... Let us focus on the List: Animal


 


 

Badge +8

@MegaJerk Update:


 


I am very close to solving it:


 


Do the following changes:


 


change the control name from the multilinefield to "Multilinetextfield" and give it the same as a css class.


 



 


Give all of the three controls a css class with the same name:


 



 


Give the numberfield a JS var: varAnimal


 



 


 


Add following code to the JS settings:


 


 


NWF.FormFiller.Events.RegisterAfterReady(function () {
NWF$(document).ready(function () {
NWF$("#" + varAnimal).change(function () {
ClearRSData();
GetRSDataFromLookup();
});
});
});function ClearRSData() {
var Multilinetextfield = NWF$('.Multilinetextfield');
var labels = NWF$(Multilinetextfield).find('.control_Name');
NWF$.each(labels, function (index) {
NWF$('.Multilinetextfield .nf-repeater-row:last').find('.nf-repeater-deleterow-image').click();
}); NWF$('.Multilinetextfield .nf-repeater-row:last').each(function () {
var $row = NWF$(this);
$row.find('.control_Name input').val('');
$row.find('.control_Bornon input').val('');
$row.find('.control_Colour input').val('');
});
}function GetRSDataFromLookup() {
var lookupId = NWF$('#' + varAnimal).val();
if (lookupId != '') {
NWF$('#errorMsg').empty();
var requestUri = _spPageContextInfo.webAbsoluteUrl + '/_api/Web/Lists/getByTitle('Animal')/items?$filter=Title eq '' + lookupId + ''';
try {
NWF$.ajax({
url: requestUri,
type: 'GET',
headers: {
'ACCEPT': 'application/json;odata=verbose'
},
success: GetRSDataFromLookupSuccess,
error: GetRSDataFromLookupError
});
}
catch (err) {
NWF$('#errorMsg').html('getListData Error: ' + err);
}
}
}function GetRSDataFromLookupSuccess(data) {
if (data.d.results.length > 0) {
var Multilinetextfield = data.d.results[0].Multilinetextfield;
parser = new DOMParser();
xmlDoc = parser.parseFromString(Multilinetextfield, 'text/xml');
var items = xmlDoc.getElementsByTagName('Item');
for (var i = 0; i < items.length; i++) {
NWF$('.Multilinetextfield .nf-repeater-row:last').each(function () {
var $row = NWF$(this);
$row.find('.control_Name input').val(xmlDoc.getElementsByTagName('control_Name')[i].childNodes[0].nodeValue);
$row.find('.control_Bornon input').val(xmlDoc.getElementsByTagName('control_Bornon')[i].childNodes[0].nodeValue);
$row.find('.control_Colour input').val(xmlDoc.getElementsByTagName('control_Colour')[i].childNodes[0].nodeValue);
});
NWF$('.Multilinetextfield').find('a').click();
}
NWF$('.Multilinetextfield .nf-repeater-row:last').find('.nf-repeater-deleterow-image').click();
}
}function GetRSDataFromLookupError() {
alert('Failed to load Lookup Items');
}

 


 


 


and now... it works... but it doesnt xD...


 


Only things left are the dropdowns and the right dateformat.


 


Example video:


 



 

Badge +8

for the dropdown:


 


$row.find('.control_Colour select').

 


instead of:


 


$row.find('.control_Colour input').
Badge +8

got it:


 


date:


 


var date = xmlDoc.getElementsByTagName...
var dateSplitted = date.split(' ')[0].split('/');
date = dateSplitted[1] + '.' + dateSplitted[0] + '.' + dateSplitted[2];
$row.find(...).val(date);

Reply