Join the #BuildWithBuildAgent Challenge! Get recognized, earn exclusive swag, and inspire the ServiceNow Community with what you can build using Build Agent.  Join the Challenge.

Issue in UI Macro using angular js

Sindhuja10
Kilo Expert

I created a UI Macro using angular js where the functionality is working on the form. After submitting the RITM getting error - Uncaught Error: [ng:btstrpd]

9 REPLIES 9

Hi sindhujab,

Acutally in the html markup first line, using "ng-app=" is bootstrapping the module. However, ServiceNow uses the angular.bootstrap(element); method to initialize AngularJS. Per the AngularJS documentation it isn't recommended to use both in the same app.

I believe if you change ng-app="MyApp" to the id attribute like this: id="MyApp". Also in order for the controller to work when viewed in the RITM this attribute needs to be added to the same top element sn-ng-formatter="MyApp". 

ie: <div id="MyApp" sn-ng-formatter="MyApp" ng-controller="MyController">

 Then add the following line at the end of your script to bootstrap the module:

angular.bootstrap(document.getElementById('MyApp'), ['MyApp']);

If the RITM still gives an error for the controller you may have to require the angularjs library with something like this at the top of the macro:

<g:requires name="scripts/angular_1.5.11/angular.min.js" includes="true"/>

Here are some reference posts:

https://community.servicenow.com/community?id=community_question&sys_id=24c6cf65db1cdbc01dcaf3231f96195c&view_source=searchResult

https://community.servicenow.com/community?id=community_question&sys_id=325247eddb98dbc01dcaf3231f9619d1

Hi Chris,

I modified the above code as you said like,

angular.element(document).ready(function() {
angular.bootstrap(document, ['MyApp']);
});
angular.module('MyApp', [])
.controller('MyController', function ($scope, $window){

});

Previously i got Uncaught Error: [ng:areq] and Uncaught Error: [ng:btstrpd] errors. Still I am getting Uncaught Error: [ng:btstrpd] error. Is there anything I am missing?

Thanks in advance

That's not quite what I suggested. I didn't wrap mine in the document.ready. I suggested to add angular.bootstrap(document.getElementById('MyApp'), ['MyApp']) at the end of your already existing script.

 

<!-- possibly may need this next line 
<g:requires name="scripts/angular_1.5.11/angular.min.js" includes="true"/>
-->

<div id="MyApp" sn-ng-formatter="MyApp" ng-controller="MyController">
    <div class="table-responsive">
       <table cellpadding="0" cellspacing="0">
        <tr>
         <th>Owner</th>
         <th>Group</th>
        </tr>
        <tbody ng-repeat="m in Storages">
          <tr>
           <td><input class="form-control" value="{{m.owner}}"/></td>
           <td><input class="form-control" value="{{m.group}}"/></td>
           <td><input type="button" ng-click="Remove($index)" value="Remove" /></td>
          </tr>
        </tbody>
        <tfoot>
          <tr>
           <td>
             <input class="form-control" 
                    type="text" 
                    id="owner" 
                    ng-model="owner" 
                    maxlength="20"/>
           </td>
           <td>
             <input class="form-control" 
                    type="text" 
                    id="group" 
                    ng-model="group" 
                    maxlength="50" />
           </td>
           <td>
             <input type="button" id="Add" ng-click="Add()" value="Add" />
           </td>
          </tr>
        </tfoot>
       </table>
    </div>
 </div>

<script>
angular.module('MyApp', [])
  .controller('MyController', function ($scope, $window) {
     $scope.Storages = [];
     $scope.Add = function () {
        var fieldValues = [$scope.owner, $scope.group];
        var values = {"owner":fieldValues[0],"group":fieldValues[1]};
        $scope.Storages.push(values);
 
       //Clear the TextBoxes.
       $scope.owner = "";
       $scope.group = "";
     };

     $scope.Remove = function (index) {
 
        if ($window.confirm("Do you want to delete this record?")) {
 
        //Remove the item from Array using Index.
        $scope.Storages.splice(index, 1);
 
        }
     };
 });
angular.bootstrap(document.getElementById('MyApp'), ['MyApp']);
</script>

Omkar Mone
Mega Sage

Hi 

UI Macros and UI pages are based on Jelly... Service Portal is a Jelly free environment and as such Ui Macros and Ui Pages will not render in the Service Portal. This is by design. Jelly is also a server side template, so I'm not even sure how it would work to have this display in a client side single page app such as Service Portal.

 

The alternative Service Portal provides is the ability to render a widget inside the catalog variable. If you look through the variable form, you should notice a widget field.

 

 

Hi,

I am creating both UI Macro and a widget so that it would work in Service Portal