ServicePortal Issue problem 1

sanyalshubh
Tera Contributor

we have two dropdowns in a Service Portal widget —Country and State. When the user selects a country, the State dropdown should automatically populate with the corresponding states for that country.
So the above is not coming up.. how to build this logic on portal. On the table I can build the logic but in portal how to build?

2 ACCEPTED SOLUTIONS

Sandeep Rajput
Tera Patron
Tera Patron

@sanyalshubh On your widget, I am assuming you have two drop downs, representing country and state. In your Widget HTML you can have the HTML like following.

 

<div>
  <label for="country">Country:</label>
  <select id="country" ng-model="data.selectedCountry" ng-change="c.getStates()">
    <option ng-repeat="country in data.countries" value="{{country.value}}">
      {{country.label}}
    </option>
  </select>
</div>

<div>
  <label for="state">State:</label>
  <select id="state" ng-model="data.selectedState" ng-disabled="!data.states.length">
    <option ng-repeat="state in data.states" value="{{state.value}}">
      {{state.label}}
    </option>
  </select>
</div>

In the widget client script, you can implement the event as follows,

(function() {
  angular.module('myApp').controller('myWidgetCtrl', function($scope, spUtil) {

    $scope.c.getStates = function() {
      if (!$scope.data.selectedCountry) return;
      
      $scope.data.states = [];  // Clear existing states

      // Call server to fetch states based on the selected country
      $scope.server.get({
        country: $scope.data.selectedCountry
      }).then(function(response) {
        $scope.data.states = response.states || [];
      });
    };

  });
})();

In the server side script, you can fetch the states based on selected country.

 

(function() {
  data.countries = [
    { label: 'United States', value: 'US' },
    { label: 'Canada', value: 'CA' },
    { label: 'India', value: 'IN' }
  ];

  data.states = [];

  if (input && input.country) {
    var stateRecords = new GlideRecord('u_state_table'); // Replace with your actual state table
    stateRecords.addQuery('country', input.country);
    stateRecords.query();

    var states = [];
    while (stateRecords.next()) {
      states.push({
        label: stateRecords.getValue('name'),
        value: stateRecords.getValue('sys_id')
      });
    }

    data.states = states;
  }
})();

 

View solution in original post

Ravi Gaurav
Giga Sage
Giga Sage

Hi @sanyalshubh 

 

You have to build the logic on the Widget script..

like Server Side Script :-

(function() {
data.countries = [];
data.states = [];

// Fetch all countries (assuming a 'Country' table exists)
var grCountry = new GlideRecord('your_country_table'); // Replace with actual table
grCountry.query();
while (grCountry.next()) {
data.countries.push({
name: grCountry.name.toString(),
code: grCountry.sys_id.toString() // Use sys_id if referencing another table
});
}
})();
The Client side script :-

function($scope, spUtil) {
$scope.selectedCountry = null;
$scope.selectedState = null;

// Load countries from the server script
$scope.countries = $scope.data.countries;
$scope.states = [];

// Function to fetch states dynamically
$scope.getStates = function() {
if (!$scope.selectedCountry) {
$scope.states = [];
return;
}

// Use spUtil to fetch states without using an API
spUtil.get('your_state_table', { country: $scope.selectedCountry.code }).then(function(response) {
$scope.states = response.data.result;
});
};
}

and If any HTML Template :-

<div>
<label for="country">Country:</label>
<select id="country" ng-model="selectedCountry"
ng-options="country as country.name for country in countries track by country.code"
ng-change="getStates()">
<option value="">-- Select Country --</option>
</select>
</div>

<div>
<label for="state">State:</label>
<select id="state" ng-model="selectedState"
ng-options="state as state.name for state in states">
<option value="">-- Select State --</option>
</select>
</div>

Note:-- I have not written the above code its from various sources just few changes I did.. Need to evelaute and check whether it is working or not..
Keep me posted

--------------------------------------------------------------------------------------------------------------------------


If you found my response helpful, I would greatly appreciate it if you could mark it as "Accepted Solution" and "Helpful."
Your support not only benefits the community but also encourages me to continue assisting. Thank you so much!

Thanks and Regards
Ravi Gaurav | ServiceNow MVP 2025,2024 | ServiceNow Practice Lead | Solution Architect
CGI
M.Tech in Data Science & AI

 YouTube: https://www.youtube.com/@learnservicenowwithravi
 LinkedIn: https://www.linkedin.com/in/ravi-gaurav-a67542aa/

View solution in original post

7 REPLIES 7

Sandeep Rajput
Tera Patron
Tera Patron

@sanyalshubh On your widget, I am assuming you have two drop downs, representing country and state. In your Widget HTML you can have the HTML like following.

 

<div>
  <label for="country">Country:</label>
  <select id="country" ng-model="data.selectedCountry" ng-change="c.getStates()">
    <option ng-repeat="country in data.countries" value="{{country.value}}">
      {{country.label}}
    </option>
  </select>
</div>

<div>
  <label for="state">State:</label>
  <select id="state" ng-model="data.selectedState" ng-disabled="!data.states.length">
    <option ng-repeat="state in data.states" value="{{state.value}}">
      {{state.label}}
    </option>
  </select>
</div>

In the widget client script, you can implement the event as follows,

(function() {
  angular.module('myApp').controller('myWidgetCtrl', function($scope, spUtil) {

    $scope.c.getStates = function() {
      if (!$scope.data.selectedCountry) return;
      
      $scope.data.states = [];  // Clear existing states

      // Call server to fetch states based on the selected country
      $scope.server.get({
        country: $scope.data.selectedCountry
      }).then(function(response) {
        $scope.data.states = response.states || [];
      });
    };

  });
})();

In the server side script, you can fetch the states based on selected country.

 

(function() {
  data.countries = [
    { label: 'United States', value: 'US' },
    { label: 'Canada', value: 'CA' },
    { label: 'India', value: 'IN' }
  ];

  data.states = [];

  if (input && input.country) {
    var stateRecords = new GlideRecord('u_state_table'); // Replace with your actual state table
    stateRecords.addQuery('country', input.country);
    stateRecords.query();

    var states = [];
    while (stateRecords.next()) {
      states.push({
        label: stateRecords.getValue('name'),
        value: stateRecords.getValue('sys_id')
      });
    }

    data.states = states;
  }
})();

 

Ravi Gaurav
Giga Sage
Giga Sage

Hi @sanyalshubh 

 

You have to build the logic on the Widget script..

like Server Side Script :-

(function() {
data.countries = [];
data.states = [];

// Fetch all countries (assuming a 'Country' table exists)
var grCountry = new GlideRecord('your_country_table'); // Replace with actual table
grCountry.query();
while (grCountry.next()) {
data.countries.push({
name: grCountry.name.toString(),
code: grCountry.sys_id.toString() // Use sys_id if referencing another table
});
}
})();
The Client side script :-

function($scope, spUtil) {
$scope.selectedCountry = null;
$scope.selectedState = null;

// Load countries from the server script
$scope.countries = $scope.data.countries;
$scope.states = [];

// Function to fetch states dynamically
$scope.getStates = function() {
if (!$scope.selectedCountry) {
$scope.states = [];
return;
}

// Use spUtil to fetch states without using an API
spUtil.get('your_state_table', { country: $scope.selectedCountry.code }).then(function(response) {
$scope.states = response.data.result;
});
};
}

and If any HTML Template :-

<div>
<label for="country">Country:</label>
<select id="country" ng-model="selectedCountry"
ng-options="country as country.name for country in countries track by country.code"
ng-change="getStates()">
<option value="">-- Select Country --</option>
</select>
</div>

<div>
<label for="state">State:</label>
<select id="state" ng-model="selectedState"
ng-options="state as state.name for state in states">
<option value="">-- Select State --</option>
</select>
</div>

Note:-- I have not written the above code its from various sources just few changes I did.. Need to evelaute and check whether it is working or not..
Keep me posted

--------------------------------------------------------------------------------------------------------------------------


If you found my response helpful, I would greatly appreciate it if you could mark it as "Accepted Solution" and "Helpful."
Your support not only benefits the community but also encourages me to continue assisting. Thank you so much!

Thanks and Regards
Ravi Gaurav | ServiceNow MVP 2025,2024 | ServiceNow Practice Lead | Solution Architect
CGI
M.Tech in Data Science & AI

 YouTube: https://www.youtube.com/@learnservicenowwithravi
 LinkedIn: https://www.linkedin.com/in/ravi-gaurav-a67542aa/

sanyalshubh
Tera Contributor

Thanks @Ravi Gaurav and @Sandeep Rajput  thanks for the code.. it really helped and I just tweak little bit and it worked