Javascript to set value in lookup list control


Badge +5

I have a lookup-list control on my form tied to a single line text field in SharePoint. In my javascript code, I get customer data from a database and set the default customer data on the form.  On the lookup list control (which is a drop-down list), I use jQuery to set the val() of the control.  This is reflected in the form and I thought it was OK.  When I save the form, nothing is saved to the field. Since this a complicated form, I thought I'd test it out on a regular list.

To replicate my environment, create a custom list in SharePoint.

Open the form in Nintex form editor and delete the Title text field.

Place a lookup list control on the form and configure it so that the value is tied to the Title field.

Test your form so that when you create a new item, you get a Drop down list. 

To test my javascript, I wrote the following code:

NWF$(document).ready(function(){

            var ddlShipVia = NWF$("#" + tbTitle);

            ddlShipVia.on("change", function(e){

                console.log("Executing ddlShipVia.onChange()");

                if(e.originalEvent == undefined) {

                    if(this.value==""){

                        ddlShipVia.val(286);

                    }

                }

            });

});

This code works and sets the DDL to the corresponding index value (69).

Click Save and I get an error saying that the field is required.  If I manually select a value, then it saves just fine. 

Does anyone know how to progamatically set a value in a Lookup List DDL?


16 replies

Badge +3

After you set the value to 286 call the change event: ddlShipVia.change();

Badge +2

I've found that Nintex uses a hidden input element right after the select element (the lookup) to hold the value bound back to the list item. So while changing the val() of the list lookup changes the lookup on screen, Nintex does not seem to be aware of the change. Calling .change() as suggested above will in fact trigger other events, like other lookups that might filter on this lookup, but Nintex is still looking at the input element when saving to the list item.

So the solution to binding the lookup value back to the list item is to call .val() on the hidden input element in addition to the lookup's select element.

Your code above should be modified as follows. Note the additional line which sets the .next(‘input’).val to 286:

NWF$(document).ready(function () {
    var ddlShipVia = NWF$("#" + tbTitle);
    ddlShipVia.on("change", function (e) {
        console.log("Executing ddlShipVia.onChange()");
        if (e.originalEvent == undefined) {
            if (this.value == "") {
                ddlShipVia.val(286);
                ddlShipVia.next('input').val(286);
            }
        }
    });
});

After publishing this change you should be able to Save the edit form and the list item Title field will be updated as expected.

UPDATE: April 2, 2017 -- My code example above no longer works with Nintex Forms 2.10.0.0 released in March of 2017. The client ID given by Nintex in the control settings now refers to the hidden input control directly, and the select is still the previous element.

Userlevel 6
Badge +15

‌  -- did the above answer help you out?

Badge +5

On the project I was working on for this, the requirements for form automation became so complicated that I had to abandon Nintex Forms for this project.  I ended up hand-coding an HTML form.  I never was able to test the above solution.

Userlevel 6
Badge +15

Thank you for letting us know, I am sorry that it didn't work out.

Badge +1

thanks! that did it for me, after changing the value of the dropdown, you also need to trigger the .change() event manually

Badge +1

Since we  upgraded to Forms version 2.10 (from an older version like 2.5) we have had a lot of trouble with this. The following code works for me but it isn't as clean as I would like it to be so if anyone has a suggestion for improvement, JS is not my specialty! There are two issues in my opinion:

  1. I'm not able to catch the change event of the child control as I should be. I have to trigger the change from the parent manually
  2. When the change happens it is too fast so I have to put in a delay loop to wait for the DDL to load completely. Seems like there should be a better way.

As I said, it works, it is just a little ugly. Note  that if you are not dealing with the parent/child relationship you can hardcode  default value really easily:

NWF$(document).ready(function() {
 NWF$("#" + myddl).val('3');
});

Here is the parent/child one:

NWF$(document).ready(function() {
 NWF$("#" + ddlParent).change(function () {       
  NWF$("#" + ddlChild).change();        
 }); 
   
  
 NWF$("#" + ddlChild).change(function () { 
  var ddlChildId = ddlChild.substring(0, ddlChild.length -4); 
  var len= NWF$("#" + ddlChildId ).find("option").length;      
  if(len>=2) {

 return delay(1000).then(function() {
   NWF$("#"      + ddlChildId).prop('selectedIndex',1);
   NWF$("input#" + ddlChildId).val(NWF$("#" + ddlChildId).find("option")[1]); 

});
  }
  else {
       while(i<10 && len==1) {
       i++;        
          return delay(1000).then(function() {
           len= NWF$("#" + ddlChildId ).find("option").length;
           if(len>=2) {
            NWF$("#"      + ddlChildId).prop('selectedIndex',1);
            NWF$("input#" + ddlChildId).val(NWF$("#" + ddlChildId).find("option")[1]);      
           }
          });        
   }
  }            
 });

 function delay(t) {
  return new Promise(function(resolve) {
   setTimeout(resolve, t)
  });
 }
});

Badge +2

My current code to set a lookup value in 2.10.0.0 boils down to this:

whenNintexFormIsReady(
    TekDogUtilities.prototype.whenLookupSelectIsDisplayed(listLookupClientId, value,
        function () { TekDogUtilities.prototype.setLookupControlByLookupId(listLookupClientId, value); }
    )
);

// ...with these supporting methods. I usually place TekDogUtilities.js in Site assets and register it with SP

function whenNintexFormIsReady(ready) {
    if (typeof NWF$ !== 'undefined') {
        NWF$(document).ready(function () {
            NWF$(window).load(function () {
                ready();
            });
        });
    }
}

function TekDogUtilities() {
}

// "How to wait until an element exists?", Etienne Tonnelier, answered Apr 20 '15 at 17:06, retrieved 3/25/2017
// http://stackoverflow.com/questions/5525071/how-to-wait-until-an-element-exists
TekDogUtilities.prototype.waitForElementToDisplay = function (selector, time, ready) {
    if (document.querySelector(selector) != null) {
        console.log(selector + ' is displayed');
        console.log('ready: ' + ready);
        ready();
    }
    else {
        setTimeout(function () {
            TekDogUtilities.prototype.waitForElementToDisplay(selector, time, ready);
        }, time);
    }
}

TekDogUtilities.prototype.whenLookupSelectIsDisplayed = function (listLookupClientId, lookupId, ready) {
    var selectClientId = listLookupClientId.replace('_hid', '');
    var optionSelector = "#" + selectClientId + " option[value='" + lookupId + "']";
    TekDogUtilities.prototype.waitForElementToDisplay(optionSelector, 100, ready);
}

TekDogUtilities.prototype.setLookupControlByLookupId = function (clientId, lookupId) {
    // nintex version 2.10.0.0 uses the select previous to the clientid
    var selectClientId = $("#" + clientId).prev('select').attr('id');
    var $option = $("#" + selectClientId + " option[value='" + lookupId + "']");
    var txt = document.getElementById(selectClientId);
    if (typeof lookupId !== 'undefined' && txt != null) {
        txt.value = lookupId;
        $option.attr("selected", "selected");
        NWF$('#' + clientId).val(lookupId);
    }
    return lookupId;
}

TekDogUtilities.prototype.setLookupControlByText = function (clientId, text) {
    // nintex version 2.10.0.0 uses the select previous to the clientid
    var selectClientId = $("#" + clientId).prev('select').attr('id');
    var lookupId = null;
    var $option = $("#" + selectClientId + " option[title='" + text + "']");
    lookupId = $option.val();
    var txt = document.getElementById(selectClientId);
    if (typeof lookupId !== 'undefined' && txt != null) {
        txt.value = lookupId;
        $option.attr("selected", "selected");
        NWF$('#' + clientId).val(lookupId); // nintex stores bound data value in the input element
    }
    return lookupId;
}

Userlevel 2
Badge +11

Today I figured out a way to set a lookup dropdown list using JavaScript with only a few lines of code and working in NF 2013 2.10.0. As a base for the code below I created a form with 2 lookups to a Currency list. Goal is to set the selected dropdown value of the 2nd one with the selected value of the 1st:

// First Dropdown - has JavaScript Client ID jsCurrency

var currencyCtrl = NWF$("#" + jsCurrency);

var currencySelection = currencyCtrl.val();                                                                          // Result as lookup string, e.g.  : 1;#EUR

var selectedCurrency = NWF.RuntimeFunctions.parseLookup(currencySelection,true);    // Lookup value itself                : EUR

// Second dropdown - has JavaScript Client ID jsSecondCurrency

var secondCurrencyCtrl = NWF$("#" + jsSecondCurrency);                                                        // this returns the input element

var selectCtrl2Id = jsSecondCurrency.replace('_hid','');                                                               // determine id of select element

var selectElement = NWF$("#" + selectCtrl2Id); ;                                                                        // this returns the select element

NWF$("#" + selectCtrl2Id + " option:contains(" + selectedCurrency +")").attr("selected", true);  // set select to specific lookup value

secondCurrencyCtrl.val(currencySelection);                                                                                // also store lookup string in input element

As mentioned this works now in two different libraries. Hopefully it works for you as well as it does now for me.

Badge +1

Thank you for sharing. Can you tell me... is your second dropdown configured in the UI to filter based on the value in the first? I think that is where my trouble comes in b/c my JS executes before the fitler takes place. What I have been trying to do is have the child control update its filtered values when the parent control changes, and then use JS to select the first element in the child control. The problem is the first element gets selected before the filter takes place which is why all those ugly delays are now in my code.

Userlevel 2
Badge +11

Hi Ann,

No, in my case the 2nd ddl is not part of a cascading set. The above code I put inside a change event function inside the document.ready of the form:

NWF$(document).ready(function() {
      NWF$("#" + jsCurrency).change(function() {

           // My above code goes in here

      });

});

Have you tried to use the childDDL.ready(function () { // your code to set default item to 1st}) on the child dropdown. With the little documentation available, it is difficult to say which events have been implement for each of the controls. Otherwise you could try add a timeout in the first ddl's change event allowing the child ddl to be filtered before setting it's default value.

Badge +1

NWF$(document).ready(function(){

            var ddlShipVia = NWF$("#" + tbTitle);

            ddlShipVia.on("change", function(e){

                console.log("Executing ddlShipVia.onChange()");

                if(e.originalEvent == undefined) {

                    if(this.value==""){

                        ddlShipVia.val(286);

                    }

                }

            });

 

});

Change event of control does not get triggered.It does not get set.

Badge +9

I have multiple list lookup controls that show up when filtered through single line of text field. The connected ids only appear for some list lookup control but not others. All the list lookup controls are pulling from one list but different views. Could you please help me with this?

Badge +2

Thank you for the script. It works for me

Badge

I have two look up fields where the temp lookup field just copies from the look up original look up field.Im trying to use a nintex form button to rollback from temp lookup column values to original look up field.Please suggest.Thanks

Badge

Since this seems to be an ongoing game of cat and mouse with changes to nintex forms and no OOB implementation still from Nintex  I'll throw my hat in here too. jsexton114's implementation seems to work the best as it adjusts to the async load times of the lookups most accurately without having to pad timeouts/delays. In my case I have cascading lookups that I want to set via Query String parameters so I have to wait for the first lookup to load, set it, wait for the next to re-load based on the first , then set it etc...

 

I tweaked jsexton114's code a little bit to get it to work in Forms 2016 4.4.0.0. I also added checks to not set if the control has already been set or if the query string parameters aren't found.

 

Thanks jsexton114 for sharing your method, huge time saver.

 

function whenNintexFormIsReady(ready) {
  NWF.FormFiller.Events.RegisterAfterReady(ready);
}

function TekDogUtilities() {
}

// "How to wait until an element exists?", Etienne Tonnelier, answered Apr 20 '15 at 17:06, retrieved 3/25/2017
// http://stackoverflow.com/questions/5525071/how-to-wait-until-an-element-exists
TekDogUtilities.prototype.waitForElementToDisplay = function (selector, time, ready) {
    if (document.querySelector(selector) != null) {
        console.log(selector + ' is displayed');
        console.log('ready: ' + ready);
        ready();
    }
    else {
        setTimeout(function () {
            TekDogUtilities.prototype.waitForElementToDisplay(selector, time, ready);
        }, time);
    }
}

TekDogUtilities.prototype.whenLookupSelectIsDisplayed = function (listLookupClientId, lookupId, ready) {
    var selectClientId = listLookupClientId.replace('_hid', '');
    var optionSelector = "#" + selectClientId + " option[value='" + lookupId + "']";
    TekDogUtilities.prototype.waitForElementToDisplay(optionSelector, 100, ready);
}

TekDogUtilities.prototype.setLookupControlByLookupId = function (clientId, lookupId) {
    // nintex version 2.10.0.0 uses the select previous to the clientid
    var selectClientId = NWF$("#" + clientId).prev('select').attr('id');
    var currentselected = NWF$("#" + selectClientId).val();
    var NWF$option = NWF$("#" + selectClientId + " option[value='" + lookupId + "']");
    var txt = document.getElementById(selectClientId);
    if (typeof lookupId !== 'undefined' && txt != null && currentselected == "**SelectValue**") {
        txt.value = lookupId;
        NWF$option.attr("selected", "selected");
        NWF$('#' + clientId).val(lookupId); 
        NWF$('#' + selectClientId).change();
    }
    return lookupId;
}

TekDogUtilities.prototype.setLookupControlByText = function (clientId, text) {
    // nintex version 2.10.0.0 uses the select previous to the clientid
    console.log(clientId)
    var selectClientId = NWF$("#" + clientId).prev('select').attr('id');
    var currentselected = NWF$("#" + selectClientId).val();
    var lookupId = null;
    var NWF$option = NWF$("#" + selectClientId + " option[title='" + text + "']");
    lookupId = NWF$option.val();
    var txt = document.getElementById(selectClientId);
    if (typeof lookupId !== 'undefined' && txt != null && currentselected == "**SelectValue**") {
        txt.value = lookupId;
        NWF$option.attr("selected", "selected");
        NWF$('#' + clientId).val(lookupId); // nintex stores bound data value in the input element
        NWF$('#' + selectClientId).change();

    }
    return lookupId;
}




JSRequest.EnsureSetup();
whenNintexFormIsReady(
	function(){
		if(JSRequest.QueryString['ProcessLocation'] != null)
	    {
	    	TekDogUtilities.prototype.whenLookupSelectIsDisplayed(ProcessLocation, JSRequest.QueryString['ProcessLocation'],
	        	function () { TekDogUtilities.prototype.setLookupControlByLookupId(ProcessLocation, JSRequest.QueryString['ProcessLocation']); }
	    	);
	    }
	    if(JSRequest.QueryString['Process'] != null)
	    {
		    TekDogUtilities.prototype.whenLookupSelectIsDisplayed(Process, JSRequest.QueryString['Process'],
		        function () { TekDogUtilities.prototype.setLookupControlByLookupId(Process, JSRequest.QueryString['Process']); }
		    );
		}
		if(JSRequest.QueryString['Activity'] != null)
		{
		    TekDogUtilities.prototype.whenLookupSelectIsDisplayed(Activity, JSRequest.QueryString['Activity'],
		        function () { TekDogUtilities.prototype.setLookupControlByLookupId(Activity, JSRequest.QueryString['Activity']); }
		    );
		}
		if(JSRequest.QueryString['TurnbackType'] != null)
		{
		    TekDogUtilities.prototype.whenLookupSelectIsDisplayed(TurnbackType, JSRequest.QueryString['TurnbackType'],
		        function () { TekDogUtilities.prototype.setLookupControlByLookupId(TurnbackType, JSRequest.QueryString['TurnbackType']); }
		    );
		}
	}
);

Reply