UI Policy conflict behavior when switching field values without saving the record

themadhankumar
Mega Contributor

Hi Team,

I am facing a doubt related to UI Policy behavior and I would like some clarification.

I have created two UI Policies on the Incident table:

  1. UI Policy 1

    • Condition: Category = Hardware

    • Action: Subcategory = Mandatory

  2. UI Policy 2

    • Condition: Category = Network

    • Action: Subcategory = Visible = false

Scenario I am observing:

  • I create a new Incident record

  • First, I select Category = Hardware
    → Subcategory becomes mandatory (this works as expected)

  • Without saving the record, I change Category = Network
    → Subcategory is still visible (UI Policy 2 does not apply)

  • If I change back to Hardware, Subcategory again becomes mandatory

Now, if I create another new Incident:

  • First, I select Category = Network
    → Subcategory becomes not visible (this works)

  • Then without saving, I change Category = Hardware
    → Subcategory becomes mandatory

  • After that, if I switch back to Network, the Subcategory visibility does not change as per UI Policy

So the UI Policy seems to work correctly only the first time, based on which category is selected first, and then it does not always revert correctly when switching values without saving.

My doubt:

  • Is this expected behavior of UI Policies?

  • Do UI Policies evaluate only once per form load?

  • Is this because the record is not saved?

  • Do I need to use Reverse if false, order, or Client Scripts to handle this?

Please let me know the correct approach to handle this scenario.

Thanks in advance.

2 ACCEPTED SOLUTIONS

Najmuddin Mohd
Mega Sage

Hello @themadhankumar ,

I have seen this type of issue when the action is written on the same field in two different UI Policies.
So, I try to use the action in the same UI Policy and try to build conditions using OR condition. 
However, I believe the requirement here cannot be build within the same UI Policy.

Can you check by using Reverse if false condition. If this does not work, try with Client Scripts.


If the above information helps you, Kindly mark this as Helpful and Accept the solution.
Regards,
Najmuddin

View solution in original post

themadhankumar
Mega Contributor

Test Case

Requirement
When the user changes the Category field on the Incident form:

  • If Category = network
    → Disable Subcategory and make it non-mandatory

  • If Category = hardware
    → Enable Subcategory and make it mandatory

This should happen immediately when the field value changes on the form.


Correct Solution Used

Type: Client Script
Script Type: onChange
Field Name: category

Final Working Script

 
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
    if (isLoading || newValue === '') {
        return;
    }

    g_form.clearMessages();
    g_form.addInfoMessage("Client Script triggered. Value: " + newValue);


    if (newValue == 'network') {
        g_form.setMandatory('subcategory', false);
        g_form.setDisplay('subcategory', false);
    }

    if (newValue == 'hardware') {
        g_form.setDisabled('subcategory', false);
        g_form.setMandatory('subcategory', true);
    }
}
 

Things to Do (Step-by-Step)

  1. Go to System Definition → Client Scripts

  2. Create a new Client Script

  3. Set:

    • Type = onChange

    • Table = Incident

    • Field name = category

    • Active = true

  4. Use field names, not labels

  5. Save the script

  6. Perform a hard refresh (Ctrl + Shift + R)


Mistakes Made By Me(Point by Point)

  1. Used UI Policy when the requirement needed real-time field change behavior
    (UI Policies do not behave like onChange scripts)

  2. Expected alert() to work
    (Blocked in new isolated client scripts)

  3. Used console.log()
    (Caused “Unexpected console statement” warning)

  4. Passed multiple parameters to g_form.addInfoMessage()
    (Method accepts only one string parameter)

  5. Used incident.subcategory instead of subcategory
    (Client scripts accept only field names, not table.field)

  6. Case mismatch in choice values
    (network is not the same as Network)

  7. Cache was not cleared after creating new scripts
    (ServiceNow loads cached client logic)


Debugging Methods Used

  1. g_form.addInfoMessage()
    Used to confirm that the script was executing

  2. Checking the Info Message output
    Confirmed correct newValue was received

  3. Removing UI Policy conflicts
    Ensured client script changes were not overridden

  4. Verifying field names in Dictionary
    Confirmed actual field names and choice values

  5. Hard refresh and cache clear
    Ensured latest client script was loaded


Key Takeaways

  • Use Client Scripts (onChange) for real-time field change behavior

  • Use UI Policies for simple UI rules without scripting

  • Always use field names, not labels or table.field

  • New client scripts run in isolated mode

  • g_form.addInfoMessage() is the safest debugging method

  • Choice values are case-sensitive

    themadhankumar_2-1768936650650.pngthemadhankumar_3-1768936654129.png

    when Category = Hardware 

    themadhankumar_4-1768936708450.png

    when Category  = Network

    themadhankumar_5-1768936730473.png

     

View solution in original post

8 REPLIES 8

Prathmeshda
Mega Guru

Hello @themadhankumar 

The behavior you are observing is expected based on how UI Policies work in ServiceNow. Here is the explanation:

UI Policies do not always re-evaluate automatically on every field change. They trigger when the form loads and when the condition of the UI Policy is met, but if you change the field value multiple times without saving, some actions (like visibility) may not revert as expected.
Reverse if false is important. If you want a field to revert to its original state when the condition is no longer true, you must check the “Reverse if false” option on the UI Policy. Without it, the field may retain its previous state.
Order of UI Policies matters. If multiple UI Policies affect the same field, the one with higher order executes first, but overlapping actions can cause inconsistent behavior when switching values.
Client Scripts can be used if needed. For complex scenarios where fields need to dynamically change on multiple value switches without saving, a Client Script (onChange) may give more reliable control.
Saving the record is not required for UI Policies to work, but some behaviors like visibility and mandatory state may not toggle correctly unless Reverse if false is enabled and UI Policy order is considered.

Recommended approach:

  • Enable Reverse if false on both UI Policies.

  • Set the order of the UI Policies to ensure predictable execution.

  • If needed, use an onChange Client Script for the Category field to handle dynamic visibility or mandatory rules more reliably.

Reference: ServiceNow Docs – UI Policies


If this response proves useful, please mark it as Accept as Solution and Helpful. Doing so benefits both the community and me. 👍🙂

themadhankumar_0-1768932702819.png

both of the UI Policy are true with the Reverse is false, but still it is not working with my expectation or my test case.

themadhankumar
Mega Contributor

Test Case

Requirement
When the user changes the Category field on the Incident form:

  • If Category = network
    → Disable Subcategory and make it non-mandatory

  • If Category = hardware
    → Enable Subcategory and make it mandatory

This should happen immediately when the field value changes on the form.


Correct Solution Used

Type: Client Script
Script Type: onChange
Field Name: category

Final Working Script

 
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
    if (isLoading || newValue === '') {
        return;
    }

    g_form.clearMessages();
    g_form.addInfoMessage("Client Script triggered. Value: " + newValue);


    if (newValue == 'network') {
        g_form.setMandatory('subcategory', false);
        g_form.setDisplay('subcategory', false);
    }

    if (newValue == 'hardware') {
        g_form.setDisabled('subcategory', false);
        g_form.setMandatory('subcategory', true);
    }
}
 

Things to Do (Step-by-Step)

  1. Go to System Definition → Client Scripts

  2. Create a new Client Script

  3. Set:

    • Type = onChange

    • Table = Incident

    • Field name = category

    • Active = true

  4. Use field names, not labels

  5. Save the script

  6. Perform a hard refresh (Ctrl + Shift + R)


Mistakes Made By Me(Point by Point)

  1. Used UI Policy when the requirement needed real-time field change behavior
    (UI Policies do not behave like onChange scripts)

  2. Expected alert() to work
    (Blocked in new isolated client scripts)

  3. Used console.log()
    (Caused “Unexpected console statement” warning)

  4. Passed multiple parameters to g_form.addInfoMessage()
    (Method accepts only one string parameter)

  5. Used incident.subcategory instead of subcategory
    (Client scripts accept only field names, not table.field)

  6. Case mismatch in choice values
    (network is not the same as Network)

  7. Cache was not cleared after creating new scripts
    (ServiceNow loads cached client logic)


Debugging Methods Used

  1. g_form.addInfoMessage()
    Used to confirm that the script was executing

  2. Checking the Info Message output
    Confirmed correct newValue was received

  3. Removing UI Policy conflicts
    Ensured client script changes were not overridden

  4. Verifying field names in Dictionary
    Confirmed actual field names and choice values

  5. Hard refresh and cache clear
    Ensured latest client script was loaded


Key Takeaways

  • Use Client Scripts (onChange) for real-time field change behavior

  • Use UI Policies for simple UI rules without scripting

  • Always use field names, not labels or table.field

  • New client scripts run in isolated mode

  • g_form.addInfoMessage() is the safest debugging method

  • Choice values are case-sensitive

    themadhankumar_2-1768936650650.pngthemadhankumar_3-1768936654129.png

    when Category = Hardware 

    themadhankumar_4-1768936708450.png

    when Category  = Network

    themadhankumar_5-1768936730473.png

     

themadhankumar
Mega Contributor

 

Test Case

Requirement
When the user changes the Category field on the Incident form:

  • If Category = network
    → Disable Subcategory and make it non-mandatory

  • If Category = hardware
    → Enable Subcategory and make it mandatory

This should happen immediately when the field value changes on the form.


Correct Solution Used

Type: Client Script
Script Type: onChange
Field Name: category

Final Working Script

function onChange(control, oldValue, newValue, isLoading, isTemplate) {
    if (isLoading || newValue === '') {
        return;
    }

    g_form.clearMessages();
    g_form.addInfoMessage("Client Script triggered. Value: " + newValue);


    if (newValue == 'network') {
        g_form.setMandatory('subcategory', false);
        g_form.setDisplay('subcategory', false);
    }

    if (newValue == 'hardware') {
        g_form.setDisabled('subcategory', false);
        g_form.setMandatory('subcategory', true);
    }
}

Things to Do (Step-by-Step)

  1. Go to System Definition → Client Scripts

  2. Create a new Client Script

  3. Set:

    • Type = onChange

    • Table = Incident

    • Field name = category

    • Active = true

  4. Use field names, not labels

  5. Save the script

  6. Perform a hard refresh (Ctrl + Shift + R)


Mistakes Made I Made (Point by Point)

  1. Used UI Policy when the requirement needed real-time field change behavior
    (UI Policies do not behave like onChange scripts)

  2. Expected alert() to work
    (Blocked in new isolated client scripts)

  3. Used console.log()
    (Caused “Unexpected console statement” warning)

  4. Passed multiple parameters to g_form.addInfoMessage()
    (Method accepts only one string parameter)

  5. Used incident.subcategory instead of subcategory
    (Client scripts accept only field names, not table.field)

  6. Case mismatch in choice values
    (network is not the same as Network)

  7. Cache was not cleared after creating new scripts
    (ServiceNow loads cached client logic)


Debugging Methods Used

  1. g_form.addInfoMessage()
    Used to confirm that the script was executing

  2. Checking the Info Message output
    Confirmed correct newValue was received

  3. Removing UI Policy conflicts
    Ensured client script changes were not overridden

  4. Verifying field names in Dictionary
    Confirmed actual field names and choice values

  5. Hard refresh and cache clear
    Ensured latest client script was loaded


Key Takeaways

  • Use Client Scripts (onChange) for real-time field change behavior

  • Use UI Policies for simple UI rules without scripting

  • Always use field names, not labels or table.field

  • New client scripts run in isolated mode

  • g_form.addInfoMessage() is the safest debugging method

  • Choice values are case-sensitive