Validation rule to allow modification of limited fields only

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
1
down vote

favorite












I have a object that has more than 40 fields. There are 3 record types and each layout shows different fields.
Now, I want to write a validation rule which allows editing of limited fields only when the stage of record is progress.



For e.g.
If my School object have following fields:



School__c
Location__c
Name
Color__c
Class_c
Students__c
Teacher__c
Faculties__c
Department__c
stage__c


Now, If i have 3 record types called Type A, Type B, Type C.



In Type A, I want user be able to edit Color__c and Class__c fields.



In Type B, I want user to be able to edit Students__c and Teacher__c fields



In Type C, I want user to Edit Faculties__c, Department__c fields.



In all record type Name should be editable.



User should not be able to edit School__c, Location__c fields. The whole validation should run when stage__c = progress.



Can i write a validation rule that satisfies above condition.







share|improve this question






















  • This one we can achieve through validation rule. Is this condition for all the users correct ?
    – Prem Anandh
    Aug 9 at 16:20






  • 1




    While this can be done using validation rules, but considering you have 40 fields, your scenario is the opposite, i.e., you need to write a validation rule to block say 30 fields to be editable and only allow handful of fields to be editable when the stage reaches a particular value for a particular record type. This could get cumbersome to maintain. Recommend approach will be to implement this using a trigger.
    – Jayant Das
    Aug 9 at 16:34
















up vote
1
down vote

favorite












I have a object that has more than 40 fields. There are 3 record types and each layout shows different fields.
Now, I want to write a validation rule which allows editing of limited fields only when the stage of record is progress.



For e.g.
If my School object have following fields:



School__c
Location__c
Name
Color__c
Class_c
Students__c
Teacher__c
Faculties__c
Department__c
stage__c


Now, If i have 3 record types called Type A, Type B, Type C.



In Type A, I want user be able to edit Color__c and Class__c fields.



In Type B, I want user to be able to edit Students__c and Teacher__c fields



In Type C, I want user to Edit Faculties__c, Department__c fields.



In all record type Name should be editable.



User should not be able to edit School__c, Location__c fields. The whole validation should run when stage__c = progress.



Can i write a validation rule that satisfies above condition.







share|improve this question






















  • This one we can achieve through validation rule. Is this condition for all the users correct ?
    – Prem Anandh
    Aug 9 at 16:20






  • 1




    While this can be done using validation rules, but considering you have 40 fields, your scenario is the opposite, i.e., you need to write a validation rule to block say 30 fields to be editable and only allow handful of fields to be editable when the stage reaches a particular value for a particular record type. This could get cumbersome to maintain. Recommend approach will be to implement this using a trigger.
    – Jayant Das
    Aug 9 at 16:34












up vote
1
down vote

favorite









up vote
1
down vote

favorite











I have a object that has more than 40 fields. There are 3 record types and each layout shows different fields.
Now, I want to write a validation rule which allows editing of limited fields only when the stage of record is progress.



For e.g.
If my School object have following fields:



School__c
Location__c
Name
Color__c
Class_c
Students__c
Teacher__c
Faculties__c
Department__c
stage__c


Now, If i have 3 record types called Type A, Type B, Type C.



In Type A, I want user be able to edit Color__c and Class__c fields.



In Type B, I want user to be able to edit Students__c and Teacher__c fields



In Type C, I want user to Edit Faculties__c, Department__c fields.



In all record type Name should be editable.



User should not be able to edit School__c, Location__c fields. The whole validation should run when stage__c = progress.



Can i write a validation rule that satisfies above condition.







share|improve this question














I have a object that has more than 40 fields. There are 3 record types and each layout shows different fields.
Now, I want to write a validation rule which allows editing of limited fields only when the stage of record is progress.



For e.g.
If my School object have following fields:



School__c
Location__c
Name
Color__c
Class_c
Students__c
Teacher__c
Faculties__c
Department__c
stage__c


Now, If i have 3 record types called Type A, Type B, Type C.



In Type A, I want user be able to edit Color__c and Class__c fields.



In Type B, I want user to be able to edit Students__c and Teacher__c fields



In Type C, I want user to Edit Faculties__c, Department__c fields.



In all record type Name should be editable.



User should not be able to edit School__c, Location__c fields. The whole validation should run when stage__c = progress.



Can i write a validation rule that satisfies above condition.









share|improve this question













share|improve this question




share|improve this question








edited Aug 9 at 17:06









Mark Pond

17.7k13082




17.7k13082










asked Aug 9 at 16:06









lambad

1183




1183











  • This one we can achieve through validation rule. Is this condition for all the users correct ?
    – Prem Anandh
    Aug 9 at 16:20






  • 1




    While this can be done using validation rules, but considering you have 40 fields, your scenario is the opposite, i.e., you need to write a validation rule to block say 30 fields to be editable and only allow handful of fields to be editable when the stage reaches a particular value for a particular record type. This could get cumbersome to maintain. Recommend approach will be to implement this using a trigger.
    – Jayant Das
    Aug 9 at 16:34
















  • This one we can achieve through validation rule. Is this condition for all the users correct ?
    – Prem Anandh
    Aug 9 at 16:20






  • 1




    While this can be done using validation rules, but considering you have 40 fields, your scenario is the opposite, i.e., you need to write a validation rule to block say 30 fields to be editable and only allow handful of fields to be editable when the stage reaches a particular value for a particular record type. This could get cumbersome to maintain. Recommend approach will be to implement this using a trigger.
    – Jayant Das
    Aug 9 at 16:34















This one we can achieve through validation rule. Is this condition for all the users correct ?
– Prem Anandh
Aug 9 at 16:20




This one we can achieve through validation rule. Is this condition for all the users correct ?
– Prem Anandh
Aug 9 at 16:20




1




1




While this can be done using validation rules, but considering you have 40 fields, your scenario is the opposite, i.e., you need to write a validation rule to block say 30 fields to be editable and only allow handful of fields to be editable when the stage reaches a particular value for a particular record type. This could get cumbersome to maintain. Recommend approach will be to implement this using a trigger.
– Jayant Das
Aug 9 at 16:34




While this can be done using validation rules, but considering you have 40 fields, your scenario is the opposite, i.e., you need to write a validation rule to block say 30 fields to be editable and only allow handful of fields to be editable when the stage reaches a particular value for a particular record type. This could get cumbersome to maintain. Recommend approach will be to implement this using a trigger.
– Jayant Das
Aug 9 at 16:34










1 Answer
1






active

oldest

votes

















up vote
4
down vote













You likely could write a validation rule to satisfy your conditions, but you might not be able to save that validation rule (because it'd likely go beyond the compiled character limit).



Validation rules aren't really meant to do what you're looking to do. Preventing certain fields from being edited is easy. The inverse of that, allowing certain fields to be edited, is hard.



A better declarative solution is to create new record types and page layouts, and mark the fields that you want to prevent from being edited as "read only" on those new layouts. You could use a workflow rule or process builder to automatically move your records into/out-of these special recordTypes.



Other than that, this would be a relatively simple trigger.



  • Gather a list of all the field api names on your object

  • Create a set of field api names you want to allow editing on (probably a Map<String, Set<String>> since you want different fields on different recordTypes)

  • Iterate over trigger.new, and check the record against its companion in trigger.old

  • If a field is changed and not in your "allowed" set, add an error

some example code to get you going



Trigger myTrigger on MyObject(before update)
// We can gather the field API names through SObject describe information
List<String> fieldAPINames = new List<String>();

// This is one way to initialize a map
Map<String, Set<String>> editableFieldsByRecordType = new Map<String, Set<String>>
'RecType1' => new Set<String>'field1__c', 'field2__c', 'field3__c'
;

for(Schema.FieldDiscribeResult fdr :Schema.SObject.MyObject.fields.getMap().values())
// The getName() method of the FieldDescribeResult class gives you the API name of the field
fieldAPINames.add(fdr.getName());


for(MyObject newRec :Trigger.new)
MyObject oldRec = Trigger.oldMap.get(newRec.Id);

for(String currentField :fieldAPINames)
if(oldRec.get(currentField) != newRec.get(currentField) && !editableFieldsByRecordType.get(newRec.recordTypeName__c).contains(currentField))
newRec.addError('Field is not editable for this stage');

// After you find the first error, you may be able to move on to the next
// record.
// Comment the next line out if you want to catch _all_ attempted edits
break;






The big caveat here (besides me not testing for a particular stage) is that I assume you have a recordTypeName__c field (a formula field) to pull the name of your recordType into the object you're working on.



Trigger context variables don't contain any "related data" (data on objects other than the one you're working on). If you need to use more than one period/dot/full-stop to access a field, like myRec.RecordType.Name, that information is not available in trigger context variables.



To get that information, you either need to explicitly query for it, or have a formula field. There are other ways around that, but those are the easiest and most common approaches.






share|improve this answer
















  • 1




    A fieldset (or more likely a couple fieldsets) can be leveraged so that the list of fields is controlled by something that can be edited in Setup rather than hardcoded.
    – Mark Pond
    Aug 9 at 17:09










Your Answer







StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "459"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsalesforce.stackexchange.com%2fquestions%2f228362%2fvalidation-rule-to-allow-modification-of-limited-fields-only%23new-answer', 'question_page');

);

Post as a guest






























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
4
down vote













You likely could write a validation rule to satisfy your conditions, but you might not be able to save that validation rule (because it'd likely go beyond the compiled character limit).



Validation rules aren't really meant to do what you're looking to do. Preventing certain fields from being edited is easy. The inverse of that, allowing certain fields to be edited, is hard.



A better declarative solution is to create new record types and page layouts, and mark the fields that you want to prevent from being edited as "read only" on those new layouts. You could use a workflow rule or process builder to automatically move your records into/out-of these special recordTypes.



Other than that, this would be a relatively simple trigger.



  • Gather a list of all the field api names on your object

  • Create a set of field api names you want to allow editing on (probably a Map<String, Set<String>> since you want different fields on different recordTypes)

  • Iterate over trigger.new, and check the record against its companion in trigger.old

  • If a field is changed and not in your "allowed" set, add an error

some example code to get you going



Trigger myTrigger on MyObject(before update)
// We can gather the field API names through SObject describe information
List<String> fieldAPINames = new List<String>();

// This is one way to initialize a map
Map<String, Set<String>> editableFieldsByRecordType = new Map<String, Set<String>>
'RecType1' => new Set<String>'field1__c', 'field2__c', 'field3__c'
;

for(Schema.FieldDiscribeResult fdr :Schema.SObject.MyObject.fields.getMap().values())
// The getName() method of the FieldDescribeResult class gives you the API name of the field
fieldAPINames.add(fdr.getName());


for(MyObject newRec :Trigger.new)
MyObject oldRec = Trigger.oldMap.get(newRec.Id);

for(String currentField :fieldAPINames)
if(oldRec.get(currentField) != newRec.get(currentField) && !editableFieldsByRecordType.get(newRec.recordTypeName__c).contains(currentField))
newRec.addError('Field is not editable for this stage');

// After you find the first error, you may be able to move on to the next
// record.
// Comment the next line out if you want to catch _all_ attempted edits
break;






The big caveat here (besides me not testing for a particular stage) is that I assume you have a recordTypeName__c field (a formula field) to pull the name of your recordType into the object you're working on.



Trigger context variables don't contain any "related data" (data on objects other than the one you're working on). If you need to use more than one period/dot/full-stop to access a field, like myRec.RecordType.Name, that information is not available in trigger context variables.



To get that information, you either need to explicitly query for it, or have a formula field. There are other ways around that, but those are the easiest and most common approaches.






share|improve this answer
















  • 1




    A fieldset (or more likely a couple fieldsets) can be leveraged so that the list of fields is controlled by something that can be edited in Setup rather than hardcoded.
    – Mark Pond
    Aug 9 at 17:09














up vote
4
down vote













You likely could write a validation rule to satisfy your conditions, but you might not be able to save that validation rule (because it'd likely go beyond the compiled character limit).



Validation rules aren't really meant to do what you're looking to do. Preventing certain fields from being edited is easy. The inverse of that, allowing certain fields to be edited, is hard.



A better declarative solution is to create new record types and page layouts, and mark the fields that you want to prevent from being edited as "read only" on those new layouts. You could use a workflow rule or process builder to automatically move your records into/out-of these special recordTypes.



Other than that, this would be a relatively simple trigger.



  • Gather a list of all the field api names on your object

  • Create a set of field api names you want to allow editing on (probably a Map<String, Set<String>> since you want different fields on different recordTypes)

  • Iterate over trigger.new, and check the record against its companion in trigger.old

  • If a field is changed and not in your "allowed" set, add an error

some example code to get you going



Trigger myTrigger on MyObject(before update)
// We can gather the field API names through SObject describe information
List<String> fieldAPINames = new List<String>();

// This is one way to initialize a map
Map<String, Set<String>> editableFieldsByRecordType = new Map<String, Set<String>>
'RecType1' => new Set<String>'field1__c', 'field2__c', 'field3__c'
;

for(Schema.FieldDiscribeResult fdr :Schema.SObject.MyObject.fields.getMap().values())
// The getName() method of the FieldDescribeResult class gives you the API name of the field
fieldAPINames.add(fdr.getName());


for(MyObject newRec :Trigger.new)
MyObject oldRec = Trigger.oldMap.get(newRec.Id);

for(String currentField :fieldAPINames)
if(oldRec.get(currentField) != newRec.get(currentField) && !editableFieldsByRecordType.get(newRec.recordTypeName__c).contains(currentField))
newRec.addError('Field is not editable for this stage');

// After you find the first error, you may be able to move on to the next
// record.
// Comment the next line out if you want to catch _all_ attempted edits
break;






The big caveat here (besides me not testing for a particular stage) is that I assume you have a recordTypeName__c field (a formula field) to pull the name of your recordType into the object you're working on.



Trigger context variables don't contain any "related data" (data on objects other than the one you're working on). If you need to use more than one period/dot/full-stop to access a field, like myRec.RecordType.Name, that information is not available in trigger context variables.



To get that information, you either need to explicitly query for it, or have a formula field. There are other ways around that, but those are the easiest and most common approaches.






share|improve this answer
















  • 1




    A fieldset (or more likely a couple fieldsets) can be leveraged so that the list of fields is controlled by something that can be edited in Setup rather than hardcoded.
    – Mark Pond
    Aug 9 at 17:09












up vote
4
down vote










up vote
4
down vote









You likely could write a validation rule to satisfy your conditions, but you might not be able to save that validation rule (because it'd likely go beyond the compiled character limit).



Validation rules aren't really meant to do what you're looking to do. Preventing certain fields from being edited is easy. The inverse of that, allowing certain fields to be edited, is hard.



A better declarative solution is to create new record types and page layouts, and mark the fields that you want to prevent from being edited as "read only" on those new layouts. You could use a workflow rule or process builder to automatically move your records into/out-of these special recordTypes.



Other than that, this would be a relatively simple trigger.



  • Gather a list of all the field api names on your object

  • Create a set of field api names you want to allow editing on (probably a Map<String, Set<String>> since you want different fields on different recordTypes)

  • Iterate over trigger.new, and check the record against its companion in trigger.old

  • If a field is changed and not in your "allowed" set, add an error

some example code to get you going



Trigger myTrigger on MyObject(before update)
// We can gather the field API names through SObject describe information
List<String> fieldAPINames = new List<String>();

// This is one way to initialize a map
Map<String, Set<String>> editableFieldsByRecordType = new Map<String, Set<String>>
'RecType1' => new Set<String>'field1__c', 'field2__c', 'field3__c'
;

for(Schema.FieldDiscribeResult fdr :Schema.SObject.MyObject.fields.getMap().values())
// The getName() method of the FieldDescribeResult class gives you the API name of the field
fieldAPINames.add(fdr.getName());


for(MyObject newRec :Trigger.new)
MyObject oldRec = Trigger.oldMap.get(newRec.Id);

for(String currentField :fieldAPINames)
if(oldRec.get(currentField) != newRec.get(currentField) && !editableFieldsByRecordType.get(newRec.recordTypeName__c).contains(currentField))
newRec.addError('Field is not editable for this stage');

// After you find the first error, you may be able to move on to the next
// record.
// Comment the next line out if you want to catch _all_ attempted edits
break;






The big caveat here (besides me not testing for a particular stage) is that I assume you have a recordTypeName__c field (a formula field) to pull the name of your recordType into the object you're working on.



Trigger context variables don't contain any "related data" (data on objects other than the one you're working on). If you need to use more than one period/dot/full-stop to access a field, like myRec.RecordType.Name, that information is not available in trigger context variables.



To get that information, you either need to explicitly query for it, or have a formula field. There are other ways around that, but those are the easiest and most common approaches.






share|improve this answer












You likely could write a validation rule to satisfy your conditions, but you might not be able to save that validation rule (because it'd likely go beyond the compiled character limit).



Validation rules aren't really meant to do what you're looking to do. Preventing certain fields from being edited is easy. The inverse of that, allowing certain fields to be edited, is hard.



A better declarative solution is to create new record types and page layouts, and mark the fields that you want to prevent from being edited as "read only" on those new layouts. You could use a workflow rule or process builder to automatically move your records into/out-of these special recordTypes.



Other than that, this would be a relatively simple trigger.



  • Gather a list of all the field api names on your object

  • Create a set of field api names you want to allow editing on (probably a Map<String, Set<String>> since you want different fields on different recordTypes)

  • Iterate over trigger.new, and check the record against its companion in trigger.old

  • If a field is changed and not in your "allowed" set, add an error

some example code to get you going



Trigger myTrigger on MyObject(before update)
// We can gather the field API names through SObject describe information
List<String> fieldAPINames = new List<String>();

// This is one way to initialize a map
Map<String, Set<String>> editableFieldsByRecordType = new Map<String, Set<String>>
'RecType1' => new Set<String>'field1__c', 'field2__c', 'field3__c'
;

for(Schema.FieldDiscribeResult fdr :Schema.SObject.MyObject.fields.getMap().values())
// The getName() method of the FieldDescribeResult class gives you the API name of the field
fieldAPINames.add(fdr.getName());


for(MyObject newRec :Trigger.new)
MyObject oldRec = Trigger.oldMap.get(newRec.Id);

for(String currentField :fieldAPINames)
if(oldRec.get(currentField) != newRec.get(currentField) && !editableFieldsByRecordType.get(newRec.recordTypeName__c).contains(currentField))
newRec.addError('Field is not editable for this stage');

// After you find the first error, you may be able to move on to the next
// record.
// Comment the next line out if you want to catch _all_ attempted edits
break;






The big caveat here (besides me not testing for a particular stage) is that I assume you have a recordTypeName__c field (a formula field) to pull the name of your recordType into the object you're working on.



Trigger context variables don't contain any "related data" (data on objects other than the one you're working on). If you need to use more than one period/dot/full-stop to access a field, like myRec.RecordType.Name, that information is not available in trigger context variables.



To get that information, you either need to explicitly query for it, or have a formula field. There are other ways around that, but those are the easiest and most common approaches.







share|improve this answer












share|improve this answer



share|improve this answer










answered Aug 9 at 16:43









Derek F

17.1k21344




17.1k21344







  • 1




    A fieldset (or more likely a couple fieldsets) can be leveraged so that the list of fields is controlled by something that can be edited in Setup rather than hardcoded.
    – Mark Pond
    Aug 9 at 17:09












  • 1




    A fieldset (or more likely a couple fieldsets) can be leveraged so that the list of fields is controlled by something that can be edited in Setup rather than hardcoded.
    – Mark Pond
    Aug 9 at 17:09







1




1




A fieldset (or more likely a couple fieldsets) can be leveraged so that the list of fields is controlled by something that can be edited in Setup rather than hardcoded.
– Mark Pond
Aug 9 at 17:09




A fieldset (or more likely a couple fieldsets) can be leveraged so that the list of fields is controlled by something that can be edited in Setup rather than hardcoded.
– Mark Pond
Aug 9 at 17:09












 

draft saved


draft discarded


























 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsalesforce.stackexchange.com%2fquestions%2f228362%2fvalidation-rule-to-allow-modification-of-limited-fields-only%23new-answer', 'question_page');

);

Post as a guest













































































這個網誌中的熱門文章

Is there any way to eliminate the singular point to solve this integral by hand or by approximations?

Why am i infinitely getting the same tweet with the Twitter Search API?

Carbon dioxide