[RESOLVED] Auto-populate fields

Hi PlumSail!

I have several lookup fields (6 fields) that are dependent upon each other and I would like to auto-populate those fields based on the value that is selected in one of them.

Currently, all fields are dependent on each other in order to populate the next corresponding field.

I have done a little experimenting to reduce the dependencies (3 fields dependent on each other) but I have ran into an issue.

The issue is that I want the other fields to auto-populate with values depending on the selection that is made in one of the look-up fields.

The lookup fields are referencing a hierarchy structure in a SharePoint List. So, depending on what is selected, it will always pull through the value that is related to it in the structure.

Is it possible to run an 'onChange' function of some sort to auto-populate the values in other fields by referencing the Hierarchy structure present in the SharePoint list?

As a visual representation of my problem:

The users will type a Cost-Centre Code, then select the Org L7 and then finally Org L3. (3 dependencies)

I want all other fields to populate once an Org L7 has been selected...By extension, Org L6, L5, L4 & L3.....

Hello @DryChips,

It depends on how source list is set up. If all data is stored in one list, you can try the approach using Extra fields, described in this post:

If data is stored in multiple lists, use PnPjs function to get field values:

fd.field('Field1').$on('change', function(value){
        pnp.sp.web.lists.getByTitle('List').items.getById(value.ID).get().then(function(item){
            fd.field('Title').value = item.Title
        });
});
1 Like

Thank you mnikitina. I will try the approach you have suggested.

So I tried both approaches but I haven't gotten anywhere.

The first approach suggested by Nikita isn't useful for my case as I have 2000+ rows to Lookup my unique value.

The code you have provided in this post doesn't seem to do anything but looks like something that might work for my case...

My lookup table is stored in a SP list. That's where I am retrieving the data.

This is how I have set-up the code:

fd.spRendered(function() {
fd.control('Org_L7').$on('change', function(value){
        pnp.sp.web.lists.getByTitle('Org Hierarchy').items.getById(value.ID).get().then(function(item){
            fd.field('Org_x0020_L6').value = item.Org_x0020_L6;
        });
});
});

Here is what I think the code is doing:

  1. Once a value is selected in Org_L7 field
  2. Go to the Org Hierarchy List (LookUp Table) and find the value selected in Org_L7
  3. Once found, find the respective Org_L6 value and populate the Org_L6 field with the value found.

The screenshot I have shared of all the fields are all Lookup fields. Would you suggest I change them to all (except Cost_centre & Org_L7) to single-line text fields?

@DryChips,

I'm sorry, there are no screenshots.

I need to understand the structure of the data in order to come up with a specific solution. Are you storing data in one list or in multiple lists? Are the Org L6, L5, L4 and L3 data stored in the same list? How are they related to the Org L7 data? By Using the Lookup field?

Hiya,

apologies for the delay.

Sure, please take a look:

All of this data is stored in one list. By typing a Cost Centre code, users will see the relevant Org L7 and a breakdown of the other Orgs.

I am essentially doing a LookUp to this list from a form to pull through the relevant details.

Hello @DryChips,

You can filter list by two fields using PnPjs and then populate other fields. Don't forget to update the code with the valid column names.

I assume that all fields on the form and in the SharePoint target list are Lookup fields. You can learn more about PnPjs function in the documentation here.

function populateFields() {
    //get the ID of the CostCenter
    var costCenter = fd.field('CostCenter').value.Id;
    //get the ID of the OrgL7
    var orgL7 = fd.field('OrgL7').value.Id
    
    //make sure both values are selected
    if(costCenter && orgL7) {
        //filter list and get item values
        pnp.sp.web.lists.getByTitle('ListName').items.filter('CostCenter/Id eq ' + costCenter + ' and LookupParent/Id eq ' + orgL7).get().then(function(item){
            fd.field('OrgL3').value = item[0].OrgL3Id;
        });
    }
}

//call function on field change
fd.field('CostCenter').$on('change', populateFields);
fd.field('OrgL7').$on('change', populateFields);
1 Like

HI mnikitina,

Thank you for the code!

Unfortunately, the code doesn't work.

The lookup fields that I have set-up in Plumsail are dependent drop downs.
Selecting/typing a Cost Centre code will bring through the Org L7, then Org L6, Org L5, Org L4 and finally Org L3. Will that interfere with the population of the fields?

The target SharePoint list was imported via Microsoft Excel. So, none of the columns are lookup fields as such.

I have changed the column names to the ones available on SharePoint.

What does '/ID eq' mean? Is that necessary?

Here is the error log in the console:

I have updated the code you have provided:

fd.spRendered(function(){
function populateFields() {
    //get the ID of the CostCenter
    var CostCentre = fd.field('Cost_Centre').value.Id;
    //get the ID of the OrgL7
    var OrgL7 = fd.field('Department').value.Id
    
    //make sure both values are selected
    if(Cost_Centre && Department) {
        //filter list and get item values
        pnp.sp.web.lists.getByTitle('OrgHierarchy').items.filter('Cost_x0020_Centre eq ' + CostCentre + 'Org_x0020_L7 eq ' + OrgL7).get().then(function(item){
            fd.field('Hospital').value = item[0].Title;
        });
    }
}

});

//call function on field change
fd.field('Cost_Centre').$on('change', populateFields);
fd.field('Department').$on('change', populateFields);

Hello @DryChips,

You can adjust the code depending on the field type and data source.

If you need help with the code, share more information. What types of fields do you use? Lookup, dropdowns, lookup control? How are the dependencies configured?

Here is how the fields are set-up in the designer:

The cost Centre code is now a single line of text. Please note that this field does its own lookup for validation purposes.
Here is the code for this:

//This code will validate the cost-centre code to a SP list
var ccexists = false;
fd.spRendered(function(){
  fd.field('Cost_Centre').validators.push({
        name: '',
        error: "Please enter a valid Cost Centre Code",
        validate: function() {
            return ccexists;
        }
  });
  
  fd.field('Cost_Centre').$on('change', function(value){
    validateCC(value);
  });
});

//This function is doing a Lookup to the Org Hierarchy SharePoint list
function validateCC(value){
  var filter = "Cost_x0020_Centre eq '" + value + "'";
  pnp.sp.web.lists.getByTitle("OrgHierarchy").items.filter(filter).getAll().then(function(items){
    if(items.length > 0){
    $($(fd.field('Cost_Centre').$el).find('input')[0]).attr('style', 'border-color: #6CEE5A; box-shadow: 0 0 5px #6CEE5A;');
    ccexists = true;
    
    }
    else{
    $($(fd.field('Cost_Centre').$el).find('input')[0]).attr('style', 'border-color:#ff0000; box-shadow: 0 0 5px #ff0000; Color:#ff0000;');
    ccexists = false;
   
    }
  });
};

The department field is a Lookup field
The speciality field is a Lookup field
The directorate field is a Lookup field
The division field is a Lookup field
The hospital field is a Lookup field

The department (Org L7) field is dependent on the Cost Centre code.
Here is how I have set this up on Plumsail:
image

The speciality (Org L6) depends on the department field
image

The Directorate (Org L5) field depends on the speciality field
image

All of this cascades down to the Hospital (Org L3) field

Here is a snippet of what the source list (Org hierarchy data) looks like:

image

Hello @DryChips,

Thank you for the details.

I've updated the code for this field and column types. Try it out. Don't forget to update internal names in the code.

function populateFields() {
    //get CostCenter
    var costCenter = fd.field('CostCenter').value;
    //get departments
    var orgL7 = fd.field('Department').value.LookupValue;

    
    
    //make sure both values are selected
    if(costCenter && orgL7) {
        var filter = "CostCenter eq '" + costCenter + "' and OrgL7 eq '" + orgL7 + "'";
        
        //filter list and get item values
        pnp.sp.web.lists.getByTitle('Source').items.filter(filter).get().then(function(item){
            fd.field('Speciality').value = item[0].Id;
        });
    }
}

//call function on field change
fd.field('CostCenter').$on('change', populateFields);
fd.field('Department').$on('change', populateFields);
1 Like

Does this code actually auto-populate a value? When I mean auto-populate, I mean it automatically adds the value it finds into the Speciality field. The lookups work as expected but it doesn't put the value in the field by itself - I have to manually click on the look-up field to select the value.

[UPDATE]

So I ran the code you provided and changed the field name as you suggested but no luck. I then proceeded to run this inside the console to see how it would behave. It was running fine until I interacted with the Depertment field. Here is type of error I get in console:

@DryChips,

You need to update the filer string in the code, the and is missing for the second condition:

var filter = "Cost_x0020_Center eq '" + costCenter + "' and Org_x0020_L7 eq '" + orgL7 + "'";
1 Like

Holy Cow. It all works! I didn't know the 'and' word was part of the query so I took it out but looks like it's very necessary.

Thank you so much! You ROCK! :smiley:

After using your code, I have noticed that my review fields have stopped working, oddly enough.
The value that is populated in the previous field don't appear to pull through the review field section in the form, despite having a value in them.

Here is the code that I am using to retrieve the data from the previous fields and listing them in the review fields.

fd.field('RSpeciality').disabled = true
fd.field('Speciality').$on('change', function() {
fd.field('RSpeciality').value = fd.field('Speciality').value.LookupValue; 
})

[Update]

Rather than having the code above, I think a 'then' method can be applied to pull through the values. I'm not sure how to write this syntax unfortunately.

So, 'On Change' of department, then set Speciality, then set Directorate... This might do the trick I think...

fd.field('RDepartment').disabled = true
	fd.field('Department').$on('change', function() {
 	fd.field('RDepartment').value = fd.field('Department').value.LookupValue.then
	})

Field names denoted with an 'R' are Review fields. E.g.
RDepartment = Plumsail Review field
Department = SharePoint field

I don't understand what is the issue. Do you mean that the lookups on the form are not filtered? Please provide more details.

Sorry.

So I currently have a review wizard which has Plumsail Fields in place that retrieves content from previous answers. This way, users can see what information they have inputted before they send a form to us. All the other fields are working great! Meaning, they are retrieving a value from the previous wizards. However, the fields that are not retrieving a value are the fields that are 'Auto-populated.'

Here is the code that you have kindly provided me:

//This code will auto-populate all the Org Hierarchy fields    
fd.spRendered(function(){    
function populateFields() {
    //get CostCenter
    var costCentre = fd.field('Cost_Centre').value;
    //get departments
    var orgL7 = fd.field('Department').value.LookupValue;

    
    
    //make sure both values are selected
    if(costCentre && orgL7) {
        var filter = "Cost_x0020_Centre eq '" + costCentre + "' and Org_x0020_L7 eq '" + orgL7 + "'";
        
        //filter list and get item values
        pnp.sp.web.lists.getByTitle('OrgHierarchy').items.filter(filter).get().then(function(item){
            fd.field('Speciality').value = item[0].Id;
            fd.field('Directorate').value = item[0].Id;
            fd.field('Division').value = item[0].Id;
            fd.field('Hospital').value = item[0].Id;
        });
    }
}

    //call function on field change
    fd.field('Cost_Centre').$on('change', populateFields);
    fd.field('Department').$on('change', populateFields);
});

Here is the code that will disable all Plumsail fields in the review wizard and retrieve the values in the previous fields:

fd.spRendered(function() {
    
    fd.field('RERostering').disabled = true
	fd.field('Question_1').$on('change', function() {
 	fd.field('RERostering').value = fd.field('Question_1').value; 
	})
    
    fd.field('RLeavingTrust').disabled = true
	fd.field('Question_2').$on('change', function() {
 	fd.field('RLeavingTrust').value = fd.field('Question_2').value; 
	})
    
    fd.field('RTermAssignment').disabled = true
	fd.field('Question_3').$on('change', function() {
 	fd.field('RTermAssignment').value = fd.field('Question_3').value; 
	})
      
    fd.field('RSupervisorName').disabled = true
	fd.field('Supervisor_Name').$on('change', function() {
 	fd.field('RSupervisorName').value = fd.field('Supervisor_Name').value; 
	})
        
    fd.field('RSupervisorEmail').disabled = true
	fd.field('Supervisor_Email_Address').$on('change', function() {
 	fd.field('RSupervisorEmail').value = fd.field('Supervisor_Email_Address').value; 
	})

	fd.field('RTitle').disabled = true
	fd.field('Titles').$on('change', function() {
 	fd.field('RTitle').value = fd.field('Titles').value; 
	})
    
    fd.field('RFirstName').disabled = true
	fd.field('First_Name').$on('change', function() {
 	fd.field('RFirstName').value = fd.field('First_Name').value; 
	})
    
    fd.field('RLastName').disabled = true
	fd.field('Last_Name').$on('change', function() {
 	fd.field('RLastName').value = fd.field('Last_Name').value; 
	})
    
    fd.field('RAssignNum').disabled = true
	fd.field('Assignment_Number').$on('change', function() {
 	fd.field('RAssignNum').value = fd.field('Assignment_Number').value; 
	})
    
    fd.field('RPayBand').disabled = true
	fd.field('Pay_Band').$on('change', function() {
 	fd.field('RPayBand').value = fd.field('Pay_Band').value; 
	})
    
    fd.field('RCurrentHours').disabled = true
	fd.field('Current_Hours').$on('change', function() {
 	fd.field('RCurrentHours').value = fd.field('Current_Hours').value; 
	})
    
    fd.field('RCostCentreCode').disabled = true
	fd.field('Cost_Centre').$on('change', function() {
 	fd.field('RCostCentreCode').value = fd.field('Cost_Centre').value; 
	})
    
    fd.field('RDepartment').disabled = true
	fd.field('Department').$on('change', function() {
 	fd.field('RDepartment').value = fd.field('Department').value.LookupValue;
	})

	    
    fd.field('RHospital').disabled = true
    fd.field('Hospital').$on('change', function() {
    fd.field('RHospital').value = fd.field('Hospital').value.LookupValue;
    }) 
    
    fd.field('RDivision').disabled = true
	fd.field('Division').$on('change', function() {
 	fd.field('RDivision').value = fd.field('Division').value.LookupValue; 
	})
    
    fd.field('RSpeciality').disabled = true
	fd.field('Speciality').$on('change', function() {
 	fd.field('RSpeciality').value = fd.field('Speciality').value.LookupValue; 
	})
    
    fd.field('RDirectorate').disabled = true
	fd.field('Directorate').$on('change', function() {
 	fd.field('RDirectorate').value = fd.field('Directorate').value.LookupValue; 
	})
    
    fd.field('RStaffGroup').disabled = true
	fd.field('Main_Staff_Group').$on('change', function() {
 	fd.field('RStaffGroup').value = fd.field('Main_Staff_Group').value; 
	})

    fd.field('RTerminationDate').disabled = true
	fd.field('Employee_Termination_Date').$on('change', function() {
 	fd.field('RTerminationDate').value = fd.field('Employee_Termination_Date').value.toDateString(); 
	})
    
    fd.field('RLastWorkingDay').disabled = true
	fd.field('Employee_Last_Working_Day').$on('change', function() {
 	fd.field('RLastWorkingDay').value = fd.field('Employee_Last_Working_Day').value.toDateString(); 
	})
    
    fd.field('RReasonForDifference').disabled = true
	fd.field('Reason_For_Difference').$on('change', function() {
 	fd.field('RReasonForDifference').value = fd.field('Reason_For_Difference').value; 
	})
    
    fd.field('RVoluntary').disabled = true
	fd.field('Voluntary').$on('change', function() {
 	fd.field('RVoluntary').value = fd.field('Voluntary').value.LookupValue; 
	})
    
    fd.field('RNonVoluntary').disabled = true
	fd.field('Non_Voluntary').$on('change', function() {
 	fd.field('RNonVoluntary').value = fd.field('Non_Voluntary').value.LookupValue; 
	})
    
    fd.field('RDestinationOnLeaving').disabled = true
	fd.field('Destination_On_Leaving').$on('change', function() {
 	fd.field('RDestinationOnLeaving').value = fd.field('Destination_On_Leaving').value; 
	})
    
    fd.field('RNHSOrganisationLeavingTo').disabled = true
	fd.field('NHS_Organisation_Leaving_To').$on('change', function() {
 	fd.field('RNHSOrganisationLeavingTo').value = fd.field('NHS_Organisation_Leaving_To').value; 
	})
    
    fd.field('RHolidayHoursDue').disabled = true
	fd.field('Holidays_Hours_Due').$on('change', function() {
 	fd.field('RHolidayHoursDue').value = fd.field('Holidays_Hours_Due').value; 
	})
    
    fd.field('RHolidayHoursOverpaid').disabled = true
	fd.field('Holiday_Hours_Overpaid').$on('change', function() {
 	fd.field('RHolidayHoursOverpaid').value = fd.field('Holiday_Hours_Overpaid').value; 
	})
      
    fd.field('RLieuHoursOutstanding').disabled = true
	fd.field('Lieu_Hours_Outstanding').$on('change', function() {
 	fd.field('RLieuHoursOutstanding').value = fd.field('Lieu_Hours_Outstanding').value; 
	})
    
    fd.field('RPaymentsLieuNotice').disabled = true
	fd.field('Payments_Made_In_Lieu_Notice').$on('change', function() {
 	fd.field('RPaymentsLieuNotice').value = fd.field('Payments_Made_In_Lieu_Notice').value; 
	})
    
    fd.field('RDateLeavingPost').disabled = true
	fd.field('Date_Employee_Leaving_Post').$on('change', function() {
 	fd.field('RDateLeavingPost').value = fd.field('Date_Employee_Leaving_Post').value.toDateString(); 
	})
});

In the above code, the part which has stopped working is this:

fd.field('RHospital').disabled = true
    fd.field('Hospital').$on('change', function() {
    fd.field('RHospital').value = fd.field('Hospital').value.LookupValue;
    }) 
    
    fd.field('RDivision').disabled = true
	fd.field('Division').$on('change', function() {
 	fd.field('RDivision').value = fd.field('Division').value.LookupValue; 
	})
    
    fd.field('RSpeciality').disabled = true
	fd.field('Speciality').$on('change', function() {
 	fd.field('RSpeciality').value = fd.field('Speciality').value.LookupValue; 
	})
    
    fd.field('RDirectorate').disabled = true
	fd.field('Directorate').$on('change', function() {
 	fd.field('RDirectorate').value = fd.field('Directorate').value.LookupValue; 
	})

The reason why they have stopped working is because they are 'On change' functions but users will never actually see those fields in the form as they will be hidden from them to reduce clutter but will be used by managers and important staff who require this information.

@DryChips,

Thank you for the details!

When changing Lookup field value programmatically, the field value is just item ID. You need to use reloadValue() function to load additional lookup data. Try updating the code that populates common field like this:

fd.field('Speciality').$on('change', function(value){
   //check that field has no additional data
    if(typeof value == 'number'){
        fd.field('Speciality').reloadValue().then(function(){        
    	    fd.field('RSpeciality').value = fd.field('Speciality').value.LookupValue;        
        })
        
    }
    else if(value != null) {
        fd.field('RSpeciality').value = value.LookupValue
    }
})
1 Like

Hi mnikitina,

I have done some stress testing for the Cost Centre code field and it's a little buggy.

Here is the code that is powering this:

//This code will validate the cost-centre code to a SP list
var ccexists = false;
fd.spRendered(function(){
  fd.field('Cost_Centre').validators.push({
        name: '',
        error: "Please enter a 7 digit valid Cost Centre Code",
        validate: function() {
            return ccexists;
        }
  });
  
  fd.field('Cost_Centre').$on('change', function(value){
    validateCC(value);
  });
});

//This function is doing a Lookup to the Org Hierarchy SharePoint list
function validateCC(value){
  var filter = "Cost_x0020_Centre eq '" + value + "'";
  pnp.sp.web.lists.getByTitle("OrgHierarchy").items.filter(filter).getAll().then(function(items){
    if(items.length > 0){
    $($(fd.field('Cost_Centre').$el).find('input')[0]).attr('style', 'border-color: #6CEE5A; box-shadow: 0 0 5px #6CEE5A;');
    ccexists = true;
    
    }
    else{
    $($(fd.field('Cost_Centre').$el).find('input')[0]).attr('style', 'border-color:#ff0000; box-shadow: 0 0 5px #ff0000; Color:#ff0000;');
    ccexists = false;
    }
  });
};
  1. The field returns an errors out as soon as the user types a value in. I want it to validate the value entered after its fully been added. Is there a way to fix this? Perhaps, using Regex?

  2. Sometimes, when I type a valid Cost Centre in the field it doesn't return the Department and Hospital. I have to re-type the value again and then it starts to work. Is there a way to fix it?

  3. I have some errors in the console as well, which I think are related to this feature I have added.

Here is what snapshot of the errors in the console:

Any reason why this is the case?

Hello @DryChips,

You can add a condition to check that the entered Cost Center is valid before pnp function. Validate the value by Regex or length. Thus you will avoid errors and make sure the call is made when the CC is valid. Maybe this will resolve the issue with re-entering value.

function validateCC(value){
//validate the entered value
if(value.length == 7) {
  var filter = "Cost_x0020_Centre eq '" + value + "'";
  pnp.sp.web.lists.getByTitle("OrgHierarchy").items.filter(filter).getAll().then(function(items){
    if(items.length > 0){
    $($(fd.field('Cost_Centre').$el).find('input')[0]).attr('style', 'border-color: #6CEE5A; box-shadow: 0 0 5px #6CEE5A;');
    ccexists = true;
    
    }
    else{
    $($(fd.field('Cost_Centre').$el).find('input')[0]).attr('style', 'border-color:#ff0000; box-shadow: 0 0 5px #ff0000; Color:#ff0000;');
    ccexists = false;
    }
  });
}
};

The errors are not related to this part of the code. Check where in the code you are using LookupValue and debug:

fd.field('FieldName').value.LookupValue
1 Like